Skip to content

Java Reflection: Invoke Constructor Issue

| java |

Let’s imagine we have the next classes:

package test.clazz;

public class First {
 private FirstArg arg;

 public FirstArg getArg() {
  return arg;
 }

 public First (FirstArg arg) {
  this.arg = arg;
  System.out.println("First() - constructor");
 }
}

public class FirstArg {
 public FirstArg() {
  System.out.println("FirstArg.FirstArg()");
 }
}

public class SecondArg  extends FirstArg{
 public SecondArg() {
  System.out.println("SecondArg.SecondArg()");
 }
}

And we can easily instantiate First class with FirstArg or SecondArg:

First f1Old = new First(new FirstArg());
First f2Old = new First(new SecondArg());
System.out.println(f1Old.getArg().getClass());
System.out.println(f2Old.getArg().getClass());

We’ll get the next output:

FirstArg.FirstArg()
First() - constructor
FirstArg.FirstArg()
SecondArg.SecondArg()
First() - constructor
class test.clazz.FirstArg
class test.clazz.SecondArg

Now, we have to instantiate First class with FirstArg or SecondArg, but via Java reflection:

public final class ConstructionUtil {
 public static Object instantiateClassOld(String className, Object iView) {
  try {
   Class iViewClass = iView.getClass();
   Class clazz = Class.forName(className);

   Constructor ctor = clazz.getDeclaredConstructor(iViewClass);
   ctor.setAccessible(true);
   return ctor.newInstance(iView);
  } catch (Exception e) {
   e.printStackTrace();
   return null;
  }
 }
} 

Check reflection based class instantiation:

Object cls = instantiateClassOld("test.clazz.First", new FirstArg());
First f1 = (First) cls;
Object cls2 = instantiateClassOld("test.clazz.First", new SecondArg());
First f2 = (First) cls2;
System.out.println(f1.getArg().getClass());
System.out.println(f2.getArg().getClass());

And we’ll get Exception:

FirstArg.FirstArg()
First() - constructor
FirstArg.FirstArg()
SecondArg.SecondArg()
java.lang.NoSuchMethodException: test.clazz.First.(test.clazz.SecondArg)
 at java.lang.Class.getConstructor0(Unknown Source)
 at java.lang.Class.getDeclaredConstructor(Unknown Source)
 at test.ConstructionUtil.instantiateClassOld(ConstructionUtil.java:63)
 at test.ConstructionUtil.main(ConstructionUtil.java:22)
 ```

Reflection mechanism can't find `First(SecondArg arg)` constructor.
We have to patch `instantiateClassOld` method like this:

```java
public final class ConstructionUtil {
 public static Object instantiateClassNew(String className, Object iView) {
  try {
   Class iViewClass = iView.getClass();
   Class clazz = Class.forName(className);
   try {
    Constructor ctor = clazz.getDeclaredConstructor(iViewClass);
    ctor.setAccessible(true);
    return ctor.newInstance(iView);

   } catch (NoSuchMethodException e) {
    Constructor[] constructors = clazz.getDeclaredConstructors();
    for (Constructor c : constructors) {
     if (c.getParameterTypes().length > 1)
      continue;
     Class type = c.getParameterTypes()[0];
     if (type.isAssignableFrom(iView.getClass())) {
      return c.newInstance(type.cast(iView));
     }

    }
   }
   return null;

  } catch (Exception e) {
   e.printStackTrace();
   return null;
  }
 }
} 

And run it again:

Object cls = instantiateClassNew("test.clazz.First",new FirstArg());
First f1 = (First) cls;
Object cls2 = instantiateClassNew("test.clazz.First",new SecondArg());
First f2 = (First) cls2;
System.out.println(f1.getArg().getClass());
System.out.println(f2.getArg().getClass());

Output:

FirstArg.FirstArg()
First() - constructor
FirstArg.FirstArg()
SecondArg.SecondArg()
First() - constructor
class test.clazz.FirstArg
class test.clazz.SecondArg

We should be careful when invoke methods via reflection with polymorphic arguments.