使用Java中的杰克逊将具有不同类型的值的地图序列化为JSON

问题描述

我想将给定的哈希图序列化为json并将其反序列化回原始图。

在这里,我想使它通用,以便其无缝运行,而与值的类型无关。

我正在使用以下代码段来构建地图,然后将其序列化为json:

Map<String,Map<String,Object>> argumentNameValueMap = new HashMap<>();

for (int i = 0; i < codeSignature.getParameterNames().length; i++) {
  argumentNameValueMap.put(codeSignature.getParameterNames()[i],mapper.convertValue(joinPoint.getArgs()[i],Map.class)); <----THIS LINE IS FAILING WHEN ARGUMENT VALUE IS OF PRIMITIVE TYPE.
}

return mapper.writeValueAsString(argumentNameValueMap);

当要放入映射中的值的类型是一个对象,但是当该值是任何原始类型(例如String / Integer等)时失败,这可以很好地工作。

我可以通过检查关联的值类型是否为任何原始类型来处理此问题,并相应地添加其他值。

但是我想知道是否还有更好的方法可以做到这一点。谢谢。

解决方法

JSON规范中,可识别的值为:JSON Object-{...}JSON Array-[...]stringnumberfalsetruenull。默认情况下,只有JSON Object可以反序列化为MapMap可以序列化为JSON Object

在您的情况下,您需要手动处理其他类型,然后以某种方式将它们转换为Map实例。您可以实现自己的com.fasterxml.jackson.databind.deser.DeserializationProblemHandler,以便在出现问题时拦截转换机制。

下面您可以找到一个简单的实现方法:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) {
        Map<String,Object> source = new HashMap<>();
        source.put("pojo",new SomeClass());
        source.put("string","String-Value");
        source.put("int",1);
        source.put("null",null);
        source.put("char",'A');
        source.put("long",Long.MIN_VALUE);
        source.put("list",Arrays.asList(1,3));
        source.put("array",new int[]{12,13});

        ObjectMapper mapper = new ObjectMapper();
        mapper.addHandler(new Convert2MapDeserializationProblemHandler());

        Map<String,Map<String,Object>> argumentNameValueMap = new HashMap<>();
        for (Map.Entry<String,Object> entry : source.entrySet()) {
            argumentNameValueMap.put(entry.getKey(),mapper.convertValue(entry.getValue(),Map.class));
        }
        argumentNameValueMap.forEach((k,v) -> System.out.println(k + " -> " + v));
    }
}

class Convert2MapDeserializationProblemHandler extends DeserializationProblemHandler {
    @Override
    public Object handleMissingInstantiator(DeserializationContext ctxt,Class<?> instClass,ValueInstantiator valueInsta,JsonParser p,String msg) throws IOException {
        if (Map.class.isAssignableFrom(instClass)) {
            Map<String,Object> map = new LinkedHashMap<>();
            TreeNode value = p.readValueAsTree();
            map.put("value",value);
            return map;
        }
        return super.handleMissingInstantiator(ctxt,instClass,valueInsta,p,msg);
    }

    @Override
    public Object handleUnexpectedToken(DeserializationContext ctxt,JavaType targetType,JsonToken t,String failureMsg) throws IOException {
        if (Map.class.isAssignableFrom(targetType.getRawClass())) {
            Map<String,value);
            return map;
        }
        return super.handleUnexpectedToken(ctxt,targetType,t,failureMsg);
    }
}

class SomeClass {
    String stringField = "Value!";

    public String getStringField() {
        return stringField;
    }

    public void setStringField(String stringField) {
        this.stringField = stringField;
    }

    @Override
    public String toString() {
        return "SomeClass{" +
                "stringField='" + stringField + '\'' +
                '}';
    }
}

上面的代码打印:

pojo -> {stringField=Value!}
string -> {value="String-Value"}
null -> null
array -> {value=[12,13]}
char -> {value="A"}
list -> {value=[1,3]}
int -> {value=1}
long -> {value=-9223372036854775808}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...