简体   繁体   English

如何使用杰克逊反序列化泛型类型?

[英]How to deserialize a generic type with jackson?

I tried many solutions, but my case seems special. 我尝试了许多解决方案,但我的情况似乎很特殊。 The @JsonProperty must be depending on class type: @JsonProperty必须取决于类类型:

I have JSON for two entities: 我有两个实体的JSON:

"Person": [ { "id": "452009517701", "name": "Perosn1", "address": "541-DPL-355" } ] “人”:[{“ id”:“ 452009517701”,“ name”:“ Perosn1”,“ address”:“ 541-DPL-355”}]

"Car": [ { "id": 5787544, "brand": "Toyota", "number": 12454 } ] “汽车”:[{“ id”:5787544,“ brand”:“ Toyota”,“ number”:12454}]

The entities look like : 实体看起来像:

public class Person{
    private String id:
    private String name;
    private String address:
    // Constcutors && Getters && Setters
}

public class Car{
    private Long id:
    private String brand;
    private Long number:
    // Constcutors && Getters && Setters
}

The generic class : 通用类:

public class GenericEntity<T>{
    //@JsonProperty
    private List<T> myList;
    // Constcutors && Getters && Setters
}

Main class : 主类:

public static void main(String[] args) {
        ObjectMapper mapper=new ObjectMapper();
        GenericEntity p=mapper.readValue(personJson,GenericEntity.class);
        GenericEntity c=mapper.readValue(carJson,GenericEntity.class);
    }

When I debug I find that the lists inside GenericEntity are always null. 调试时,我发现GenericEntity内的列表始终为空。 I do not know how to set jsonProperty dynamically on the top of the list inside the GenericEntity . 我不知道如何在GenericEntity内部列表的顶部动态设置jsonProperty。

Also, i used : 另外,我用过:

Object readValue = mapper.readValue(jsonPerson, new TypeReference<GenericEntity<Person>>() {}); 

And : 和:

JavaType javaType = mapper.getTypeFactory().constructParametricType(GenericEntity.class, Person.class);
        Object readValue =mapper.readValue(jsonPerson, javaType);

Bu i got this : 我知道了:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.test.GenericEntity` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Person')
 at [Source: (String)""Person": [ { "id": "452009517701", "name": "Perosn1", "address": "541-DPL-355" } ]"; line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1032)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)

The simplest option would be to use a wrapper type with a separate field per collection type, like that: 最简单的选择是使用包装类型,每个集合类型都使用一个单独的字段,例如:

class GenericEntity {
    @JsonProperty("Car") List<Car> car; 
    @JsonProperty("Person") List<Person> person; 
}

This way you would always have one of those lists filled (according to our conversation in comments). 这样,您总是可以填写其中一个列表(根据我们在评论中的对话)。 This will work fine as long as you don't have too many types and it doesn't change too frequently :) 只要您没有太多的类型并且它不会经常更改就可以了:)

The more-advanced way would be to use a custom deserializer, like that: 更高级的方法是使用自定义解串器,如下所示:

@JsonDeserialize(using = MyDeserializer.class)
class GenericEntity<T> {
    List<T> myList;

    GenericEntity(List<T> myList) {
        this.myList = myList;
    }
}

The deserializer itself would have to create a GenericEntity on its own, but it can delegate all specific-type-deserializing job to other deserializers (so our job would be just to tell it what to deserialize and to what type): 反序列化器本身必须自己创建一个GenericEntity ,但是它可以将所有特定类型反序列化的工作委派给其他反序列化器(因此,我们的工作就是告诉它要反序列化的类型和类型):

class MyDeserializer extends JsonDeserializer<GenericEntity<?>> {

    @Override
    public GenericEntity<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        ObjectCodec codec = p.getCodec();
        JsonNode node = codec.readTree(p);
        if (node.hasNonNull("Person")) {
            JsonParser nodeParser = node.get("Person").traverse(codec);
            nodeParser.nextToken();
            Person[] people = ctxt.readValue(nodeParser, Person[].class);
            return new GenericEntity<>(asList(people));
        } else if (node.hasNonNull("Car")) {
            JsonParser nodeParser = node.get("Car").traverse(codec);
            nodeParser.nextToken();
            Car[] cars = ctxt.readValue(nodeParser, Car[].class);
            return new GenericEntity<>(asList(cars));
        }
        throw new RuntimeException("Couldn't find a type to deserialize!");
    }
}

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

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