0

I am writing some generic DAO as follows

public class MyGenericDAO<T> {

      Class<T> clazz;

      public void doSome(){
        for(int =0 ;i<14;i++){
            //do something
           }
      }
}

Now i want to initialize clazz based on Type of T? .How can i do it?

For example if someone does MyGenericDAO<Xyz> = new MyGenericDAO<MyGenericDAO>() then type of T should be Xyz.

How can i do it?Is it possible without refelection?

user93796
  • 18,749
  • 31
  • 94
  • 150

3 Answers3

4

It's not even possible with reflection, unfortunately. If you need it, you'll need to make a MyGenericDao constructor that takes a Class<T> argument:

public MyGenericDao(class<T> clazz) {
  this.clazz = clazz;
}
jacobm
  • 13,790
  • 1
  • 25
  • 27
3

Unfortunately, due to the type erasure the only way to initialize clazz to the type of T is passing the corresponding class in the constructor:

MyGenericDAO(Class<T> clazz) {
    this.clazz = clazz;
}

Once of the reasons why java.lang.Class has been made generic is precisely to support this pattern. Since the T in Class<T> must correspond to the T in MyGenericDAO<T>, the compiler will be able to do the type checking for you.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • That's really not entirely true. See my 2nd comment on the OP. – Matt Ball Mar 04 '13 at 22:12
  • @MattBall I saw it, and I was intrigued for a moment, but unfortunately it does not help much, even after a relatively honest hack ([link](http://ideone.com/nyei5D)). I expected it to print `Integer` and `String`, but got instead only `T` and `T`. Considering the type erasure, it kind of makes sense. – Sergey Kalinichenko Mar 04 '13 at 22:14
  • Huh, I _really_ thought there was [an anonymous subclassing hack you could use](http://www.artima.com/weblogs/viewpost.jsp?thread=208860), but indeed I can't seem to use it here. – Matt Ball Mar 04 '13 at 22:46
  • 1
    Super type tokens don't work that way. The trick named by @MattBall requires a (anonymous) subclass which the type argument stored in actual bytecode [DEMO](http://ideone.com/1CzZOz) – Raffaele Mar 04 '13 at 22:46
  • @Raffaele yes, that's exactly what I had in mind. For some reason that doesn't work with my local Java 6 installation (`ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType`). – Matt Ball Mar 04 '13 at 22:52
  • @Raffaele I tried using an anonymous subclass ([see the link that I posted in the comment above](http://ideone.com/nyei5D) - the subclass is in the implementation of the `getTypeParameter` method), but unfortunately it does not work this way. Making an explicit anonymous subtype the way that your demo does is very cute, but it is unlikely to help getting the `T` of the `MyGenericDAO` in the OP's situation. – Sergey Kalinichenko Mar 04 '13 at 22:54
  • @MattBall I bet you have missed a pair of curly braces after `new TestDto()` in Raffaele's demo :):):) – Sergey Kalinichenko Mar 04 '13 at 22:54
  • @dasblinkenlight yes, that's exactly it. I'd tried to do the same at runtime, though my types done got erased. http://ideone.com/vFLHZQ – Matt Ball Mar 04 '13 at 22:57
  • @dasblinkenlight I forked your code to quickly make mine, so I saw it :) I hope it's clear why it doesn't work: if you inspect the bytecode of `TestDto$1.class` (the anonymous class defined inside your `getTypeParameter()`) it can't contain any reference other than `T`. Instead when my code is compiled, two classes are synthesized (should be `Main$1.class` and `Main$2.class`) and the bytecode contains literally the references to `String` and `Integer` – Raffaele Mar 04 '13 at 23:00
  • @Raffaele Yes, it is absolutely clear why it does not work the way that I tried it, although I hoped for a moment that there's some reflection magic that I did not understand. – Sergey Kalinichenko Mar 04 '13 at 23:03
0

Type arguments don't get to the runtime, so the calling code must pass a token to construct the Class<T> object at runtime. I name it token because there are many different objects you can pass to rebuild a Class<T> object at runtime, for example:

  • a String, to be used with Class.forName(name)
  • a Class<T> object
  • a type token, ie a subclass of a parameterized type whose arguments are neither type variables nor wildcard (bounded or not), for example a new List<String>(){} (I used new and the curly braces to underline that this expression returns an instance of an anonymous subclass)

With type tokens:

public class MyGenericDAO<T> {

  @SuppressWarnings("unchecked")
  public Class<T> getTypeParameter() throws Exception {
    Type type = ((ParameterizedType) getClass().getGenericSuperclass())
           .getActualTypeArguments()[0];
    return (Class<T>) type;
  }
}

Note that there is an unchecked conversion when you cast the Type to a Class<T>. The calling code then looks like:

MyGenericDAO<Foo> dao = new MyGenericDAO<Foo>(){};
// Then if you want an instance
Foo foo = dao.getTypeParameter().newInstance();

Again, note the curly braces, since super type tokens only work when there is a real class generated at compile time. This approach only works if the client code honors the contract and uses an anonymous inner class every time a DAO object is needed (otherwise the magic of getTypeParameter() vanishes)

Raffaele
  • 20,627
  • 6
  • 47
  • 86