0

I've been trying all kinds of solutions to get this working. But without success.

I have a few classes like this

class Level1<T> {

    public Level2<T> l2;
}

class Level2<T> {

    public Level3<T> l3;
}

class Level3<T> {

    public List<T> objectsList;
}

T in this case can be any object, and should be possible to be resolved during runtime.

My JSON looks like this:

{
    "Level1": {
        "Level2": {
            "Level3": {
                "genericObject": [
                    { 
                      "attribute1": ..., 
                      "attribute2": ...
                    },
                    { 
                      "attribute1": ..., 
                      "attribute2": ...
                    } 
                ]
            }
        }
    }
}

The JSON property "genericObject" changes its name and attributes depending of which kind of object I'm receiving.

I've tried defining in my ObjectMapper like this, in which I pass a Class object to my function (genericObjectClass):

JavaType javaType = TypeFactory.defaultInstance().constructParametricType(ArrayList.class, List.class, genericObjectClass);
javaType = TypeFactory.defaultInstance().constructParametricType(Level3.class, javaType);
javaType = TypeFactory.defaultInstance().constructParametricType(Level2.class, javaType);
javaType = TypeFactory.defaultInstance().constructParametricType(Level1.class, javaType);

Level1<genericObject> l1 = objectMapper.readValue(jsonString, javaType);

Tried solutions:

(de)serialising Nested Generics in Jackson

How to use Jackson with Generics

Is Jackson really unable to deserialize json into a generic type?

alexluz
  • 95
  • 2
  • 7

1 Answers1

1

There are several things that you need to change

  1. Level1 object is not the root object, but a field. If you don't want to create one more wrapper object, use UNWRAP_ROOT_VALUE

    mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    
  2. You don't need to constructParametricType for the whole object hierarchy, just construct it for top class in the chain

    constructParametricType(Level1.class, genericObjectClass);
    
  3. Your json fields don't map to pojo fields. So you need to annotate your POJO fields with @JsonProperty("Level2") @JsonProperty("genericObject") and so on.

So your deserialization code should look like

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);

JavaType javaType = TypeFactory.defaultInstance()
         .constructParametricType(Level1.class, c);

mapper.readValue(json, javaType);

And classes look like

class Level1<T> {
    @JsonProperty("Level2")
    public Level2<T> l2;
}
class Level2<T> {
    @JsonProperty("Level3")
    public Level3<T> l3;
}
class Level3<T> {
    @JsonProperty("genericObject")
    public List<T> objectsList;
}

And here is full working gist demo

varren
  • 14,551
  • 2
  • 41
  • 72
  • Thank you for your answer. But what I meant by "genericObject", is that the @JsonProperty will change during runtime. Therefore I couldn't do something like @JsonProperty("genericObject"), because it could be many kinds of POJOs. I'll try the TypeFactory the way you suggested, to see if it works. Thank you! – alexluz Oct 16 '17 at 22:07
  • @alexluz if you will have different field names in your json, it is fine and probably you don't need to use `@JsonProperty` for different POJOs . But json field names need to be exactly the same as in the POJO you want to deserialize. Generic or not, they need to match. If you can't ensure that, then you have to write custom deserializer. But, after your comment, it looks like you can just ignore this part of my answer. – varren Oct 16 '17 at 22:16