Question

I’m using JBoss 7.1.3 with Java 6. I’m having trouble trying to figure out what I need to substitute for “???” in the below code to get my method to work properly. What I want is to instantiate an instance of my “T” class, invoking the generic constructor each time I instantiate the class. Below is the method …

public class MyClass<T extends AbstractModel>
{

    public void myMethod()
    {
        …
        final HashMap<String, String> data = new HashMap<String, String>();
        final T item = getInstance(???, data);

    }


    private T getInstance(final Class<T> class1,
                  final HashMap<String, String> data)
    {
        T retObj = null;
        try
        {
            Constructor ct = class1.getDeclaredConstructor(HashMap.class);
            Object[] argList = new Object[1];
            argList[0] = data;
            retObj = (T) ct.newInstance(argList);
        } catch (Exception e)
        {
        }   // try
        return retObj;
    }   // getInstance

here is the constructor for my abstract model class …

public abstract class AbstractDIDOModel 
{

    protected HashMap<String, String> data;

    AbstractModel(final HashMap<String, String> data) 
    { 
        this.data = data;
    }
Was it helpful?

Solution 2

You can use a trick if your class has the type parameters set, because in that case the type information is available at runtime. You can capture it and store it in a member field. Then you can use that field as the class inside your generic construction method.

public abstract class AbstractDIDOModel<T> 
{

 private Class<?> persistentClass = (Class<?>) ((ParameterizedType)  this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

 private T getInstance(final HashMap<String, String> data)
    {
        T retObj = null;
        try
        {
            Constructor ct = persistentClass.getDeclaredConstructor(HashMap.class);
            Object[] argList = new Object[1];
            argList[0] = data;
            retObj = (T) ct.newInstance(argList);
        } catch (Exception e)
        {
        }   // try
        return retObj;
    }

Finally, declare your concrete classes as such:

public class MyClass<T extends AbstractModel>
{
   ....
}

OTHER TIPS

MyClass should have the Class<T> passed in:

public class MyClass<T extends AbstractModel>
{
    private final Class<T> type;

    public MyClass(Class<T> type) { this.type = type; }

    public void myMethod()
    {
        …
        final HashMap<String, String> data = new HashMap<String, String>();
        final T item = getInstance(type, data);

    }

Due to Type Erasure, no information of T exists at runtime and so you cannot obtain the type it refers to in most cases.

Note also that Constructor is typed, so you can replace this:

Constructor ct = class1.getDeclaredConstructor(HashMap.class);
//...
retObj = (T) ct.newInstance(argList);

With this:

Constructor<T> ct = class1.getDeclaredConstructor(HashMap.class);
//...
retObj = ct.newInstance(argList);

If your goal is to use Class<T> as a Factory, I would take a different approach however. I would just accept a Factory<T>, where Factory<T> is an interface:

public interface Factory<T extends AbstractModel> {
   T create(HashMap<String, String> data);
}

Then creators of MyClass<T> can just implement this simply, without having to resort to reflection:

Factory<ConcreteModel> factory = new Factory<ConcreteModel>() {
   @Override
   public ConcreteModel create(HashMap<String, String> data) {
        return new ConcreteModel(data);
   }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top