出于外部原因,我的系统中的所有java Map
只能作为来自客户端的键值对的列表接收,例如:实际上将收到Map<String, Book>
作为Json序列化的List<MapEntry<String, Book>>
。这意味着我需要自定义我的Json反序列化过程以期望地图的这种表示。
问题是JsonDeserializer
让我实现
deserialize(JsonParser p, DeserializationContext ctxt)
无法访问它应该反序列化的检测到的泛型类型的方法(上例中的Map<String, Book>
)。如果没有这些信息,我不能在不失去类型安全的情况下反序列化List<MapEntry<String, Book>>
。
我在看Converter,但它的背景更少。
E.g。
public Map<K,V> convert(List<MapToListTypeAdapter.MapEntry<K,V>> list) {
Map<K,V> x = new HashMap<>();
list.forEach(entry -> x.put(entry.getKey(), entry.getValue()));
return x;
}
但这可能会创建危险的地图,会在检索时抛出ClassCastException
,因为无法检查类型是否合理。
有办法解决这个问题吗?
作为我期望的一个例子,Gson的JsonDeserializer
看起来像这样:
T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
即。它以理智的方式提供对期望类型的访问。
答案 0 :(得分:2)
直接从作者那里得到Jackson Google group的答案。
要理解的关键是 JsonDeserializer
被创建/上下文化,并且他们仅在那一刻收到完整类型和其他信息。要获得此信息,解串器需要实现ContextualDeserializer
。调用其createContextual
方法来初始化反序列化器实例,并且可以访问BeanProperty
,这也提供了完整的JavaType
。
所以它最终看起来像这样:
public class MapDeserializer extends JsonDeserializer implements ContextualDeserializer {
private JavaType type;
public MapDeserializer() {
}
public MapDeserializer(JavaType type) {
this.type = type;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
//beanProperty is null when the type to deserialize is the top-level type or a generic type, not a type of a bean property
JavaType type = deserializationContext.getContextualType() != null
? deserializationContext.getContextualType()
: beanProperty.getMember().getType();
return new MapDeserializer(type);
}
@Override
public Map deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
//use this.type as needed
}
...
}
注册并正常使用:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Map.class, new MapDeserializer());
mapper.registerModule(module);