6

I know this question has been asked often but I'm unable to find a solution. How can I get a generic type class name in a Spring injected repository?

Here it is my base repository

public interface UserRepository extends JpaRepository<User, Long>, IUserRepository<User>{ User findByUsername(String username); } 

this is the interface

public interface IUserRepository<T> { public List<T> findAllValidEtSiteAndStructure(); } 

and finally here it is the implementation

public class UserRepositoryImpl<T> implements IUserRepository<T> { @PersistenceContext private EntityManager em; private Class< T > type; @Override public List<T> findAllValidEtSiteAndStructure() { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication instanceof UserAuthentication) { final User currentUser = ((UserAuthentication) authentication).getDetails(); return (List<T>) em.createQuery("FROM " + type.getName()+ " WHERE site=:site AND structure=:structure AND valid=:valid") .setParameter("site", currentUser.getInstallation().getSite()) .setParameter("structure", currentUser.getInstallation().getStructure()) .setParameter("valid", true) .getResultList(); } return null; } } 

how can I get type.name? Thanks in advance

4 Answers 4

12

Considering that you're using Spring Framework, use the code snippet bellow, I've tested and it worked just fine:

ResolvableType resolvableType = ResolvableType.forClass(UserRepository.class).as(JpaRepository.class); System.out.println(resolvableType.getGeneric(0));//User System.out.println(resolvableType.getGeneric(1));//Long 
Sign up to request clarification or add additional context in comments.

Comments

4

Basically you can't get the generic type because of type erasure.

What I would do is add an abstract method to UserRepositoryImpl that returns the relevant type:

public abstract Class getType(); 

And then I would create specific instances for UserRepositoryImpl for which the type is already known at compile time. For example:

public class StudentRepository extends UserRepositoryImpl<Student> { public Class getType() { return Student.class; } } 

Comments

2

The general answer to you question can be seen in the documentation -> http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations in the chapter Custom implementations for Spring Data repositories

But I think that should not be necessary in your case. You should be able to do it in the following way.

public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); List<User> findByStructureAndSiteAndValid(Structure structure, Site site, boolean valid); } 

Comments

0

Unfortunately, because of type erasure, we can't get the real type directly and statically unless we have an instance of it in code (it's possible to do it with a combination of reflection and annotations).

You can also pass the type statically through the constructor, then choose to expose or not the your especialized type:

public class StudentRepository extends UserRepositoryImpl<Student> { public StudentRepository(EntityManager em) { super(em, Student.class); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.