1

I had an idea to use a Dao class (Dao.java):

class Dao <Model extends AbstractModel> {
    public String getUrl() {
        return Model.class.getAnnotation(MyPath.class).url();
    }
}

and a model like this (Account.java):

@MyPath(url = "blabla")
class Account extends AbstractModel {
    ...
}

but the problem is that in that case if i run

@Test
public void testDaoUrl() {
    Dao<Account> dao = new Dao<Account>();
    dao.getUrl();
}

Model.class seems to be an AbstractModel and not an Account. Is there any work around to get MyPath annotation from the Dao (without giving it an instance of Account.class)?

Thanks in advance for any idea!

PS: MyPath-Annotation:

@Retention(RUNTIME)
@Target(TYPE)
@interface MyPath {
    public String url();
}
Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
Ilya Ananyev
  • 33
  • 1
  • 8
  • `Model.class` should be a compiler error. Also, possible duplicate: http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime – Radiodef May 29 '15 at 15:21

1 Answers1

2

Yes, there is another solution, but it's uglier than passing a Class argument to the Dao constructor and more prone to error.

This trick is known as the type token. I've seen it used mostly in deserialization libraries (like Gson or Jackson for JSON).

class Dao<Model extends AbstractModel> {
    private final Class<?> typeArgument;

    public Dao() {
        Type superclass = getClass().getGenericSuperclass(); 
        ParameterizedType parameterized = (ParameterizedType) superclass;
        // with nested generic types, this becomes a little more complicated
        typeArgument = (Class<?>) parameterized.getActualTypeArguments()[0];
    }

    public String getUrl() {
        return typeArgument.getAnnotation(MyPath.class).url();
    }
}

and used like so

new Dao<Account>(){}.getUrl()

So, when creating a Dao instance, you actually, instead, create a Dao subclass instance. This way the instance is of a parameterized subtype of Dao, ie. something like

class AnonymousDao extends Dao<Account> {}

and then the parameterized type can be extracted and used.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724