Spring Data - 从Repository获取实体名称/类型

时间:2017-12-11 18:56:28

标签: java spring spring-data

我正在寻找一种从实现Spring Data JPA Repository接口的实例中获取实体类型或类名的方法。

我有许多接口扩展了扩展Repository接口的基接口,并定义了一些基本查询。

@NoRepositoryBean
public interface EnumerationRepository<T extends IDatabaseEnumeration> extends Repository<T, String> {
    // ...
}

public interface SampleEnumerationRepository extends EnumerationRepository<SampleEnumeration> {

}

Spring允许我将所有这些接口的实现作为集合注入到bean

@Autowired
private Collection<EnumerationRepository<? extends IDatabaseEnumeration>> repositories;

我想将所有这些实现放入Map,以便在泛型方法中轻松访问。我想使用实体类型或名称作为键,但我不知道从哪里得到它。有没有办法获得这些属性之一?最好是班级类型。

我能够通过这样的查询实现所需的行为。但是我想尽可能避免这种解决方案,因为它会创建对底层数据库的依赖。

@Query(value = "select '#{#entityName}' from dual", nativeQuery = true)
public String getEntityName();

3 个答案:

答案 0 :(得分:2)

@ jens-schauder的答案在我的案例中没有用,但它向我展示了正确的方向。

Spring为我注入了扩展spring Repository接口的接口的实现。因此,我必须得到所有接口,过滤掉弹簧内部接口,所以我最终得到了我定义的接口。然而,这个不是通用的,所以我必须得到具有泛型类型的它的超级接口。

我不太关心性能,因为只在Spring容器初始化期间调用此方法。

Fortunatelly多态在这种情况下运作良好。所以我只需要在超级接口上实现默认方法。喜欢这个

@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;
    }

}

我希望这对面临类似问题的其他用户有用。

答案 1 :(得分:1)

如果类型参数绑定到接口中的类型,则可以使用以下答案获取类型参数:https://stackoverflow.com/a/1901275/66686

Index   id  user_id merchant_id marketing_email_id  start_date  end_date    email_status    sms_status  created_at  visited_at
0   68989   68990   13277   38  437 2016-04-11 00:00:00 2016-04-16 00:00:00 1   NaN 2016-04-11 11:05:31 []
1   403557  403558  195246  179 2218    2017-06-09 00:00:00 2017-06-12 00:00:00 0   1   2017-06-09 06:01:04 []
2   333381  333382  127359  514 1820    2017-04-24 00:00:00 2017-05-01 00:00:00 0   1   2017-04-24 10:00:33 ['2017-04-24']
3   511815  511816  151653  259 1136    2017-08-05 00:00:00 2017-08-08 00:00:00 0   1   2017-08-05 11:31:19 []
4   167172  167173  51546   32  363 2016-08-05 00:00:00 2016-08-15 00:00:00 1   NaN 2016-08-05 12:00:43 []

答案 2 :(得分:0)

尝试一下

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import org.springframework.aop.support.AopUtils;
import org.springframework.data.repository.Repository;
import org.springframework.util.Assert;

import java.util.List;

public class Repospector {
    private static final TypeResolver RESOLVER = new TypeResolver();

    public Class<?> getEntityClass(Repository<?, ?> repository) {
        Class<?> targetClass = AopUtils.getTargetClass(repository);
        List<ResolvedType> types = RESOLVER.resolve(targetClass).typeParametersFor(Repository.class);
        Assert.state(types.size() == 2, "Call the whambulance!");
        return types.get(0).getErasedType();
    }
}