Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream collect with Generic type

Tags:

java

java-8

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.

like image 262
paul Avatar asked Oct 27 '16 14:10

paul


People also ask

Which is faster stream or collection?

For this particular test, streams are about twice as slow as collections, and parallelism doesn't help (or either I'm using it the wrong way?).

How do you collect streams into strings?

We can use Stream collect() function to perform a mutable reduction operation and concatenate the list elements. The supplier function is returning a new StringBuilder object in every call. The accumulator function is appending the list string element to the StringBuilder instance.

What is collect method in Stream API?

collect() Method. Stream. collect() is one of the Java 8's Stream API's terminal methods. It allows us to perform mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in a Stream instance.


1 Answers

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.

like image 198
Marko Topolnik Avatar answered Sep 28 '22 08:09

Marko Topolnik