Search code examples
javaspringspring-data

Spring Data - get entity name/type from Repository


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();

Solution

  • @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.