Constructor not found by reflection when argument is a subclasses of the constructor's argument declared type

Viewed 236

I'm using reflection to instanciate classes for a specific need.

Current code is like :

public final <T> T instanciate(Class<? extends T> a_clazz, Object... args) {

    // Other stuff when no arg...

    Class<?>[] l_argsClasses = getClassesFromObjects(args);
    Constructor<?> constructor = a_clazz.getConstructor(l_argsClasses);
    constructor.newInstance(args)
}

Unfortunately, i read that it will not work when given parameters are not exactly the same type in the constructor declaration.

So when i give a subclass, the constructor is not found and I get a NoSuchMethodException.

It seems that there is no mechanism to handle polymorphism here.

Example :

public class A {

}

public class B extends A {

}

public class Foo extends A {
    public Foo(A a) {

    }
}

Will work :

instanciate(Foo.class, new A());  // because Foo(A a)

Won't work :

instanciate(Foo.class, new B());  // because Foo(B b) does't exists

Do you have any solution to handle this issue ?

Thank you

2 Answers

The java.beans package has the classes Statement and Expression which can perform the necessary lookup with sub-type rules:

Expression e = new Expression(Foo.class, "new", new Object[]{ new B() });
Foo foo = (Foo)e.getValue();

The documentation of the execute method describes the special pseudo method name "new" for invoking a constructor.

The solution I have chosen to use is the methods provided by apache.commons.lang.reflect

It provides two different versions :

  • One need to match the parameters types exactly : invokeExactConstructor()
  • One match the parameter types by assignment compatibility : invokeConstructor()

I have tested briefly and it's working. So i'm using it.

Here is the result :

public final <T> T instanciate(Class<? extends T> clazz, Object... args) {
    try {
        return clazz.cast(ConstructorUtils.invokeConstructor(clazz, args));
    } catch (Exception e) {
        throw new RuntimeException("Failed to instanciate Object", e);
    }
}

Pretty simpler code which is nice

Related