paul paul - 1 month ago 15
Java Question

Stream collect with Generic type

I´m trying to use generic in a method where I deserializing an json into pojo so it could return whatever object type.

Here my code:

private Bla(List<A> as, List<B> bs)
{
this.as = as;
this.bs = bs;
}

public static Bla from(JsonObject json)
{
return new Bla(Bla.<A>load(json, As), Bla.<B>load(json, Bs));
}

private static <T> List<T> load(JsonObject jsonObject, String param)
{
return jsonObject.getJsonArray(param).stream()
.map(Bla::getItem)
.collect(Collectors.toList());
}

private static <T> T getItem(Object json)
{
try {
return mapper.readValue(json.toString(), new TypeReference<T>() {
});
} catch (IOException e) {
throw new RuntimeException("Error parsing json items", e);
}
}


The problem is that
.collect(Collectors.toList());
seems not compile cause cannot resolve the instance type.

The compilation error is:


Error:(43, 25) java: incompatible types: inference variable T has incompatible bounds
equality constraints: T
lower bounds: java.lang.Object


To avoid confusion in my example A and B are Pojos

Regards.

Answer

Let's examine this method:

private static <T> List<T> load(JsonObject jsonObject, String param)
{
    return jsonObject.getJsonArray(param).stream()
                                         .map(Bla::getItem)
                                         .collect(Collectors.toList());
}

The type of the last step, Collectors.toList() must be List<T>, but to get it the type of the previous step, Bla::getItem must be inferred as T getItem. Since getItem is a generic method, this needs a complex pattern of type constraint propagation which is apparently more than Java's type inference will handle. To solve this, help the compiler with a hint:

.map(Bla::<T>getItem)

(credit for this syntactic variant goes to user Nándor Előd Fekete).

A second issue is your getItem method:

private static <T> T getItem(Object json)
{
    return mapper.readValue(json.toString(), new TypeReference<T>() {};
}

Using TypeReference here doesn't help because T is not a concrete type. It will remain non-reified in the anonymous class that the compiler creates here, therefore Jackson will get no helpful hint from it. You can just use a simpler readValue signature that doesn't take the TypeReference.

Comments