有什么方法可以使用 Jackson 将带有 BigDecimal 键的 Map 序列化为 BigDecimal 而不是字符串?
Is there any way to serialize a Map with a BigDecimal key as a BigDecimal and not as string using Jackson?
尝试使用 Jackson 和 属性 ObjectMapper.DefaultTyping.NON_FINAL 序列化 Map 时,键被序列化为字符串,而值被正确序列化为 BigDecimal。当我反序列化它时,这会导致问题,因为它被反序列化为 Map.
我需要将密钥序列化为 BigDecimal 而不是字符串,有什么办法吗?
我正在使用 Jackson-all-1.9。11.jar,但我也尝试使用 jackson-2.12.4 罐子,但出现了同样的情况。
有什么解决办法吗?或者我可以创建一个自定义序列化器,它只覆盖 Map Serializer 以在 BigDecimal 键的情况下由 ObjectMapper 自动使用吗?如果是,如何实现?
下面是代码示例,返回结果。
public static void main(String[] args)
{
try
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Map<BigDecimal, BigDecimal> map = new HashMap<>();
map.put(BigDecimal.ONE, BigDecimal.ONE);
map.put(BigDecimal.TEN, BigDecimal.TEN);
String str = mapper.writeValueAsString(map);
System.out.println(str);
}
catch(Exception e)
{
e.printStackTrace();
}
}
结果如下:
["java.util.HashMap",{"10":["java.math.BigDecimal",10],"1":["java.math.BigDecimal",1]}]
您需要为要在 Map
中用作密钥的每个 class 实现一组自定义密钥序列化器和反序列化器。例如,对于数字,它可能如下所示:
class KeyBigDecimalJsonSerializer extends JsonSerializer<Number> {
@Override
public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeFieldName(value + "_" + value.getClass().getName());
}
}
class CustomKeyDeserializer extends KeyDeserializer {
private final ObjectMapper mapper = new ObjectMapper();
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
if (key.contains("_")) {
return deserializeKeyWithClass(key, ctxt);
}
return key;
}
private Object deserializeKeyWithClass(String key, DeserializationContext ctxt) throws IOException {
String[] parts = key.split("_");
try {
Class<?> aClass = ctxt.findClass(parts[1]);
return mapper.readValue(parts[0], aClass);
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
}
}
用法:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class MapKeysApp {
public static void main(String[] args) throws Exception {
SimpleModule module = new SimpleModule();
module.addKeySerializer(Number.class, new KeyBigDecimalJsonSerializer());
module.addKeyDeserializer(Object.class, new CustomKeyDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Map<Object, Object> map = new HashMap<>();
map.put(BigDecimal.ONE, BigDecimal.ONE);
map.put(BigDecimal.TEN, BigDecimal.TEN);
map.put(2.1D, 2.1D);
map.put(100, 100);
map.put("TEN", "ten");
String json = mapper.writeValueAsString(map);
System.out.println(json);
mapper.readValue(json, Map.class).forEach((k, v) -> {
System.out.println(k + " (" + k.getClass().getName() + ") : " + v + " (" + v.getClass().getName() + ")");
});
}
}
以上代码打印:
["java.util.HashMap",{"100_java.lang.Integer":100,"10_java.math.BigDecimal":["java.math.BigDecimal",10],"TEN":"ten","2.1_java.lang.Double":2.1,"1_java.math.BigDecimal":["java.math.BigDecimal",1]}]
100 (java.lang.Integer) : 100 (java.lang.Integer)
10 (java.math.BigDecimal) : 10 (java.math.BigDecimal)
TEN (java.lang.String) : ten (java.lang.String)
2.1 (java.lang.Double) : 2.1 (java.lang.Double)
1 (java.math.BigDecimal) : 1 (java.math.BigDecimal)
尝试使用 Jackson 和 属性 ObjectMapper.DefaultTyping.NON_FINAL 序列化 Map
我需要将密钥序列化为 BigDecimal 而不是字符串,有什么办法吗? 我正在使用 Jackson-all-1.9。11.jar,但我也尝试使用 jackson-2.12.4 罐子,但出现了同样的情况。
有什么解决办法吗?或者我可以创建一个自定义序列化器,它只覆盖 Map Serializer 以在 BigDecimal 键的情况下由 ObjectMapper 自动使用吗?如果是,如何实现?
下面是代码示例,返回结果。
public static void main(String[] args)
{
try
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Map<BigDecimal, BigDecimal> map = new HashMap<>();
map.put(BigDecimal.ONE, BigDecimal.ONE);
map.put(BigDecimal.TEN, BigDecimal.TEN);
String str = mapper.writeValueAsString(map);
System.out.println(str);
}
catch(Exception e)
{
e.printStackTrace();
}
}
结果如下:
["java.util.HashMap",{"10":["java.math.BigDecimal",10],"1":["java.math.BigDecimal",1]}]
您需要为要在 Map
中用作密钥的每个 class 实现一组自定义密钥序列化器和反序列化器。例如,对于数字,它可能如下所示:
class KeyBigDecimalJsonSerializer extends JsonSerializer<Number> {
@Override
public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeFieldName(value + "_" + value.getClass().getName());
}
}
class CustomKeyDeserializer extends KeyDeserializer {
private final ObjectMapper mapper = new ObjectMapper();
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
if (key.contains("_")) {
return deserializeKeyWithClass(key, ctxt);
}
return key;
}
private Object deserializeKeyWithClass(String key, DeserializationContext ctxt) throws IOException {
String[] parts = key.split("_");
try {
Class<?> aClass = ctxt.findClass(parts[1]);
return mapper.readValue(parts[0], aClass);
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
}
}
用法:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class MapKeysApp {
public static void main(String[] args) throws Exception {
SimpleModule module = new SimpleModule();
module.addKeySerializer(Number.class, new KeyBigDecimalJsonSerializer());
module.addKeyDeserializer(Object.class, new CustomKeyDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Map<Object, Object> map = new HashMap<>();
map.put(BigDecimal.ONE, BigDecimal.ONE);
map.put(BigDecimal.TEN, BigDecimal.TEN);
map.put(2.1D, 2.1D);
map.put(100, 100);
map.put("TEN", "ten");
String json = mapper.writeValueAsString(map);
System.out.println(json);
mapper.readValue(json, Map.class).forEach((k, v) -> {
System.out.println(k + " (" + k.getClass().getName() + ") : " + v + " (" + v.getClass().getName() + ")");
});
}
}
以上代码打印:
["java.util.HashMap",{"100_java.lang.Integer":100,"10_java.math.BigDecimal":["java.math.BigDecimal",10],"TEN":"ten","2.1_java.lang.Double":2.1,"1_java.math.BigDecimal":["java.math.BigDecimal",1]}]
100 (java.lang.Integer) : 100 (java.lang.Integer)
10 (java.math.BigDecimal) : 10 (java.math.BigDecimal)
TEN (java.lang.String) : ten (java.lang.String)
2.1 (java.lang.Double) : 2.1 (java.lang.Double)
1 (java.math.BigDecimal) : 1 (java.math.BigDecimal)