简体   繁体   English

用Jackson反序列化自定义地图

[英]Deserialize a custom Map with Jackson

I'm currently trying to serialize and deserialize a custom Map type as JSON using Jackson 2.8.4. 我目前正在尝试使用Jackson 2.8.4将自定义Map类型序列化和反序列化为JSON。 I've managed to get serialization working based on this answer , but I'm struggling with deserialization. 我已经设法根据此答案进行序列化工作,但是我在反序列化方面苦苦挣扎。 Here is an example: 这是一个例子:

public class TestMapSerialize {

    public interface TestMapGetters {
        Map<String, String> getFooMap();
        Map<String, String> getBarMap();
    }

    @JsonSerialize(as = TestMapGetters.class)
    public static class TestMap extends ForwardingMap<String, String>
            implements TestMapGetters {

        private Map<String, String> fooMap;
        private Map<String, String> barMap;

        @Override
        protected Map<String, String> delegate() {
            return ImmutableMap.<String, String>builder()
                    .putAll(fooMap)
                    .putAll(barMap)
                    .build();
        }

        // Getters and setters...

    }

    public static void main(String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();
        final TestMap map = new TestMap();

        map.setFooMap(ImmutableMap.of("a", "b", "c", "d"));
        map.setBarMap(ImmutableMap.of("e", "f", "g", "h"));

        final String json = mapper.writeValueAsString(map);

        // Prints {"fooMap":{"a":"b","c":"d"},"barMap":{"e":"f","g":"h"}} as expected.
        System.out.println(json);

        // Throws JsonMappingException, see below.
        final TestMap copy = mapper.readValue(json, TestMap.class);
    }

}

When I try to deserialize as above, I get an exception: 当我尝试如上所述反序列化时,出现异常:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: {"fooMap":{"a":"b","c":"d"},"barMap":{"e":"f","g":"h"}}; line: 1, column: 11] (through reference chain: test.TestMapSerialize$TestMap["fooMap"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
    at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1234)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1122)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1075)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:60)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:517)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:362)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:27)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
    at test.TestMapSerialize.main(TestMapSerialize.java:66)

So Jackson is still trying to deseralize my class as though it's a generic Map , which won't work because it's a bean. 因此,杰克逊仍在尝试对类进行反序列化,就好像它是通用Map ,因为它是bean,所以无法正常工作。 I've tried adding @JsonDeserialize(as = TestMapGetters.class) as well, but then I get: 我也尝试添加@JsonDeserialize(as = TestMapGetters.class) ,但随后得到:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Failed to narrow type [map type; class test.TestMapSerialize$TestMap, [simple type, class java.lang.String] -> [simple type, class java.lang.String]] with annotation (value test.TestMapSerialize$TestMapGetters), from 'test.TestMapSerialize$TestMap': Class test.TestMapSerialize$TestMapGetters not subtype of [map type; class test.TestMapSerialize$TestMap, [simple type, class java.lang.String] -> [simple type, class java.lang.String]]
    at com.fasterxml.jackson.databind.AnnotationIntrospector.refineDeserializationType(AnnotationIntrospector.java:1194)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.modifyTypeByAnnotation(DeserializerCache.java:519)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:333)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:476)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3899)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3794)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
    at test.TestMapSerialize.main(TestMapSerialize.java:68)
Caused by: java.lang.IllegalArgumentException: Class test.TestMapSerialize$TestMapGetters not subtype of [map type; class test.TestMapSerialize$TestMap, [simple type, class java.lang.String] -> [simple type, class java.lang.String]]
    at com.fasterxml.jackson.databind.type.TypeFactory.constructSpecializedType(TypeFactory.java:359)
    at com.fasterxml.jackson.databind.AnnotationIntrospector.refineDeserializationType(AnnotationIntrospector.java:1192)
    ... 10 more

which makes sense, because it's not a subtype. 这很有意义,因为它不是子类型。 I'd rather not have to write a custom deserializer, since this would deserialize fine if my object weren't a subtype of Map . 我宁愿不必编写自定义反序列化器,因为如果我的对象不是Map的子类型,则可以反序列化。 Is there any way I can tell Jackson to ignore the fact that my class is a Map and just deserialize as a bean? 我有什么办法可以告诉杰克逊忽略我的班级是Map而是反序列化为bean的事实吗?

I figured out that I can add a static creator method to my TestMap class: 我发现可以向我的TestMap类添加静态创建者方法:

@JsonCreator
static TestMap fromJson(
        @JsonProperty("fooMap") ImmutableMap<String, String> fooMap,
        @JsonProperty("barMap") ImmutableMap<String, String> barMap) {
    final TestMap map = new TestMap();
    map.setFooMap(fooMap);
    map.setBarMap(barMap);
    return map;
}

It would still be nice to have a way to say "just serialize and deserialize as a POJO" to avoid the whole @JsonCreator and @JsonSerialize(as) rigamarole. 最好有一种方式说“只是作为POJO序列化和反序列化”,以避免整个@JsonCreator@JsonSerialize(as)

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

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