Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Jackson Deserializer Getting Access to Current Field Class

I'm trying to write a custom deserializer for Jackson and I want to make it generic (generic in the sense of working on any type, not as in "generics").

However I cannot seem to figure out how to get a handle to the type of the field being deserialized.

Eg, I'm looking to do something like the following:

@Override
public MyObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {

         Class c = <get type of current field>
         // do something with that type
         return new SubclassOfC(somedata based on c);
}

It's specifically the get type of current field part that I have struggled with.

Edit: It is the type of the java field I am interested in.

like image 668
sksamuel Avatar asked Jan 20 '12 15:01

sksamuel


3 Answers

You don't -- deserializers are registered by type, so you need to construct deserializer to know what type it is expected to deserialize.

If you do want to registered a generic deserializer, you can however make things more dynamic by implementing ContextualDeserializer. Its createContextual() method is called with BeanProperty argument, and you can check things like name of the property (which may be null, in case of root values which are not referenced by a property) and type (which is the declared type). This method can then return a new instance (do NOT modify original deserializer, since it is shared by all properties), configured with all extra information you need.

like image 172
StaxMan Avatar answered Oct 14 '22 06:10

StaxMan


I have solved my particular problem by adding an implementation of Deserializers to the ObjectMapper. Eg

   Deserializers d = new Deserializers.Base() {

   @Override
   public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property)
                  throws JsonMappingException {
                if (property.getType().getContentType() != null)
                    return new EnumDeserializer(property.getType().getContentType().getRawClass());
                return new EnumDeserializer(property.getType().getRawClass());
            }

        };
        mapper.setDeserializerProvider(mapper.getDeserializerProvider().withAdditionalDeserializers(d));

This will return my custom EnumDeserializer instantiated for each separate Enum type.

like image 27
sksamuel Avatar answered Oct 14 '22 07:10

sksamuel


I solved it like this.

Get current field java type...

@Override
public Enum deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException, JsonProcessingException {
    System.out.println("EnumDeserializer ....");
    Field field = findField(jsonparser.getCurrentName(), jsonparser.getCurrentValue().getClass());
    Class<?> javaType = field.getType();
    return null;
}

public Field findField(String name, Class<?> c) {
    for (; c != null; c = c.getSuperclass()) {
        for (Field field : c.getDeclaredFields()) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            if (field.getName().equals(name)) {
                return field;
            }
        }
    }
    return null;
}

like image 1
user5944283 Avatar answered Oct 14 '22 06:10

user5944283