如何使用 Jackson ObjectMapper 反序列化带有类型元数据的 json 列表?

问题描述 投票:0回答:2

杰克逊版本:2.11.1

我正在尝试将 List 序列化为 json 字符串,然后反序列化它:

public class JacksonTypeTest {

    public static abstract class Pet {
        final String name;

        protected Pet(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    public static class Dog extends Pet {

        public Dog(@JsonProperty("name") String name) {
            super(name);
        }
    }

    public static class Cat extends Pet {

        public Cat(@JsonProperty("name") String name) {
            super(name);
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        List<Pet> pets = new ArrayList<>();
        pets.add(new Dog("Dog1"));
        pets.add(new Cat("Cat1"));

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator()); // Embed typing data into json

        String json = objectMapper.writeValueAsString(pets);
        System.out.println(json);
        // output: [["com.hyd.jacksontest.JacksonTypeTest$Dog",{"name":"Dog1"}],["com.hyd.jacksontest.JacksonTypeTest$Cat",{"name":"Cat1"}]]

        ObjectReader listReader = objectMapper.readerForListOf(Pet.class);
        List<Pet> petList = listReader.readValue(json);
        // exception: Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException:
        // Unexpected token (START_ARRAY), expected VALUE_STRING:
        // need JSON String that contains type id (for subtype of java.util.List)

        System.out.println(petList);
    }
}

它在第

List<Pet> petList = listReader.readValue(json);
行失败,并显示消息:

意外的标记 (START_ARRAY),预期的 VALUE_STRING:需要包含类型 id 的 JSON 字符串(对于 java.util.List 的子类型)

输出:

[["com.hyd.jacksontest.JacksonTypeTest$Dog",{"name":"Dog1"}],["com.hyd.jacksontest.JacksonTypeTest$Cat",{"name":"Cat1"}]]
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_ARRAY), expected VALUE_STRING: need JSON String that contains type id (for subtype of java.util.List)
 at [Source: (String)"[["com.hyd.jacksontest.JacksonTypeTest$Dog",{"name":"Dog1"}],["com.hyd.jacksontest.JacksonTypeTest$Cat",{"name":"Cat1"}]]"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
    at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1650)
    at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1400)
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:155)
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96)
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserializeWithType(CollectionDeserializer.java:319)
    at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
    at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2057)
    at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1496)
    at com.hyd.jacksontest.JacksonTypeTest.main(JacksonTypeTest.java:52)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)

如何进行反序列化?

java jackson
2个回答
1
投票

好吧,我终于明白了。

问题是,根对象没有类型元数据。

要解决此问题,我需要更改代码:

objectMapper.activateDefaultTyping(
    objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL
);

添加第二个参数后,生成的 JSON 字符串如下所示:

["java.util.ArrayList",[["com.hyd.jacksontest.JacksonTypeTest$Dog",{"name":"Dog1"}],["com.hyd.jacksontest.JacksonTypeTest$Cat",{"name":"Cat1"}]]]

这样就可以成功反序列化了。代码现在可以运行了。


0
投票

您检查过调试正在反序列化的内容吗? json值和你的对象一样吗?

替代代码:

创建一个包含 Pet.class 列表的包装对象类。

如果你不想创建包装类,那么你需要将 json 字符串反序列化为 String 类型的 List 并循环遍历该列表,将字符串反序列化为 Pet 类。

    List <String> petJsons = new ArrayList <> ();
    petJsons = mapper.readValue(json, List.class);

    for (Iterator <String> iterator = petJsons.iterator(); iterator.hasNext();) {
        String petJson = (String) iterator.next();
        pets.add(objectMapper.objectMapper.readValue(petJson, Pet.class));
    }

© www.soinside.com 2019 - 2024. All rights reserved.