I am looking for a way to get an entity type or class name from an instance implementing Spring Data JPA Repository
interface.
I have got a number of interfaces extending a base interface that extends Repository
interface and that defines some base queries.
@NoRepositoryBean
public interface EnumerationRepository<T extends IDatabaseEnumeration> extends Repository<T, String> {
// ...
}
public interface SampleEnumerationRepository extends EnumerationRepository<SampleEnumeration> {
}
Spring allows me to inject implementations of all these interfaces as a collection into a bean
@Autowired
private Collection<EnumerationRepository<? extends IDatabaseEnumeration>> repositories;
I wanted to put all of these implementations into a Map
for an easy access inside a generic method. I wanted to use the entity type or name as the key but I am not sure where to get it. Is there any way to get one of these attributes? Preferably the class type.
I was able to achieve the desired behaviour with a query like this. But I would like to avoid this solution if possible as it creates a dependency on the underlying DB.
@Query(value = "select '#{#entityName}' from dual", nativeQuery = true)
public String getEntityName();
@jens-schauder 's answer did not work in my case but it showed me the right direction.
Spring injected me the implementation of my interface extending the spring Repository
interface. Therefore I had to get all interfaces, filter out spring internal ones, so I ended up with the one I defined. This one however was not generic yet so I had to get its super interface that had the generic type.
I don't really care about performance as this method is called only during Spring container initialization.
Fortunatelly polymorphism works quite well in this case. So I only had to implement default method on the super interface. Like this
@NoRepositoryBean
public interface EnumerationRepository<T extends IDatabaseEnumeration> extends Repository<T, String> {
// ...
default Class<T> getEntityClass() {
Type[] interfaces = getClass().getInterfaces();
for (Type t : interfaces) {
if (t instanceof Class<?>) {
Class<?> clazz = (Class<?>) t;
if (clazz.getPackage().getName().startsWith(ApplicationConst.BASE_PACKAGE)) {
// Repositories should implement only ONE interface from application packages
Type genericInterface = clazz.getGenericInterfaces()[0];
return (Class<T>) ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
}
}
}
return null;
}
}
I hope this might be useful to other users facing similar issues.