Jackson无法将java.util.List读取为泛型类型

mctunoxg  于 7个月前  发布在  Java
关注(0)|答案(1)|浏览(78)

当我尝试再次序列化和重新序列化泛型类型Jackson中的List时失败。
有一个JDoodle,如果你想玩一个工作的例子:https://jdoodle.com/a/6nJ4
这是我的泛型类

public static class UserMessageResult<T> {

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
    private T entity;

    public UserMessageResult() {
    }

    public UserMessageResult(T entity) {
        this.entity = entity;
    }
}

这个类在列表中用作泛型

@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY)
public static class AnEntity {

    private int anInt;
    private String aString;

    public AnEntity() {
    }

    public AnEntity(int anInt, String aString) {
        this.anInt = anInt;
        this.aString = aString;
    }

    public int getAnInt() {
        return anInt;
    }

    public String getaString() {
        return aString;
    }

}

如果我将AnEntity放入List中,并将此列表添加到UserMessageResult中,则Jackson无法读取它刚刚创建的JSON。

List<AnEntity> anEntityList= List.of(
        new AnEntity(10, "aaa"),
        new AnEntity(20, "bbb")
    );
    UserMessageResult<List<AnEntity>> userMessageResult = new UserMessageResult(anEntityList);
    System.out.println(userMessageResult);
    
    String jsonStr = MAPPER.writeValueAsString(userMessageResult);
    System.out.println(jsonStr);
    

    final TypeReference<UserMessageResult<List<AnEntity>>> typeRef = new TypeReference<>() {
    };

    UserMessageResult<List<AnEntity>> actualUserMessageResult = MAPPER.readValue(jsonStr, typeRef);
    System.out.println(actualUserMessageResult);

错误消息

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class MyClass$AnEntity]: missing type id property '@class' (for POJO property 'entity')
 at [Source: (String)"{
  "entity" : [ "java.util.ImmutableCollections$List12", [ {
    "anInt" : 10,
    "aString" : "aaa"
  }, {
    "anInt" : 20,
    "aString" : "bbb"
  } ] ]
}"; line: 2, column: 16] (through reference chain: MyClass$UserMessageResult["entity"]->java.util.ArrayList[0])
    at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
    at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:2094)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1607)
    at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:307)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:211)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:122)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1296)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:361)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
    at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4825)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3772)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3755)
    at MyClass.listOfEntities(MyClass.java:57)
    at MyClass.main(MyClass.java:21)

显然,列表项中的@class属性丢失了。如果我手动更改JSON并添加@class属性,一切都正常:

System.out.println("+++++++++++++++++ Manualy corrected JSON +++++++++++++++++");
    String jsonStr = """
        {
          "entity" :  [ {
            "@class" : "MyClass$AnEntity",
            "anInt" : 10,
            "aString" : "String 1"
          }, {
            "@class" : "MyClass$AnEntity",
            "anInt" : 20,
            "aString" : "String 2"
          } ] 
        }
        """;

    final TypeReference<UserMessageResult<List<AnEntity>>> typeRef = new TypeReference<>() {
    };

    UserMessageResult<?> actualUserMessageResult = MAPPER.readValue(jsonStr, typeRef);
    System.out.println( actualUserMessageResult);

我用的是Jackson2.15.这在Jackson2.14版之前一直正常工作。使用和不使用@JsonTypeInfo注解并没有改变任何东西。
有什么想法吗?

mo49yndu

mo49yndu1#

1.当你通过使用TypeReference告诉解析器你的对象的类型时,只需要删除@JsonTypeInfo注解和你的listOfEntities()代码(你首先序列化它,然后再序列化结果json String)就会开始工作。
1.如果你想保持类型信息存储在序列化的字符串中,而不是TypeReference,只使用原始类型:

MAPPER.readValue(jsonStr, UserMessageResult.class)

我检查了我的编译器中的两个替代方案和两个工作。
令人惊讶的是,你在jdoodle代码中的“手动更正”deserializeJson()方法对我不起作用。这里我得到一个错误:

Unrecognized field "aString" (class MyClass$AnEntity)

在Sping Boot 3.1.1下测试,Jackson依赖由Sping Boot parent管理:

<jackson-bom.version>2.15.2</jackson-bom.version>

相关问题