3

Hi have a Generic class in Spring, and I would like to get the generic T type class for an injected bean. I know the classic way in Java and read how Spring 4 implements Java Generics. Also, I tried to find a solution using ResolvableType but nothing works.

@Autowired
GenericDao<SpecificClass> specificdao;

public GenericDaoImpl <T> {

    private Class<T> type;

    public DaoImpl () { 
         this.type = ...? 
    }

    public T findById(Serializable id) {
        return (T) HibernateUtil.findById(type, id);
    }
}

Are there any way to avoid this?

@Autowired
@Qualifier
GenericDao<SpecificClass> specificdao;

@Repository("specificdao")
public SpecificDaoImpl extends GenericDao<SpecificClass> {
      public SpecificDaoImpl () {
          // assuming the constructor is implemented in GenericDao
          super(this.getClass())
      }
}

Thanks.

Community
  • 1
  • 1
Esteban S
  • 1,859
  • 5
  • 22
  • 43
  • 1
    I may be wrong, but I doubt if this can be easily done (due to type erasure). BTW: from the code you've provided, it seems you're trying to re-implement the functionality provided by the Spring Data. Why not to use it instead? – G. Demecki Nov 26 '15 at 14:19
  • Yes it is, but I would to do it by my own. Thanks. – Esteban S Nov 27 '15 at 07:37
  • 2
    One small remark: The result `this.getClass()` would be the same if called from the super class `GenericDaoImpl`, since `getClass()` returns the runtime type. So the class object doesn't need to be a parameter of the `GenericDaoImpl` constructor, `GenericDaoImpl` can call it itself. – Lii Nov 27 '15 at 12:14
  • Also: You don't need the unchecked cast in `findById` since you have the class object. You can use `return this.type.cast(HibernateUtil.findById(type, id));`, which is a little more safe since it will actually check that the result is of the right type. – Lii Nov 27 '15 at 13:30
  • [This answer](http://stackoverflow.com/a/18709327/452775) seems to contain info about almost the same thing. – Lii Nov 27 '15 at 13:32

1 Answers1

2

If I understand your question: what you want to achieve is very tricky.

You can use TypeTools and then do something like:

import net.jodah.typetools.TypeResolver;

public GenericDaoImpl <T> {

    private Class<T> type;

    public GenericDaoImpl () { 
         Class<?>[] typeArguments = TypeResolver.resolveRawArguments(GenericDaoImpl.class, getClass());
         this.type = (Class<T>) typeArguments[0];
    }

    public T findById(Serializable id) {
        return (T) HibernateUtil.findById(type, id);
    }
}

But still I doubt if it's a good idea. Because usually you don't want:

@Autowired
GenericDao<SpecificClass> specificDao;

But instead:

@Autowired
SpecificDao specificDao;

Why? Because each DAO has almost always completely different methods than other DAOs. The only generic methods, common to all, are probably: findById, findAll, save, count, delete etc.

So subclassing from a GenericDAO is the most obvious way, as it allows you to add any needed method inside a concrete DAO.

BTW: You said that you want re-implement Spring Data functionality on your own. But please notice that in Spring way, you still have to create concrete repositories.

halfer
  • 19,824
  • 17
  • 99
  • 186
G. Demecki
  • 10,145
  • 3
  • 58
  • 58