简体   繁体   中英

Detecting Class object equivalence for classes loaded by different ClassLoaders

My Task is to write a unit test for a method findSubClassImplementation that returns an instance for a given Class object. The method signature looks like this:

public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception 

Internally the method checks wether the supplied Class object belongs to a set of known classes and then returns an instance of that class:

if (Subclass.class.equals(cls)) 
        return (T) new Subclass(args);

If the class is not known, an Exception is thrown. This code is given

I tried to load all Classes inheriting from SuperClass via Reflection and then pass them as argument to findSubClassImplementation :

Set<Class<? extends SuperClass>> subTypesOf = reflections.getSubTypesOf(SuperClass.class);
Class<? extends SuperClass> clazz = subTypesOf.iterator().next();
SuperClass instance = findSubClassImplementation(clazz);

I then use a Debugger to step into the method, and I can see the line of code where

if (Subclass.class.equals(cls)) 

returns false, although cls = Subclass.class

I assume what happens is this: Class does not implement equals, thus equals of Object is used, that compares with "==". As reflection uses a different ClassLoader than is used in findSubClassImplementation the two class Objects are different. Is this assumption correct?

Is it possible to get the other Class object for a class that I have loaded with Reflection? Do you have another idea how to deal with this problem?

ANSWER:

Turns out I am not very good at reading: The hirarchy is in 3 levels: SuperClass --> IntermediateAbstractClass--> Subclass. The comparison is always to the intermediate abstract class:

if (IntermediateAbstractClass.class.equals(cls)) return (T) new Subclass(args);

Thus my question wasn't very accurate or precise - I am sorry if you feel like I wasted your time. I'll mark Michael Wiles answer as the correct one, because his advice pushed my to discover my missunderstanding. Thank you!

Maybe you don't need to check what class is cls , since cls already contains all the information you need. Try simply with

public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
    // ... retrieve args
    final Class<?>[] constructorParamTypes = new Class<?>[args.length];
    for (int i = 0; i < args.length; i++) {
        constructorParamTypes[i] = args[i].getClass();
    }
    return cls.getConstructor(constructorParamTypes).newInstance(args);
}

Or in the Java 8 way:

public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
    // ... retrieve args
    final Class<?>[] constructorParamTypes = Arrays.stream(args).map(Object::getClass)
            .toArray(size -> new Class<?>[size]);
    return cls.getConstructor(constructorParamTypes).newInstance(args);
}

There must be something that is different about the classes...

You say that Subclass.equals(otherSubclass) returns false we need to ascertain why this is the case.

Check the name of each class for equality and then check the classloader of each class for equality.

Based on your provided code to do the reflection there is nothing here to sugggest that these classes loaded by "Reflection" are in fact loaded from different classloaders.

Furthermore try all sorts of classes, maybe there is something unique about that particular class that causes the behaviour.

One suggestion to try would be to add Integer to the subclass set and then pass in Number to the method...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM