Jackson从对象映射中取消枚举序列化



假设我们有一个带有Map<String, Object>的Pojo,我们如何告诉Jackson对象映射器一些键名实际上是枚举而不是字符串?例如,映射将不相等,因为attr5将被取消序列化为String而不是MyEnum。

public class App {
enum MyEnum {
A,
B,
C;
}
static class Pojo {
private Map<String, Object> map = new HashMap<>();
public void setEntry(String key, Object value) {
map.put(key, value);
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Pojo pojo = new Pojo();
pojo.setEntry("attr1", 1);
pojo.setEntry("attr2", false);
pojo.setEntry("attr3", "hello");
pojo.setEntry("attr4", Arrays.asList("a", "b", "c"));
pojo.setEntry("attr5", MyEnum.A);
String pojoString = mapper.writeValueAsString(pojo);
Pojo newPojo = mapper.readValue(pojoString, Pojo.class);
System.out.println("Maps are equal: " + newPojo.getMap().equals(pojo.getMap()));
}
}

因为fps说jackson无法区分Object中的enum和String。在这种情况下,我将建议您在json中传输变量的类型。它很简单,可以满足你的需要。请尝试:

Jackson配置:

ObjectMapper mapper = new ObjectMapper();
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator
.builder()
.allowIfBaseType(Object.class)
.build();
mapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);

您的json将看起来像:

{"map":{"attr5":["com.company.MyEnum","A"],"attr2":false,"attr1":1,"attr4":["java.util.Arrays$ArrayList",["a","b","c"]],"attr3":"hello"}}

它只会将类型信息添加到Map with Object类型中的值中。你的测试将通过,因为两张地图将相等。

我的解决方案是为映射制作一个自定义序列化程序。

class CustomMapDeserializer extends StdDeserializer<Map<String,Object>> {
public CustomMapDeserializer() {
this(null);
}

public CustomMapDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Map<String,Object> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> res = new LinkedHashMap<>();
for(Map.Entry<String, JsonNode> n : jp.getCodec().readTree(jp).fields()){
if(!n.getKey().equals("attr5")) //Only attr5 will be taken as enum
res.put(n.getKey(),mapper.treeToValue(n.getValue(),Object.class))
else
res.put(n.getKey(),mapper.treeToValue(n.getValue(),MyEnum.class))
}
return res;
}
}
class Pojo {
@JsonDeserialize(using= CustomMapDeserializer.class)    //Apply Deserializer here
private Map<String, Object> map = new HashMap<>();
public void setEntry(String key, Object value) {
map.put(key, value);
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}
...

最新更新