Search code examples
javatypespredicate

Check type of Predicate generic


I'm having 2 classes, their internals doesn't matter at all.

class ClassA {
    //... 
}

class ClassB {
    //...
}

And I'm having 2 predicates that use those classes, let's say they look like this

private Predicate<ClassA> classAPredicate() {
    return Objects::nonNull;
}

private Predicate<ClassB> classBPredicate() {
    return Objects::nonNull;
}

Now, I'm having generic method in external library that is already beeing used by many users and unfortunatelly, it has pretty generic input parameter which is Object which in 90% of cases is Predicate.

What I need to do, is to extend this method functionality by checking type of passed Predicate and based on that, perform some operations.

public void test(Object obj) {
    Predicate predicate = (Predicate)obj;
    if(predicate.getClass().isAssignableFrom(ClassA.class)) {
        System.out.println(predicate.test(new ClassA()));
        // logic specific to Predicate<ClassA>
    } else {
        System.out.println(predicate.test(new ClassB()));
        // logic specific to Predicate<ClassB>
    }
}

But, during tests I'm passing both Predicates and it fails with Exception in thread "main" java.lang.ClassCastException:

 test(classAPredicate());
 test(classBPredicate());

I've been debugging and isAssignableFrom() is always returning false so the error is obvious here. I'm not sure if that is the right approach, but I didn't came up with anything else yet. Is there any way to check what is the type of that Predicate?

I know that what I'm trying to implement isn't ideal, but that is current requirement...


Solution

  • In the above, the predicate class is not assignable from Class A.

    if(predicate.getClass().isAssignableFrom(ClassA.class))
    

    This causes the else condition to run which passes an instance of B to the Predicate for type A which causes a cast exception. Due to type erasure, it will not be easy to resolve whether an instance of A or B should be passed to the predicate. 3 options are:

    1. Try each input type until one doesn't throw a ClassCastException.
    2. Handle the expected behavior in a new method instead of the existing test function.
    3. Define a more specific interface than Predicate which also has a method to get the type the predicate tests and use the test type in the condition instead. Ex:
    public interface TypedPredicate<T> extends Predicate<T> { Class<T> getTestType(); }