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

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

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

我希望有一些方法可以将此字符串反序列化为 BaseClass(多态反序列化)。像这样的

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

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

最佳答案

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

  1. 未绑定(bind)的 JSON 元素的反序列化问题,因为 JSON 包含在 Java 中没有可绑定(bind)的元素;或

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

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

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

import org.codehaus.jackson.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 Jackson 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;}
}

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

import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonSubTypes.Type;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.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;}
}

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

https://stackoverflow.com/questions/6542833/

相关文章:

java - 对 kotlin 数据类使用 Jackson @JsonProperty 注释

json - 将参数传递给 jq 过滤器

java - 将 Gson 与接口(interface)类型一起使用

java - 如何使用 Jackson 定义可选的 json 字段

ruby-on-rails - rails : Restrict API requests to J

java - 为什么 Json 测试程序不起作用?

Java - 嵌套在嵌套中的 Gson 解析

javascript - 定义 "cyclic data structures"

json - 处理 HTTP 请求正文中的可选 JSON 字段

c# - ASP.NET web api 无法获取 application/x-www-form-u