在 Java 中使用 Jackson 将具有不同类型值的映射序列化为 JSON
Serializing map having value of different types to JSON using Jackson in Java
我想将给定的哈希映射序列化为 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 等
我可以通过编写检查关联值类型是否为任何原始类型并相应地添加 if else 来处理此问题。
但是我想知道是否有更好的方法来做到这一点。谢谢
在 JSON
规范中识别的值为:JSON Object
- {...}
、JSON Array
- [...]
、string
、number
、false
、true
和 null
。默认情况下,只有 JSON Object
可以反序列化为 Map
,而 Map
可以序列化为 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, JsonParser p, String failureMsg) throws IOException {
if (Map.class.isAssignableFrom(targetType.getRawClass())) {
Map<String, Object> map = new LinkedHashMap<>();
TreeNode value = p.readValueAsTree();
map.put("value", value);
return map;
}
return super.handleUnexpectedToken(ctxt, targetType, t, p, 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}
我想将给定的哈希映射序列化为 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 等
我可以通过编写检查关联值类型是否为任何原始类型并相应地添加 if else 来处理此问题。
但是我想知道是否有更好的方法来做到这一点。谢谢
在 JSON
规范中识别的值为:JSON Object
- {...}
、JSON Array
- [...]
、string
、number
、false
、true
和 null
。默认情况下,只有 JSON Object
可以反序列化为 Map
,而 Map
可以序列化为 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, JsonParser p, String failureMsg) throws IOException {
if (Map.class.isAssignableFrom(targetType.getRawClass())) {
Map<String, Object> map = new LinkedHashMap<>();
TreeNode value = p.readValueAsTree();
map.put("value", value);
return map;
}
return super.handleUnexpectedToken(ctxt, targetType, t, p, 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}