如何使用 Java 和 Jackson 库对 Json 字符串进行多态反序列化?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6542833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 07:36:43  来源:igfitidea点击:

How can I polymorphic deserialization Json String using Java and Hymanson Library?

javajsonserializationHymansonbase-class

提问by mohamede1945

I've some classes A, B, C they all inherit from class BaseClass.

我有一些类 A、B、C,它们都继承自 BaseClass 类。

I've a String json that contains the json representation of the A, B, C or BaseClass.

我有一个字符串 json,其中包含 A、B、C 或 BaseClass 的 json 表示。

I want to have some way to deserialize this String to the BaseClass (polymorphic deserialization). Something like this

我想有一些方法将此字符串反序列化为 BaseClass(多态反序列化)。像这样的东西

BaseClass base = ObjectMapper.readValue(jsonString, BaseClass.class);

jsonStringcould be Json String representation of any of A, B, C, or BaseClass.

jsonString可以是 A、B、C 或 BaseClass 中任何一个的 Json 字符串表示。

采纳答案by Programmer Bruce

It's not clear what problem the original poster is having. I'm guessing that it's one of two things:

目前尚不清楚原始海报有什么问题。我猜这是两件事之一:

  1. Deserialization problems with unbound JSON elements, because the JSON contains elements for which there is nothing in the Java to bind to; or

  2. Want to implement polymorphic deserialization.

  1. 未绑定 JSON 元素的反序列化问题,因为 JSON 包含 Java 中没有任何内容可绑定的元素;或者

  2. 想实现多态反序列化。

Here's a solution to the first problem.

这是第一个问题的解决方案。

import static org.codehaus.Hymanson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES;

import org.codehaus.Hymanson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    BaseClass base = new BaseClass();
    A a = new A();
    B b = new B();
    C c = new C();

    ObjectMapper mapper = new ObjectMapper();

    String baseJson = mapper.writeValueAsString(base);
    System.out.println(baseJson); // {"baseName":"base name"}
    String aJson = mapper.writeValueAsString(a);
    System.out.println(aJson); // {"baseName":"base name","aName":"a name"}
    String bJson = mapper.writeValueAsString(b);
    System.out.println(bJson); // {"baseName":"base name","bName":"b name"}
    String cJson = mapper.writeValueAsString(c);
    System.out.println(cJson); // {"baseName":"base name","cName":"c name"}

    BaseClass baseCopy = mapper.readValue(baseJson, BaseClass.class);
    System.out.println(baseCopy); // baseName: base name

    // BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
    // throws UnrecognizedPropertyException: 
    // Unrecognized field "aName", not marked as ignorable
    // because the JSON contains elements for which no Java field
    // to bind to was provided.

    // Need to let Hymanson know that not all JSON elements must be bound.
    // To resolve this, the class can be annotated with 
    // @JsonIgnoreProperties(ignoreUnknown=true) or the ObjectMapper can be
    // directly configured to not FAIL_ON_UNKNOWN_PROPERTIES
    mapper = new ObjectMapper();
    mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

    BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
    System.out.println(aCopy); // baseName: base name
    BaseClass bCopy = mapper.readValue(bJson, BaseClass.class);
    System.out.println(bCopy); // baseName: base name
    BaseClass cCopy = mapper.readValue(cJson, BaseClass.class);
    System.out.println(cCopy); // baseName: base name
  }
}

class BaseClass
{
  public String baseName = "base name";
  @Override public String toString() {return "baseName: " + baseName;}
}

class A extends BaseClass
{
  public String aName = "a name";
  @Override public String toString() {return super.toString() + ", aName: " + aName;}
}

class B extends BaseClass
{
  public String bName = "b name";
  @Override public String toString() {return super.toString() + ", bName: " + bName;}
}

class C extends BaseClass
{
  public String cName = "c name";
  @Override public String toString() {return super.toString() + ", cName: " + cName;}
}

Here's a solution to the second problem.

这是第二个问题的解决方案。

import org.codehaus.Hymanson.annotate.JsonSubTypes;
import org.codehaus.Hymanson.annotate.JsonSubTypes.Type;
import org.codehaus.Hymanson.annotate.JsonTypeInfo;
import org.codehaus.Hymanson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    BaseClass base = new BaseClass();
    A a = new A();
    B b = new B();
    C c = new C();

    ObjectMapper mapper = new ObjectMapper();

    String baseJson = mapper.writeValueAsString(base);
    System.out.println(baseJson); // {"type":"BaseClass","baseName":"base name"}
    String aJson = mapper.writeValueAsString(a);
    System.out.println(aJson); // {"type":"a","baseName":"base name","aName":"a name"}
    String bJson = mapper.writeValueAsString(b);
    System.out.println(bJson); // {"type":"b","baseName":"base name","bName":"b name"}
    String cJson = mapper.writeValueAsString(c);
    System.out.println(cJson); // {"type":"c","baseName":"base name","cName":"c name"}

    BaseClass baseCopy = mapper.readValue(baseJson, BaseClass.class);
    System.out.println(baseCopy); // baseName: base name
    BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
    System.out.println(aCopy); // baseName: base name, aName: a name
    BaseClass bCopy = mapper.readValue(bJson, BaseClass.class);
    System.out.println(bCopy); // baseName: base name, bName: b name
    BaseClass cCopy = mapper.readValue(cJson, BaseClass.class);
    System.out.println(cCopy); // baseName: base name, cName: c name
  }
}

@JsonTypeInfo(  
    use = JsonTypeInfo.Id.NAME,  
    include = JsonTypeInfo.As.PROPERTY,  
    property = "type")  
@JsonSubTypes({  
    @Type(value = A.class, name = "a"),  
    @Type(value = B.class, name = "b"),  
    @Type(value = C.class, name = "c") }) 
class BaseClass
{
  public String baseName = "base name";
  @Override public String toString() {return "baseName: " + baseName;}
}

class A extends BaseClass
{
  public String aName = "a name";
  @Override public String toString() {return super.toString() + ", aName: " + aName;}
}

class B extends BaseClass
{
  public String bName = "b name";
  @Override public String toString() {return super.toString() + ", bName: " + bName;}
}

class C extends BaseClass
{
  public String cName = "c name";
  @Override public String toString() {return super.toString() + ", cName: " + cName;}
}

If instead, the goal is to deserialize to a subclass type without a JSON element specifically dedicated to indicate what the subclass type is, then that is also possible, so long as something in the JSON can be used to decide what the subclass type should be. I posted an example of this approach at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-Hymanson-into.html.

如果相反,目标是反序列化为子类类型,而没有专门用于指示子类类型的 JSON 元素,那么这也是可能的,只要 JSON 中的某些内容可用于决定子类类型应该是什么. 我在http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-Hymanson-into.html 上发布了一个这种方法的例子。

回答by theleftfielder

Have you looked at Google's Gson library? I think it does what you're looking for.

你看过谷歌的 Gson 库吗?我认为它可以满足您的需求。

http://code.google.com/p/google-gson/

http://code.google.com/p/google-gson/