2012-03-29 2 views
4

У меня есть карты в формате 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; 
    } 
} 

Есть ли лучше/простой способ сделать это?

+0

Я знаю, что это уже несколько месяцев, но вы когда-нибудь находили более чистый подход к этому? Мне нужно сделать что-то подобное и не нашел ничего лучшего. – sfitts

+0

Я закончил создание собственной структуры сериализации с помощью [Gson] (http://code.google.com/p/google-gson/). Джексон был слишком запутан. –

ответ

-1

Похоже, вы прекратили использовать Джексона, но для всех, у кого есть аналогичная проблема, вы можете включить DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY. Когда этот параметр включен, когда Джексон находит объект в JSON, но он должен десериализоваться в коллекции, он создаст коллекцию и поместит объект в коллекцию, которая кажется вам такой, какой вы хотите.

+0

Полезно знать, но я не думаю, что он обращается к этому делу. В приведенном выше примере это звучит так, как будто это даст мне один объект в коллекции с свойствами «foo» и «bar», чего я не хочу. Я по сути хочу игнорировать все имена свойств (поскольку они содержат избыточную информацию) и обрабатывать их значения как массив. –

Смежные вопросы