Spring get generic type class
Asked Answered
S

4

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

Suave answered 12/5, 2015 at 22:15 Comment(0)
T
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);
}
Twofold answered 13/5, 2015 at 5:19 Comment(0)
E
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
Ebner answered 26/7, 2016 at 14:2 Comment(0)
C
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;
  }
}
Coverage answered 13/5, 2015 at 5:28 Comment(0)
T
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);
}
Twofold answered 13/5, 2015 at 5:19 Comment(0)
E
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);
  }
}
Element answered 8/6, 2024 at 16:48 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.