vendredi 7 février 2020

In Reflection, Method object's parameter class doesn't match argument class?

I'm working on a Reflection project that will have some functionality similar to JUnit, but I'm running into an obstacle.

I've written a Car class that allows me to run the following program:

Car a = new Car("Model T");
Cab b = new Car("Tesla");
a.honk; //prints "beep beep" 
a.crash(b); //prints "Model T crashes into Tesla"

All the stuff above works fine.

Now, I want to be able to run the same tests of the Car class via some functionality testing methods I've written using reflection. I have written methods that invoke constructors and called methods as requested. I have 1 method called "makeObject" that finds a constructor in the requested class and returns the constructed object. I also have a method called testMethod that should have an object run one of its non-static methods. These are both working GREAT... until I get to a situation that requires object assignment/casting.

//API
Object makeObject(String nameOfClass, Object[] argumentsForConstructor)
void testMethod(Object objectToPerformMethod, String methodToCall, Object[] argumentsForMethod)

Here's an example of how it would be used to run the same test program that I included at the start of my post:

//Find the Car class and invoke the constructor that receives a String parameter.
Object o1 = makeObject("Car", new Object[]{"Model T"});      //this works fine.
Object o2 = makeObject("Car", new Object[]{"Tesla"});        //this works fine.

//Invoke the honk method of object o1.  No parameters required.
//The result is that "beep beep" is printed.
testMethod(o1, "honk", new Object[] {});                     //this works fine.

//Invoke the crash(Car c) method of o1 using o2 as the parameter.
//This should print "Model T crashes into Tesla".
testMethod(o1, "crash", new Object[] {o2});                 //this doesn't work.

This last test is where my problem is coming into play. testMethod appears to be unable to find a version of the crash method that matches my request. The crash method is supposed to receive a Car object, which it does, even though o2 is an Object reference.

It is able to identify all the methods of o1 and finds the one called "crash". It sees then recognizes that the crash method requires a Car object. It also sees that I've passed in object o2 and recognizes that o2 is, in fact, a Car object. BUT, it strangely doesn't recognize that the argument and parameter are compatible types. And it refuses to run the method.

I realize that o1 and o2 are object references, but when I getClass() on o2 and getParameterTypes() on the crash method object the returned classes are identical.

Class objectClass  = o2.getClass();
Class[] paramTypes = method.getParameterTypes(); //where method is the Method object for crash
Class paramClass = paramTypes[0]; //there was only 1 paramType.  I confirmed that it's the Car class.
System.out.println(objectClass); //prints class Car
System.out.println(paramClass); //prints class Car
if (paramClass.isAssignableFrom(objectClass)) {      //always returns false?
    System.out.println("I want to run this method because the signature matches.");
    // o1 should invoke method using FutureTask
}

But the isAssignableFrom() always returns false, even though they are both Car classes. Any idea what might be the problem? I've inspected the both of the Class objects (objectClass and paramClass) and they appear to be identical, even down to the paths in the ClassLoaders.

Instead of isAssignableFrom(), I've also tried isInstance, but it didn't work either:

if (paramClass.isInstance(o2)) {      //also always returns false




Aucun commentaire:

Enregistrer un commentaire