Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson: Deserialize Object to Array with Generics

I try to write a custom JsonDeserializer, but I can't figure out how to get the Generic type information of my class.

I18NProperty.class:

public class I18NProperty<T> extends ArrayList<T> {
  public static class Content<T> {
    public Locale i18n;     
    public T val;
  }
}

My desired JSON representation looks like this ( name is an instance of I18NProperty<Content<String>> ) :

{
  "name": {
    "en": "foo",
    "jp": "bar"
  }
}

Now I tried to write a JsonDeserializer and I'm able to read the field names and values, but I can't figure out how to create an instance of the generic type (in this example String):

public static class I18NPropertyDeserializer extends StdDeserializer<I18NProperty<? extends Content<?>>> {
    protected I18NPropertyDeserializer() {
        super(I18NProperty.class);
    }

    @Override
    public I18NProperty<? extends Content<?>> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        I18NProperty<Content<?>> result = new I18NProperty<>();
        while(p.nextToken() != JsonToken.END_OBJECT) {
            String lang = p.getCurrentName();
            p.nextToken();              
-->         Object val = p.readValueAs(Object.class);

-->         I18NProperty.Content<?> c = new I18NProperty.Content<>();
            c.i18n = new Locale(lang);
-->         c.val = null;
            result.add(c);
        }
        return result;
    }
}

I marked the lines with --> where I need the Generic Type information.

This must be possible somehow, because normally I can give Jackson a arbitrary class which contains any generic fields and it will correctly deserialize it.

Thanks in advance, Benjamin

like image 607
Benjamin M Avatar asked Sep 18 '25 22:09

Benjamin M


1 Answers

your code probably won't work because

  • public static class I18NPropertyDeserializer extends StdDeserializer<I18NProperty<? extends Content<?>>>

    affirm that the private variable of Content public T val; is also Content because I18NProperty<T> and public T val means that what ever goes between <> of I18NProperty is going to be the type of val, and you don't want to have val of type Content right!! you want it to be a simple object like String, Integer, Float ...

  • public class I18NProperty<T> extends ArrayList<T>means that I18NProperty is going to extend ArrayList<String> in case val is String ArrayList<Integer> in case val is Integer ... you get it what i mean .But what you want is that I18NProperty extends Array<Content<T>>

So i made a change in the class I18NProperty<T> to make it extends ArrayList<Content> .

For the class I18NPropertyDeserialize what i have done is i made the class generic to have information about type T of public T val; and in order to instantiate the class of type T we should have object class for that type passed to the constructor I18NPropertyDeserializer(Class<T> clazz) now we are able to instantiate the object wich is going to be put in Content.val

I18NPropertyDeserialize :

public class I18NPropertyDeserializer<T> extends
        StdDeserializer<I18NProperty<T>> {

    private Class<T> clazz;

    protected I18NPropertyDeserializer(Class<T> clazz) {
        super(I18NProperty.class);
        this.clazz = clazz;
    }

    @Override
    public I18NProperty<T> deserialize(JsonParser p,
            DeserializationContext ctxt) throws IOException,
            JsonProcessingException {
        I18NProperty<T> result = new I18NProperty<>();
        while (p.nextToken() != JsonToken.END_OBJECT) {
            String lang = p.getCurrentName();
            p.nextToken();
            T val;
            val = p.readValueAs(clazz);
            I18NProperty.Content<T> c = new I18NProperty.Content<>();
            c.i18n = new Locale(lang);
            c.val = val;
            result.add(c);
        }
        return result;
    }
}

I18NProperty

public class I18NProperty<T> extends ArrayList<I18NProperty.Content<T>> {
  public static class Content<T> {
    public Locale i18n;     
    public T val;
  }}
like image 131
achabahe Avatar answered Sep 21 '25 10:09

achabahe