3

I have a class:

public abstract class BaseDaoImpl<T extends BaseModel> implements BaseDao<T> {
}

I'm also using annotations to generate SQL queries (for various reasons I'm not able to use a framework such as hibernate) such as @Table & @Column

I would like to be able to retrieve the <T extends BaseModel> .class instance without having to take T as an input on a method.

I suppose the easy alternative would be to create a method:

public void set(Class<T> clazz){}

However I'd like to avoid this if possible to keep my code as streamlined as possible. Is this possible?

Nic2352
  • 95
  • 8

2 Answers2

4

Unfortunately, it's not possible to do due to type erasure: you have to force your classes to provide meta-information in runtime. I would do something like this (an adapted snippet from a big real project).

public abstract class AbstractBaseDao<T extends BaseModel> implements BaseDao<T>{

    public abstract Class<T> getType();
}

class ConcreteModel extends BaseModel {/*...*/}

class ConcreteDao extends AbstractBaseDao<ConcreteModel> {

    @Override
    public Class<ConcreteModel> getType() {
        return ConcreteModel.class;
    }
}

An alternative way is to define a custom annotation like this:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Type {

    Class value();
}

interface BaseDao<T extends BaseModel> { }

@Type(ConcreteModel.class)
public class ConcreteDao implements BaseDao<ConcreteModel> { }

...and use it in some processor for your DAOs, but this will require some additional infrastructure code to register all annotated classes. And - again - you cannot limit type bounds within annotations.

4

Although using reflection is a bit of a code smell, you can get the information you need:

Class<T> modelImplementationClass = (Class<T>)
   ((BaseModel)this.getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

Reflection is a Java API that allows you to access or modify the behavior of methods, classes, interfaces at runtime.

Reflection should generally be avoided as it's quite slow and breaks abstraction by revealing internal implementation details.

Ben Green
  • 3,953
  • 3
  • 29
  • 49
  • I tried to play with snippet and got confused: we would like to extract information on the parameter not from a model classes, but from a concrete DAO, right? For this snippet: ``` final ConcreteDao concreteDao = new ConcreteDao(); System.out.println((concreteDao.getClass().getGenericSuperclass())); System.out.println((concreteDao.getClass().getGenericInterfaces()[0]).getTypeName()); ``` You will get this output: ``` class java.lang.Object com.github.gstromov.leetcode.open.easy.BaseDao ``` – The Rabbit of No Luck Nov 27 '19 at 12:03