我有这样的JSON地图:
"things": {"foo": {"name": "foo", ...}, "bar": {"name": "bar", ...}}
我想将它们反序列化,就像它们是数组一样:
"things": [{"name": "foo", ...}, {"name": "bar", ...}]
(以匹配XML / JAXB反序列化行为):
<things><thing name="foo">...</thing><thing name="bar">...</thing></things>
进入这样的集合:
@XmlElementWrapper
@XmlElement(name = "thing")
@JsonDeserialize(using = MapToCollectionDeserializer.class)
Collection<Thing> things;
请注意,我有各种元素类型的集合 - 不只是Thing
- 所以我需要一个通用的机制。
但是,在编写自定义反序列化器时,访问上下文类型信息的正确方法是什么?
public class MapToCollectionDeserializer extends StdDeserializer<Object>
{
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
Preconditions.checkState(jp.getCurrentToken() == JsonToken.START_OBJECT);
final LinkedList<Object> result = new LinkedList<>();
JsonToken tok;
while ((tok = jp.nextToken()) != JsonToken.END_OBJECT)
{
Preconditions.checkState(tok == JsonToken.FIELD_NAME);
// How to get the collection element type for deserialization?
result.add(...);
}
return result;
}
}
到目前为止,我的方法是使用ContextualDeserializer
,它可以向反序列化程序提供BeanProperty
(包含类型信息)。但是,JsonDeserializer仍然必须有一个no-arg构造函数,所以我最初构造一个破坏的对象:
public class MapToCollectionDeserializer extends StdDeserializer<Object>
implements ContextualDeserializer<Object>
{
private final BeanProperty property;
public MapToCollectionDeserializer()
{
super(Collection.class);
property = null; // YUCK: BROKEN!!!
}
private MapToCollectionDeserializer(BeanProperty property)
{
super(property.getType());
this.property = property;
}
@Override
public JsonDeserializer<Object> createContextual(DeserializationConfig config,
BeanProperty property) throws JsonMappingException
{
return new MapToCollectionDeserializer(property);
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException
{
Preconditions.checkState(jp.getCurrentToken() == JsonToken.START_OBJECT);
final JavaType elementType = property.getType().containedType(0);
final LinkedList<Object> result = new LinkedList<>();
JsonToken tok;
while ((tok = jp.nextToken()) != JsonToken.END_OBJECT)
{
Preconditions.checkState(tok == JsonToken.FIELD_NAME);
jp.nextToken();
final JsonDeserializer<Object> valueDeser = ctxt.getDeserializerProvider()
.findValueDeserializer(ctxt.getConfig(), elementType, property);
result.add(valueDeser.deserialize(jp, ctxt));
}
return result;
}
}
有更好/更简单的方法吗?
答案 0 :(得分:-1)
看起来你停止使用杰克逊,但对于有类似问题的人,你可以打开DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
。启用该设置后,当杰克逊在JSON中找到一个对象但是应该反序列化为一个集合时,它将创建一个集合并将该对象放入集合中,这看起来就像你想要的那样。