在使用Jackson的TypeResolverBuilder时反序列化原语长字段



运行以下测试应用程序

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Main {
    public static void main(String[] args) throws IOException {
        // Create test data
        Data data = new Data();
        data.key = 1;
        Map<String, Object> mapData = new HashMap<>();
        mapData.put("longInMap", 2L);
        mapData.put("longAsField", data);
        // Configure Jackson to preserve types
        JsonFactory factory = new JsonFactory();
        ObjectMapper mapper = new ObjectMapper(factory);
        StdTypeResolverBuilder resolver = new StdTypeResolverBuilder();
        resolver.init(JsonTypeInfo.Id.CLASS, null);
        resolver.inclusion(JsonTypeInfo.As.PROPERTY);
        resolver.typeProperty("__t");
        mapper.setDefaultTyping(resolver);
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        // Serialize
        String json = mapper.writeValueAsString(mapData);
        System.out.println("json = " + json);
        // Deserialize
        Map deserializedData = mapper.readValue(json, Map.class);
    }
    static class Data {
        public long key;
    }
}

我得到这样的输出和异常

json = {
  "__t" : "java.util.HashMap",
  "longInMap" : [ "java.lang.Long", 2 ],
  "longAsField" : {
    "__t" : "com.pinkmatter.bean.serialization.Main$Data",
    "key" : [ "java.lang.Long", 1 ]
  }
}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Class java.lang.Long not subtype of [simple type, class long] (through reference chain: java.util.HashMap["longAsField"]->com.pinkmatter.bean.serialization.Data["key"])
  at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:379)
  at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:339)
  at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1591)
  at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
  ...
Caused by: java.lang.IllegalArgumentException: Class java.lang.Long not subtype of [simple type, class long]
  at com.fasterxml.jackson.databind.type.TypeFactory.constructSpecializedType(TypeFactory.java:359)
  at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver._typeFromId(ClassNameIdResolver.java:72)
  at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver.typeFromId(ClassNameIdResolver.java:42)
  ...

我试图从我们正在使用的库中序列化一堆基本的普通旧java对象(所以我们不能修改类或添加注释),同时也试图保留集合中值的类型(上面示例中的"longInMap"必须保持为Long对象)。

问题是Jackson在试图反序列化Data类中的原语public long key时抛出上述异常。如果我将类型更改为public int key,则不会抛出异常并且反序列化工作。

另外,由于有许多不同类型的对象,我不知道在编译时确切地知道什么将被序列化,我认为使用mix-in是行不通的。

请告诉我可能做错了什么,或者在保持集合中对象类型的同时,对原始长字段进行反序列化的可能的解决方案。

我用的是Jackson 2.8.3

这里提供了一个解决方案https://github.com/FasterXML/jackson-databind/issues/1395

解决方法是替换

StdTypeResolverBuilder resolver = new StdTypeResolverBuilder();

StdTypeResolverBuilder resolver = new StdTypeResolverBuilder() {
        @Override
        public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
            if (baseType.isPrimitive()) {
                return null;
            }
            return super.buildTypeSerializer(config, baseType, subtypes);
        }
        @Override
        public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
            if (baseType.isPrimitive()) {
                return null;
            }
            return super.buildTypeDeserializer(config, baseType, subtypes);
        }
    };

已实现修复,并将在jackson-databind 2.8.4中提供,之后将不再需要解决方法。

最新更新