У меня есть карты в формате JSON как это:Deserialize 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 все равно должны иметь конструктор без аргументов, так что я в конечном итоге строить сломанный объект сначала:
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;
}
}
Есть ли лучше/простой способ сделать это?
Я знаю, что это уже несколько месяцев, но вы когда-нибудь находили более чистый подход к этому? Мне нужно сделать что-то подобное и не нашел ничего лучшего. – sfitts
Я закончил создание собственной структуры сериализации с помощью [Gson] (http://code.google.com/p/google-gson/). Джексон был слишком запутан. –