[ACCEPTED]-can I reflectively instantiate a generic type in java?-reflection

Accepted answer
Score: 11

The generic information is lost in runtime. There 5 is no runtime equivalent of a Creator<String>.class. You 4 could create a type between Creator and 3 StringCreator which fixes the generic type:

public interface Creator<T> {
        T create();
}
public interface StringCreator extends Creator<String> { }
public class StringCreatorImpl implements StringCreator  {
        public String create() { return new String(); }
}
public class FancyStringCreator implements StringCreator  {
        public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
        Class<?> someClass = Class.forName(args[0]);
        Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class);
        Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
        Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}

But 2 of course you lose a bit of flexibility, because 1 you cannot use the following creator class:

public class AnotherCreator implements Creator<String> {
    public String create() { return ""; }
}
Score: 5

This will do what you are trying to do while 11 providing type safety. There's no way to 10 avoid an unchecked warning, but the type 9 checking done here justifies its suppression.

  public static void main(String[] args)
    throws Exception
  {
    Class<? extends Creator<String>> clz = load(argv[0], String.class);
    Constructor<? extends Creator<String>> ctor = clz.getConstructor();
    Creator<String> creator = ctor.newInstance();
    System.out.println(creator.create());
  }

  public static <T> Class<? extends Creator<T>> load(String fqcn, Class<T> type)
    throws ClassNotFoundException
  {
    Class<?> any = Class.forName(fqcn);
    for (Class<?> clz = any; clz != null; clz = clz.getSuperclass()) {
      for (Object ifc : clz.getGenericInterfaces()) {
        if (ifc instanceof ParameterizedType) {
          ParameterizedType pType = (ParameterizedType) ifc;
          if (Creator.class.equals(pType.getRawType())) {
            if (!pType.getActualTypeArguments()[0].equals(type))
              throw new ClassCastException("Class implements " + pType);
            /* We've done the necessary checks to show that this is safe. */
            @SuppressWarnings("unchecked")
            Class<? extends Creator<T>> creator = (Class<? extends Creator<T>>) any;
            return creator;
          }
        }
      }
    }
    throw new ClassCastException(fqcn + " does not implement Creator<String>");
  }

The 8 main restriction you have to adhere to is 7 that a class in the hierarchy must specify 6 the type parameter. For example class MyCreator implements Creator<String>. You can't 5 use it with class GenericCreator<T> implements Creator<T>.

It doesn't currently handle 4 the valid case where you create a new interface 3 interface StringCreatorIfc extends Creator<String>, and have a class implement that. It could 2 be enhanced to do that, but I'll leave that 1 as an exercise for those inclined.

Score: 3

You don't need that line. Nor do you need 4 the constructor as you're just using the 3 default one. Just instantiate the class 2 directly:

public static void main(String[] args) throws Exception {
        Class<?> someClass = Class.forName(args[0]);
        Creator<String> creator = (Creator<String>) someClass.newInstance();
}

If you insist, you'll only be able 1 to get halfway there:

public static void main(String[] args) throws Exception {
    Class<?> someClass = Class.forName(args[0]);
    Class<? extends Creator> creatorClass = someClass.asSubclass(Creator.class);
    Constructor<? extends Creator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
    Creator<String> creator = (Creator<String>) creatorCtor.newInstance((Object[]) null);
}

More Related questions