简体   繁体   English

使用Jackson ObjectMapper将子类名称序列化为JSON,而不是超类

[英]Using Jackson ObjectMapper to serialize the subclass name into JSON, not the superclass

In the following Jackson/Java code that serializes objects into JSON, I am getting this: 在下面将对象序列化为JSON的Jackson / Java代码中,我得到了这个:

{"animal":{"x":"x"}}

However, what I actually want to get is this: 但是,我真正想要得到的是:

{"dog":{"x":"x"}}

Is there something I can do to AnimalContainer so that I get the runtime type ("dog", "cat") of the object, instead of "animal")? 我可以对AnimalContainer做些什么,以便获得对象的运行时类型(“dog”,“cat”),而不是“animal”)? ( Edit: I am aware that the map name comes from the getter- and setter- method names.) The only way I can think of to do it is within AnimalContainer to have an attribute of each type of Animal, have setters and getters for all of them, and enforce that only one is valued at a time. 编辑:我知道地图名称来自getter和setter方法名称。)我能想到的唯一方法是在AnimalContainer中拥有每种类型的Animal的属性,有setter和getter for所有这些,并强制一次只评估一个。 But this defeats the purpose of having the Animal superclass and just seems wrong. 但这违背了拥有动物超类的目的而且似乎错了。 And in my real code I actually have a dozen subclasses, not just "dog" and "cat". 在我的真实代码中,我实际上有十几个子类,而不仅仅是“狗”和“猫”。 Is there a better way to do this (perhaps using annotations somehow)? 有没有更好的方法来做到这一点(也许以某种方式使用注释)? I need a solution for deserializing, as well. 我也需要一个反序列化的解决方案。

public class Test
{
   public static void main(String[] args) throws Exception
   {
      AnimalContainer animalContainer = new AnimalContainer();
      animalContainer.setAnimal(new Dog());

      StringWriter sw = new StringWriter();   // serialize
      ObjectMapper mapper = new ObjectMapper(); 
      MappingJsonFactory jsonFactory = new MappingJsonFactory();
      JsonGenerator jsonGenerator = jsonFactory.createJsonGenerator(sw);
      mapper.writeValue(jsonGenerator, animalContainer);
      sw.close();
      System.out.println(sw.getBuffer().toString());
   }
   public static class AnimalContainer
   {
      private Animal animal;
      public Animal getAnimal() {return animal;}
      public void setAnimal(Animal animal) {this.animal = animal;}
   }
   public abstract static class Animal 
   {
      String x = "x";
      public String getX() {return x;}
   }
   public static class Dog extends Animal {}
   public static class Cat extends Animal {} 
}

As per this announement , Jackson 1.5 implements full polymorphic type handling, and trunk now has that code integrated. 根据这个公告 ,Jackson 1.5实现了完整的多态类型处理,而trunk现在已经集成了该代码。

There are two simple ways to make this work: 有两种简单的方法可以完成这项工作:

  • Add @JsonTypeInfo annotation in supertype (Animal here), OR 在超类型(动物在这里)中添加@JsonTypeInfo注释,或者
  • Configure object mapper by calling ObjectMapper.enableDefaultTyping() (but if so, Animal needs to be abstract type) 通过调用ObjectMapper.enableDefaultTyping()来配置对象映射器(但如果是这样,Animal需要是抽象类型)

This is probably not the answer you are looking for, but there are plans to implement proper "polymorphic deserialization" (and necessary support on serialization for it), for Jackson version 1.4 or so (ie not the next one, 1.3, but one after that). 这可能不是您正在寻找的答案,但有计划实施适当的“多态反序列化”(以及对其进行序列化的必要支持),对于杰克逊版本1.4左右(即不是下一个,1.3,但是一个之后)那)。

For current version, you have to implement custom serializers/deserializers: I would probably just define factory method for deserialization, and type getter for serializer (define 'getAnimalType' or whatever in abstract base class as abstract, override in sub-classes -- or even just implement in base class, output class name of instance class?). 对于当前版本,您必须实现自定义序列化器/反序列化器:我可能只是为反序列化定义工厂方法,并为序列化器键入getter(将'getAnimalType'或抽象基类中的任何内容定义为抽象,在子类中重写 - 或者甚至只是在基类中实现,实例类的输出类名?)。

Anyway, just in case it matters, here are underlying problems wrt implementing handling of sub-classes with JSON, and without schema language (since json doesn't really have widely used one): 无论如何,以防万一重要,这里是使用JSON实现子类处理的基本问题,并且没有模式语言(因为json实际上没有广泛使用过):

  • how to separate data (bean property values) from metadata (type information only needed to construct proper subclasses) -- must be kept separate, but JSON as format has no way to define (could use naming convention) 如何将数据(bean属性值)与元数据(仅需要构造正确的子类所需的类型信息)分开 - 必须保持独立,但JSON作为格式无法定义(可以使用命名约定)
  • how to add proper annotations to generate and use such metadata; 如何添加适当的注释来生成和使用这些元数据; and without depending on language specific features (shouldn't have to tie to java class names for example) 并且不依赖于语言特定的功能(例如,不应该绑定到java类名)

These are solvable problems, but not trivially easy to solve. 这些都是可以解决的问题,但并不容易解决。 :-) :-)

This is the only way I can think of to do it, and it is ugly. 这是我能想到的唯一方法,它很难看。 Is there a better way? 有没有更好的办法?

   @JsonWriteNullProperties(false)
   public static class AnimalContainer
   {
      private Animal animal;

      public Animal getCat()
      {
         return animal instanceof Cat ? animal : null;
      }
      public void setCat(Cat cat)
      {
         this.animal = cat;
      }
      public Animal getDog()
      {
         return animal instanceof Dog ? animal : null;
      }
      public void setDog(Dog dog)
      {
         this.animal = dog;
      }
      public Animal getFish()
      {
         return animal instanceof Fish ? animal : null;
      }
      public void setFish(Fish fish)
      {
         this.animal = fish;
      }
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM