当前位置:  开发笔记 > 编程语言 > 正文

为什么杰克逊多态序列化在列表中不起作用?

如何解决《为什么杰克逊多态序列化在列表中不起作用?》经验,为你挑选了2个好方法。

杰克逊正在做一些真正奇怪的事情,我找不到任何解释.我正在进行多态序列化,当一个对象独立时它可以很好地工作.但是,如果将相同的对象放入列表并将列表序列化,则会删除类型信息.

它丢失类型信息的事实将导致人们怀疑类型擦除.但是在序列化列表内容期间会发生这种情况; 杰克逊所要做的就是检查它正在序列化的当前对象以确定其类型.

我用Jackson 2.5.1创建了一个例子:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.List;

public class Test {

  @JsonIgnoreProperties(ignoreUnknown = true)
  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
  @JsonSubTypes({
    @Type(value = Dog.class, name = "dog"),
    @Type(value = Cat.class, name = "cat")})
  public interface Animal {}

  @JsonTypeName("dog")
  public static class Dog implements Animal {
    private String name;

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }
  }

  @JsonTypeName("cat")
  public static class Cat implements Animal {
    private String name;

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }
  }

  public static void main(String[] args) throws JsonProcessingException {
    List list = new ArrayList<>();
    list.add(new Cat());
    System.out.println(new ObjectMapper().writeValueAsString(list));
    System.out.println(new ObjectMapper().writeValueAsString(list.get(0)));
  }
}

这是输出:

[{"name":null}]
{"@type":"cat","name":null}

如您所见,当对象在列表中时,Jackson不会添加类型信息.有谁知道为什么会这样?



1> Sotirios Del..:

这里和这里讨论了发生这种情况的各种原因.我不一定与理由同意,但杰克逊,因为类型擦除,并不蝙蝠知道元素的类型List(或CollectionMap)含有.它选择使用不能解释注释的简单序列化程序.

您可以在这些链接中建议两个选项:

首先,您可以创建一个实现的类,List适当地实例化它并序列化实例.

class CatList implements List {...}

泛型类型参数Cat不会丢失.杰克逊可以使用它并使用它.

其次,您可以实例化并使用ObjectWriter类型List.例如

System.out.println(new ObjectMapper().writerFor(new TypeReference>() {}).writeValueAsString(list));

将打印

[{"@type":"cat","name":"heyo"}]


你也可以像`new ObjectMapper().writerFor(mapper.getTypeFactory().constructCollectionType(List.class,Animal.class)).writeValueAsString(list)`
那真的很奇怪,我无法想象他们为什么会做出这样的选择。无论列表的类型如何,您都认为其中的对象将始终以相同的方式序列化。

2> monitorjbl..:

Sotirios Delimanolis给出的答案是正确的.但是,我认为将此解决方法作为单独的答案发布是很好的.如果你所处的环境中你不能为你需要返回的每种类型的事物更改ObjectMapper(比如Jersey/SpringMVC webapp),那么还有另一种选择.

您可以在包含该类型的类中包含一个私有final字段.该字段对于类外的任何内容都不可见,但如果您使用@JsonProperty("@type")(或"@class"或任何类型字段命名)对其进行注释,则无论对象位于何处,Jackson都会对其进行序列化.

@JsonTypeName("dog")
public static class Dog implements Animal {
  @JsonProperty("@type")
  private final String type = "dog";
  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}


它适用于我,但当我序列化一个元素时,@ type字段是重复的.
推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有