1

I wrote generic method which returns list of some objects, for example Orders. My question is why in second, non-generic method it returns correct list of Orders and the first method (generic) returns list of linkedHashMaps instead of Orders?

Generic:

 private <T> List<T> mapObjectsToList(String objectsListInJson) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    TypeReference<List<T>> mapType = new TypeReference<List<T>>() {
    };
    return objectMapper.readValue(objectsListInJson, mapType);
}

Non-generic:

private List<Order> mapObjectsToList(String objectsListInJson) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    TypeReference<List<Order>> mapType = new TypeReference<List<Order>>() {
    };
    return objectMapper.readValue(objectsListInJson, mapType);
}

Generic method returns that: LinkedHashMap

Ukis
  • 13
  • 4
  • 1
    You should take a look at some of these Q&As: https://stackoverflow.com/q/6062011/2891664 https://stackoverflow.com/q/6846244/2891664. This probably has to do with the use of the type variable in `TypeReference>`. – Radiodef Jun 08 '17 at 00:19

3 Answers3

0

Because in the non generic method you have explicitly said that you are adding Order.

And in the generic one you are sending back objects, which are essentialy of type Order.

In any case both of it will return List.

Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108
0

The problem is that you can't pass a type parameter by simply declaring it.

Type parameters are erased so within your generic function <T> just not exist so even the type reference can't convey such info.

You should build the type reference with the actual reference of the class and pass a type reference to the method like this:

List<Composite> out = mapObjectsToList(in, new TypeReference<List<Composite>>() {});

or ...

Knowing in advance that you are deserializing exactly List of T you can play with TypeFactory

private static <T> List<T> mapObjectsToList(Reader objectsListInJson, Class<T> clazz) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    CollectionLikeType typeref = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, clazz);
    return objectMapper.readValue(objectsListInJson, typeref);
}

And call it like this:

List<Composite> out = mapObjectsToList(in, Composite.class);
minus
  • 2,646
  • 15
  • 18
0

The problem is that the generic type variable T is not bound to any concrete type, so the compiler sees it as Object. So:

TypeReference<List<T>> mapType = new TypeReference<List<T>>() {};

is actually:

TypeReference<List<Object>> mapType = new TypeReference<List<Object>>() {};

And when the ObjectMapper can't gather info about the concrete type of the object to deserialize, it defaults to LinkedHashMap.

If you want to be able to deserialize to a generic type at runtime, you should pass the TypeReference type token as an argument to your mapObjectsToList method:

// Make this a singleton, i.e. don't create a new instance on every call!
ObjectMapper objectMapper = new ObjectMapper();

private <T> List<T> mapObjectsToList(
        String objectsListInJson, 
        TypeReference<List<T>> mapType) throws IOException {

    return objectMapper.readValue(objectsListInJson, mapType);
}

And then use the above method as follows:

List<Order> orders = mapObjectsToList(
    stringWithTheJSON, 
    new TypeReference<List<Order>> {});

On a side note, I've moved the ObjectMapper objectMapper = new ObjectMapper() statement outside the method. There should be only one ObjectMapper instance in the whole application, unless you require different configuration for serializing/deserializing.

fps
  • 33,623
  • 8
  • 55
  • 110
  • Ok, so what is the difference when I do method private List mapObjectsToList(String objectsListInJson) and private List mapObjectsToList(String objectsListInJson) ? – Ukis Jun 08 '17 at 19:21
  • Thanks for answer! So what are generics for, if we can everywhere do it by using Object instead? – Ukis Jun 08 '17 at 19:28
  • It's new TypeReference(), not in that example :). But T is converted to Object anyway, so is there any difference in this case? – Ukis Jun 08 '17 at 19:48
  • Ok, so TypeReference> as argument is converted to Typereference> but method returned type (private List mapObjectsToList) is converted to Object or Order as well? – Ukis Jun 08 '17 at 20:01
  • 1
    Ok, I understand now. Thank you very much. :) – Ukis Jun 08 '17 at 20:10