I have JSON cards:
"things": {"foo": {"name": "foo", ...}, "bar": {"name": "bar", ...}}
I want to deserialize them as if they were arrays:
"things": [{"name": "foo", ...}, {"name": "bar", ...}]
(according to XML / JAXB deserialization behavior):
<things><thing name="foo">...</thing><thing name="bar">...</thing></things>
in a collection such as:
@XmlElementWrapper @XmlElement(name = "thing") @JsonDeserialize(using = MapToCollectionDeserializer.class) Collection<Thing> things;
Note that I have collections with different types of elements, not just Thing - so I need a common mechanism.
However, when writing a custom deserializer, what is the right way to access context type information?
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);
My approach still uses the ContextualDeserializer , which can provide BeanProperty (which contains type information) for the deserializer. However, the JsonDeserializer should still have a no-arg constructor, so I first create a broken object:
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; } }
Is there a better / easier way to do this?