19

My goal is to develop a class that can output an object of a specified class.

public class GetMe<T> {
    public T get() {
        Object obj = generateObject();
        return (T) obj;
    }
}

Now, I know this isn't possible due to erasure. So, we can pass in a class instance and use that to cast.

public class GetMe<T> {
    public GetMe<T>(Class<T> clazz) {
        this.clazz = clazz;
    }

    public T get() {
        Object obj = generateObject();
        return clazz.cast(obj);
    }
}

This works great! As long as the class isn't parameterized. If it is, then I've got a problem.

I'm not allowed to use List<String>.class. If I pass in a ParameterizedType (which in itself is difficult to generate), there's no cast method to use.

Is there a way out of this quagmire?

Monkey Boson
  • 1,250
  • 4
  • 11
  • 21
  • There is a way to retain generics at run time, but what is `generateObject` and why can't it return an object of type `T`? – ide Feb 12 '11 at 19:48
  • look at this examples, might help: http://serdom.eu/ser/2007/03/25/java-generics-instantiating-objects-of-type-parameter-without-using-class-literal – Yochai Timmer Feb 12 '11 at 19:59
  • Let's say `generateObject()` is a third-party deserializer. I know it's of type T, because I serialized it earlier, but the method nonetheless only returns Object. It could also be the result of a method.invoke, which only returns Object. – Monkey Boson Feb 12 '11 at 20:50
  • Yochai: Funny, I tried doing exactly what one of examples recommended ( `(Class) paramType.getActualTypeArguments()[0];` ). Unfortunately, this will often fail as there's absolutely no guarantee that a `Type` is a `Class`. For example, `List` is a `Type` that castable to `Class`, but `List` is a Type that isn't castable to `Class`. – Monkey Boson Feb 12 '11 at 20:55
  • Buy you can't create an instance of List anyway... you need to return an actual Class. (new ArrayList() ) .... List<> is an interface. You can use a constraint to guarantee it's an object: public class GetMe – Yochai Timmer Feb 13 '11 at 06:10

5 Answers5

5

I think super type tokens may solve this problem for you.

Matt McHenry
  • 20,009
  • 8
  • 65
  • 64
2

The problem with List<String> is that, because of erasure, it would at runtime indistinguishable from any other List<?>. The easiest way around this is to create a new class or interface which has the generic part "fixed", like

public interface StringList extends List<String> {
    /* nothing to see here */
}

This way you have a type token (the StringList.class object) which you can pass around at runtime and specifies exactly what you want, but without the need for generics at runtime.

Waldheinz
  • 10,399
  • 3
  • 31
  • 61
  • I like this idea, but wouldn't I then need many of these "fixed" classes"? Is there a way to make them at run-time? I used List in my example; in my project it is actually `Map>`, where Domain could be one of ~200 object, some of which are themselves parameterized. – Monkey Boson Feb 12 '11 at 20:45
1

Here is just a small idea. I'm not really sure if it will fit in your context but nevertheless:

public class GetMe<T>
{
    public List<T> getList() {
        @SuppressWarnings("unchecked")
        List<T> result = (List<T>) new LinkedList(); 
        return result;
    }
}

Cheers!

Lachezar Balev
  • 11,498
  • 9
  • 49
  • 72
0

The first problem is how you plan to instantiate a List object. If you disclose more of what you are trying to build, we may be able to help you better.

You may want to use Type instead of Class. Type can represent all generic types, although it's not pleasant to work with.

abstract public class GetMe<T> 
{
    Type type;
    public GetMe<T>(Type type) 
    {
        this.type = type;
    }
}

Another problem is how to create a generic type like List<String>. The "super type token" looks neat in syntax, in reality it's basically

static class XX extends TypeReference<List<String>>{}
....
Type typeListString = Util.extract(XX.class);

I would much prefer this way

List<String> f;

Type typeListString = getDeclaredField("f").getGenericType();

Actually, many of these frameworks that do fancy runtime generic magics are working on instance fields only.

irreputable
  • 44,725
  • 9
  • 65
  • 93
0

I think the confusion comes from the fact that you're trying to create an object from List<> which in face it an interface, not an object.
So no matter what you'd try, you just can't create an instance of List<> , (interfaces aren't actual classes, and don't have constructors)

Try using a constraint to avoid having interfaces put in the declaration:

public class GetMe<T extends Object> 

This will guarantee that T is an actual class and not an interface.

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185