paul paul - 22 days ago 7
Scala Question

Jackson deserialize with Generics

I´m trying to deserialize a json into scala class, that contains a Collection of types Aclass,Bclass or Cclass

class Results[M](results:util.ArrayList[M]) {

def getResults:util.ArrayList[M]=results

def this() {
this(new util.ArrayList())
}
}


The Json looks like:

{ "results":[{"a":1},{"a":1}]}


or

{ "results":[{"b":1},{"b":1}]}


or

{ "results":[{"b":1},{"b":1}]}


Here my object mapper

val mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)


And here how I deserialize a json of class type Aclass

val results = mapper.readValue(json, classOf[Results[Aclass]])


The problem is that results, return a ArrayList where every element instead to be an instance of Aclass, is a
LinkedHashMap
.

If I change the code instead to use generic I make it explicit in the type

class Results[Aclass](results:util.ArrayList[Aclass]) {

def getResults:util.ArrayList[Aclass]=results

def this() {
this(new util.ArrayList())
}
}


It works and return an class with result of array of Aclass elements.

What I´m doing wrong here?. I think it´s a bug in the library

Regards.

Answer

The reason is that java.lang.Class does not hold information about generic parameters. The value of classOf[Result[Aclass]] is java.lang.Class. It does not have information about the type parameter Aclass. It represents only the Results class.

The mapper does what you ask for: gives you Results of whatever and the best whatever for it is a map.

To solve it, use readValue method that takes JavaType instead. JavaType can be created using TypeFactory:

val results:Results[Aclass] = mapper.readValue(json, mapper.getTypeFactory()
        .constructParametricType(classOf[Results[_]], classOf[Aclass]))
Comments