Giovanni Lovato
Giovanni Lovato

Reputation: 2273

How to properly cast expected generic-typed arguments?

I'm lost in generics (Java). The real scenario involves JPA and CriteriaBuilder's

<Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x, Y y);

but I simplified the same case in the following class:

public class GenericsTest {

    public class Bean<T> {

    };

    public <T extends Comparable<T>> T targetMethod(Bean<T> bean, T object) {
        return object;
    }

    @SuppressWarnings("unchecked")
    public <T> T castToGeneric(Bean<T> bean, Object object) {
        return (T) object;
    }

    @SuppressWarnings("unchecked")
    public <T> void understandGenerics(Bean<T> bean, Object object) {
        Bean<Comparable<T>> beanOfComparable = (Bean<Comparable<T>>) bean;
        Comparable<T> comparableObject = this.castToGeneric(beanOfComparable, object);
        this.targetMethod(beanOfComparable, comparableObject);
    }

}

The invocation targetMethod(beanOfComparable, comparableObject) in the last line generates

The method targetMethod(Bean<T>, T) in the type GenericsTest is not applicable for the arguments (Bean<Comparable<T>>, Comparable<T>)

and I don't understand where the problem is, since T in targetMethod must be a Comparable<T>, that is the type I'm giving it.

Upvotes: 1

Views: 55

Answers (1)

Andrew Williamson
Andrew Williamson

Reputation: 8691

The constraint on your targetMethod is the thing that is causing it to fail:

public <T extends Comparable<T>> T targetMethod(Bean<T> bean, T object)

When you pass in the variables (Bean<Comparable<X>>, Comparable<X>), you are implying that the generic parameter T is Comparable<X> (I'm using X here to distinguish between the generic from targetMethod and the generic from understandGenerics).

The constraint on targetMethod says that when your T is Comparable<X>, then T must extend Comparable<Comparable<X>>. Of course, this is not going to be satisfied.

I think what you intend to do would be better accomplished like so:

@SuppressWarnings("unchecked")
public <T extends Comparable<T>> void understandGenerics(Bean<T> bean, Object object) {
    T comparable = (T) object;
    targetMethod(bean, comparable);
}

Notice with the added constraint that T must be comparable, the whole process is much simpler. In general, it pays to limit unchecked code as much as possible, and put constraints on the types instead.

Upvotes: 2

Related Questions