vendredi 27 mars 2015

Class.getDeclaredConstructor doesn't retrieve compatible argument supertype constructors

In my program, I register JComponent classes to my classes that handle them for my purposes (converting their values to setting entries). It looks like this:



InputHandlers.register(InputJTextField.class, javax.swing.JPasswordField.class);
InputHandlers.register(InputJTextField.class, JTextField.class);
InputHandlers.register(InputJCheckBox.class, JCheckBox.class);
...


I save these registered values to Map and retrieve them later. But for the example above, I have a problem: though javax.swing.JPasswordField.class is subtype of JTextField.class, the Class.getDeclaredConstructor doesn't see it that way.


I made a general example to make this question easier to answer. Consider following classes:



class A {
private final B b;
public A(B b) {
this.b = b;
}
}
class B {}
class C extends B {}


Imagine you want to do this:



A.class.getDeclaredConstructor(C.class);


It will throw java.lang.NoSuchMethodException even though C is subtype of B. Here's the full code:



/**
* Test how Class.getDeclaredConstructor seeks for constructors.
* @author Jakub
*/
public class Constructors {
public static class A {
private final B b;
public A(B b) {
this.b = b;
}
}
public static class B {}
public static class C extends B {}
public static void main(String[] args) //throws Exception
{
/** TRY USING REFLECTION **/
//Make A from B
tryAfromParam(new B());
//Make A from C that is cast to B
tryAfromParam((B)new C());
//Make A from C without casting
tryAfromParam(new C());
}
public static A tryAfromParam(Object param) {
System.out.println("Try to make A from "+param.getClass()+" using A.class.getConstructor(...)");
try {
A a = AfromParam(param);
System.out.println(" Sucess :)");
return a;
} catch (Exception ex) {
System.out.println(" CONSTRUCTOR FAILED: "+ex);
}
return null;
}
public static A AfromParam(Object param) throws Exception {
//Fetch the A's class instance
Class cls = A.class;
//Define constructor parameters
Class[] arguments = new Class[] {
param.getClass()
};
//Try to get the constructor
Constructor<A> c = cls.getConstructor(arguments);
//Try to instantiate A
A a = c.newInstance(param);
//Return result
return a;
}
}


And the question is: How to find constructor compatible with arguments or any of their super types? Note that new A(new C()) is valid, so the reflection should work the same way - generally I want to call the constructor the way Java would call it.






Aucun commentaire:

Enregistrer un commentaire