【问题标题】:How to deserialize generic classes with Jackson?如何用 Jackson 反序列化泛型类?
【发布时间】:2014-04-05 05:58:06
【问题描述】:

我有一些这样的课程:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSubTypes(
              {
                  @JsonSubTypes.Type(value = LionCage.class, name = "LION"),
                  @JsonSubTypes.Type(value = TigerCage.class, name = "TIGER"),
              }
             )
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
public abstract class Cage<ANIMAL> {

  private AnimalType type;
  private ANIMAL animal;

}

public enum AnimalType {

    LION, TIGER

}

public LionCage extends Cage<Lion>{

    public LionCage(){
        super(AnimalType.LION);
    }
}

public Lion {

 private int maneLength;

}

public class Zoo {

   private List<Cage<?>> cages = new LinkedList<Cage<?>>();

}

现在,如果我尝试执行以下操作:

String json = "{cages: [{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}]}";

ObjectMapper om = new ObjectMapper();

Cage cage = om.readValue(json, Zoo.class);

cages 中的第一个值应该是LionCage 类型,它是。

问题是cages.get(0).getAnimal() 返回一个LinkedHashMap我怎样才能让它返回正确的Animal 子类?

我正在使用 Jackson 1。

谢谢!

【问题讨论】:

  • 你能把你的getter和setter也放进去吗? The problem is that cage.getAnimal() returns a LinkedHashMap 考虑到 animalAnimal,这似乎很奇怪。
  • @SotiriosDelimanolis 是public Animal getAnimal()Animal 不是一个类。它是一个泛型“类型”,很像Map&lt;K, V&gt; 中的KV
  • 你说得对,错过了Animal作为类型变量。

标签: java json generics jackson json-deserialization


【解决方案1】:

对于您的List 问题,这是您想要使用原始类型的一次。将Cage 类型参数声明为原始参数,而不是使用通配符进行参数化。

public class Zoo {

    private List<Cage> cages = new LinkedList<Cage>();
    // ... getters and setters similarly
}

使用通配符,您是在告诉 Jackson 这无关紧要,因此它使用默认值 LinkedHashMap。如果您删除通配符并使用原始类型,则需要在其他地方寻找提示。在这种情况下,它将查看它使用的实际 Cage 实现。


您的 JSON 应该如下所示

String json = "{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}";

Jackson 将能够确定 animalLion

通过type它会知道它是一个LionCage并且通过类定义

public LionCage extends Cage<Lion>{

它将知道对类型变量Animal 的任何引用实际上应该是Lion

我在杰克逊 2.

但它也适用于 Jackson 1。代码如下

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.ObjectMapper;

public class Example {

    public static void main(String[] args) throws Exception {
        String json = "{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}";

        ObjectMapper om = new ObjectMapper();

        Cage cage = om.readValue(json, Cage.class);
        System.out.println(cage.getClass());
        System.out.println(cage.getAnimal());

        System.out.println(((Lion) cage.getAnimal()).getManeLength());
    }
}

class Lion {

    private int maneLength;

    public int getManeLength() {
        return maneLength;
    }

    public void setManeLength(int maneLength) {
        this.maneLength = maneLength;
    }
}

class LionCage extends Cage<Lion> {

    public LionCage() {
        super(AnimalType.LION);
    }
}

class Tiger {
}

class TigerCage extends Cage<Tiger> {

    public TigerCage() {
        super(AnimalType.TIGER);
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSubTypes({ @JsonSubTypes.Type(value = LionCage.class, name = "LION"),
        @JsonSubTypes.Type(value = TigerCage.class, name = "TIGER"), })
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class Cage<Animal> {

    public Cage(AnimalType type) {
        this.setType(type);
    }

    public AnimalType getType() {
        return type;
    }

    public void setType(AnimalType type) {
        this.type = type;
    }

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    private AnimalType type;
    private Animal animal;
}

enum AnimalType {
    LION, TIGER;
}

打印

class com.spring.LionCage
com.spring.Lion@15d16efc
10

【讨论】:

  • 这就是我的 JSON 的样子。 Jackson NOT 正确地反序列化它。试试看。
  • @Adam Aha,我稍后会回复你。 (考虑升级。)
  • @Adam 它也适用于 Jackson 1。我已经发布了确切的代码(这是你的 + getters/setters),所以你可以验证。杰克逊 1.9.13.
  • 感谢您的帮助。你是对的,这行得通。我的问题是关于动物的集合。我做了更多的测试,发现这就是问题所在。我已经相应地修改了问题。
  • @Adam 我已经编辑了我的答案。将 List&lt;Cage&lt;?&gt;&gt; 替换为 List&lt;Cage&gt; ,即。原始类型,在 Zoo 类中的任何位置。
【解决方案2】:

我认为您应该通过删除不必要的类型并使用JsonTypeInfo.As.EXTERNAL_PROPERTY 而不是JsonTypeInfo.As.PROPERTY 来简化您的解决方案。使用JsonTypeInfo.As.EXTERNAL_PROPERTY,您不必创建Cage 子类。而且您根本不必创建AnimalType。您的 POJO 类可能如下所示:

@JsonIgnoreProperties(ignoreUnknown = true)
class Cage<ANIMAL> {

    @JsonSubTypes({
        @JsonSubTypes.Type(value = Lion.class, name = "LION"),
        @JsonSubTypes.Type(value = Tiger.class, name = "TIGER")
    })
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
    private ANIMAL animal;

    public ANIMAL getAnimal() {
        return animal;
    }

    public void setAnimal(ANIMAL animal) {
        this.animal = animal;
    }

    @Override
    public String toString() {
        return "Cage [animal=" + animal + "]";
    }
}

class Lion {

    private int maneLength;

    public int getManeLength() {
        return maneLength;
    }

    public void setManeLength(int maneLength) {
        this.maneLength = maneLength;
    }

    @Override
    public String toString() {
        return "Lion [maneLength=" + maneLength + "]";
    }
}

class Tiger {

    private int length;

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    @Override
    public String toString() {
        return "Tiger [maneLength=" + length + "]";
    }
}

简单用法:

String jsonLion = "{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}";
String jsonTiger = "{\"type\": \"TIGER\", \"animal\": {\"length\" : 11}}";

ObjectMapper om = new ObjectMapper();

System.out.println(om.readValue(jsonLion, Cage.class));
System.out.println(om.readValue(jsonTiger, Cage.class));

上面的代码打印:

Cage [animal=Lion [maneLength=10]]
Cage [animal=Tiger [maneLength=11]]

我没有使用Jackson 1.X 测试我的解决方案,但我希望它对你有用。

【讨论】:

    猜你喜欢
    • 2012-07-24
    • 2012-10-18
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 2019-04-29
    • 2020-07-23
    相关资源
    最近更新 更多