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
If we want the actual type of a generic parameter, we should inject it to the class in another way (e.g. constructor parameter, abstract function that returns the actual type, etc...).
A generic type is a class or interface that is parameterized over types. We use angle brackets (<>) to specify the type parameter.
The generic class works with multiple data types. A normal class works with only one kind of data type.
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
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With