Stream collect with Generic type

paul :

I´m trying to use generic in a method where I deserializing a 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.

Marko Topolnik :

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.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=454949&siteId=1