提问者:小点点

Jackson将具有多态元素的列表序列化为XML


我有一个带有< code >列表的< code>Zoo类型

例如:

abstract class Animal {}

@JacksonXmlRootElement(localName = "Dog")
class Dog extends Animal {}

@JacksonXmlRootElement(localName = "Cat")
class Cat extends Animal {}

@JacksonXmlRootElement(localName = "Zoo")
public class Zoo {

  @JacksonXmlProperty
  @JacksonXmlElementWrapper(useWrapping = false)
  List<Animal> animals = new ArrayList<>();
}

序列化 Zoo 实例。

public static void main(String[] args) throws JsonProcessingException {
  Zoo zoo = new Zoo();
  zoo.animals.add(new Dog());
  zoo.animals.add(new Cat());
  zoo.animals.add(new Dog());
  String xml = new XmlMapper().writerWithDefaultPrettyPrinter()
      .writeValueAsString(zoo);
  System.out.println(xml);
}

我希望得到:

<Zoo>
  <Dog/>
  <Cat/>
  <Dog/>
</Zoo>

实际输出:

<Zoo>
  <animals/>
  <animals/>
  <animals/>
</Zoo>

共1个答案

匿名用户

使用自定义序列化器可以获得预期的结果,但使用JsonTypeInfo会失去所有可用的优势,并且还必须编写自定义反序列化器。无论如何,您可以定义三个简单的类,如下所示:

public abstract class Animal {}
public class Dog extends Animal {}

@JsonSerialize(using = ZooSerializer.class)
public class Zoo {
  List<Animal> animals = new ArrayList<>();
}

然后你必须编写你的自定义ZooSerializer序列化器来构建你的自定义xml:

public class ZooSerializer extends StdSerializer<Zoo> {

    public ZooSerializer(Class<Zoo> t) {
        super(t);
    }
    
    public ZooSerializer() {
        this(null);
    }

    @Override
    public void serialize(Zoo zoo, JsonGenerator jg, SerializerProvider sp) throws IOException {
        jg.writeStartObject();
        for (Animal animal: zoo.animals) {
            jg.writeNullField(animal.getClass().getSimpleName());
        }
        jg.writeEndObject();
    }
}

这将产生预期的结果,但代价是失去所有优点,因为自动序列化和反序列化可以通过对两个类使用< code>JsonTypeInfo和< code>JsonSubTypes批注来获得:

Zoo zoo = new Zoo();
zoo.animals.add(new Dog());
zoo.animals.add(new Dog());
/* the str content obtained by the serialization of zoo
Zoo>
  <Dog/>
  <Dog/>
</Zoo>
*/
String str = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(zoo);