2016-03-22 23 views
9

Aşağıdaki senaryoyu düşünün:Genel bir tür için Jackson'da özel bir deserializer nasıl oluşturulur?

class <T> Foo<T> { 
    .... 
} 

class Bar { 
    Foo<Something> foo; 
} 

Ben Foo için özel Jackson deserializer yazmak istiyorum. Bunu yapmak için (örneğin, Foo<Something> özelliğine sahip Bar sınıfının seri hale getirilmesi için), Bar modelinde kullanılan Foo<T> beton türünü seri hale getirme zamanında (ör. T'un olduğunu bilmem gerekir) partikül vakası).

Bu tip bir desperizatör nasıl yazılır? Jackson, yazdığı koleksiyonlar ve haritalar ile yaptığı için bunu yapmak mümkün olmalıdır.

Açıklamalar: sorunun çözümü için 2 parça vardır

Öyle görünüyor: Foo<Somehting>

2 serisini

1) Bar içindeki mülkiyet foo beyan tipini elde ve bunu kullanın) Başarıyla 1)

)

no'lu adımı tamamlamak için foo sınıfının 0,sınıfında serileştirdiğimiz serileştirme zamanında öğrenin.

1 ve 2 nasıl tamamlanır?

+0

Sen * ilan öğrenmek için yansıma kullanabilirsiniz * foo'nun türü Foo 'dur. Bu konuda. Jackson'ın bunun burada sizin için bir araç olup olmadığını söyleyeceğini bilmiyorum. ['Alan # getGenericType'] (http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html#getGenericType--) – Radiodef

cevap

23

Ayrıca, ContextualDeserializer uygulayan genel türünüz için özel bir JsonDeserializer uygulayabilirsiniz.

public static class Wrapper<T> { 
    public T value; 
} 

Şimdi şöyle JSON serisini istiyorum: örneğine içine

{ 
    "name": "Alice", 
    "age": 37 
} 

Örneğin, genel bir değeri içeren aşağıdaki basit sarıcı türü olduğunu varsayalım şunun gibi bir sınıf:

public static class Person { 
    public Wrapper<String> name; 
    public Wrapper<Integer> age; 
} 

Uygulanması ContextualDeserializerPerson sınıfındaki her alan için, alanın jenerik tip parametrelerini temel alan spesifik bir desterizer oluşturmamızı sağlar. Bu, adı bir dizge olarak ve dizinin bir tamsayı olarak serileştirilmesini sağlar.

tam deserializer şuna benzer: Bu Jackson tarafından ilk çağrılacak olarak

public static class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer { 
    private JavaType valueType; 

    @Override 
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { 
     JavaType wrapperType = property.getType(); 
     JavaType valueType = wrapperType.containedType(0); 
     WrapperDeserializer deserializer = new WrapperDeserializer(); 
     deserializer.valueType = valueType; 
     return deserializer; 
    } 

    @Override 
    public Wrapper<?> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException { 
     Wrapper<?> wrapper = new Wrapper<>(); 
     wrapper.value = ctxt.readValue(parser, valueType); 
     return wrapper; 
    } 
} 

O burada ilk createContextual bakmak en iyisidir. Alanın türünü BeanProperty (ör. Wrapper<String>) dışında okuyoruz ve sonra ilk jenerik tip parametresini (ör. String) ayıklıyoruz. Daha sonra yeni bir desperizatör oluştururuz ve iç tipini valueType olarak saklarız. deserialize kez

bu yeni oluşturulan deserializer üzerine denir, biz sadece ziyade bütün sarıcı türü olarak daha iç türü olarak değerini serisini Jackson sormak ve Serileştirilmemiş değerini içeren yeni Wrapper döndürebilir.O zaman yukarıdan örnek JSON serisini denerseniz

SimpleModule module = new SimpleModule() 
     .addDeserializer(Wrapper.class, new WrapperDeserializer()); 

ObjectMapper objectMapper = new ObjectMapper(); 
objectMapper.registerModule(module); 

görebiliriz: Bu özel deserializer kayıt için

, biz o zaman bu modülü bunu içeren bir modül oluşturmak gerekir ve kayıt o beklendiği gibi çalıştığını:

deserializers Jackson documentation nasıl çalıştığı içeriksel hakkında biraz daha detay bulunmaktadır
Person person = objectMapper.readValue(json, Person.class); 
System.out.println(person.name.value); // prints Alice 
System.out.println(person.age.value); // prints 37 

.

+1

Bu gönderi için teşekkür ederiz. İstediğim şeyi elde etmek inanılmaz derecede yardımcı oldu. Google'dan başka birinin gelmesi durumunda kök değerleri ile çalışan birkaç değişiklik yaptım. https://gist.github.com/darylteo/a7be65b539c0d8d3ca0de94d96763f33 –

+1

Yardımına gerçekten yardımcı oldum Bağlamsal türün kendisi jenerik olabilir, bu durumda özellik boş olacaktır, ctxt.getContextualType –

1

hedef kendisi olduğunu sen DeserializationContext gelen valueTtype almak gerekir için genel tür sonra mülkiyet null olacaktır ise:

@Override 
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { 
    if (property == null) { // context is generic 
     JMapToListParser parser = new JMapToListParser(); 
     parser.valueType = ctxt.getContextualType().containedType(0); 
     return parser; 
    } else { // property is generic 
     JavaType wrapperType = property.getType(); 
     JavaType valueType = wrapperType.containedType(0); 
     JMapToListParser parser = new JMapToListParser(); 
     parser.valueType = valueType; 
     return parser; 
    } 
} 
+0

kullanarak JsonDeserializer'ı oluşturmanız gerekir. kabul edilen cevap üzerinde bir NPE alıyorum, bu çözüm muhtemelen ihtiyacınız olan şeydir. Teşekkür ederim - Beni ne kadar zaman kurtardığının hiçbir fikrim yok. – Martin

İlgili konular