英文:
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)); // <----当参数值为基本类型时,此行失败。
}
return mapper.writeValueAsString(argumentNameValueMap);
当要放入映射中的值的类型为对象时,这段代码正常工作,但在值的类型为任何基本类型(如String/Integer等)时会失败。
我可以通过检查关联值的类型是否为任何基本类型,并相应地添加 if else 条件来处理这个问题。
但我想知道是否有更好的方法来做到这一点。谢谢。
英文:
I would like to serialize a given hashmap into json and deserialize it back to the original map.
Here I would like to make this generic so that it behaves seamlessly regardless of the type of the value.
I am using the following code snippet for constructing the map and then serailizing it as 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);
This is working fine when the type of value that is going to put into the map is an object but fails while the value is of any primitive type i.e. String/Integer etc.
I can handle this by writing a check if the associated value type is of any primitive type and add if else accordingly.
But I would like to know if there is any better way to do this. Thanks.
答案1
得分: 1
在`JSON`规范中,被认可的值包括:`JSON Object` - `{...}`,`JSON Array` - `[...]`,`string`,`number`,`false`,`true`和`null`。只有`JSON Object`可以默认被反序列化为`Map`,而`Map`可以被序列化为`JSON Object`。
在您的情况下,您需要手动处理其他类型,并将它们转换为`Map`实例。您可以实现自己的`com.fasterxml.jackson.databind.deser.DeserializationProblemHandler`,它允许在出现问题时拦截转换机制。
以下是一个简单的实现示例:
```java
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}
英文:
In JSON
specification recognized values are: JSON Object
- {...}
, JSON Array
- [...]
, string
, number
, false
, true
and null
. Only JSON Object
can be deserialised by default to Map
and Map
can be serialised to a JSON Object
.
In your case you need to handle other types manually and convert them to Map
instance somehow. You can implement your own com.fasterxml.jackson.databind.deser.DeserializationProblemHandler
which allows to intercept conversion mechanism in case of problems.
Below you can find a simple implementation how to do that:
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 + '\'' +
'}';
}
}
Above code prints:
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}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论