Spring Data – get entity name/type from Repository

Issue

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.

Answered By – Tomas Kralik

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published