gpt4 book ai didi

java - ParameterizedType 和创建通用 dao

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:24:17 24 4
gpt4 key购买 nike

我尝试这个通用代码是因为我不想为数据库中的每个实体都创建一个 Dao 类,因为我有 80 个专门用于那些我将只执行 CRUD 查询的人。因为在大多数情况下,我只需要坚持或通过 id 进行查找。

public interface GenericDao<T, PK extends Serializable> {

T create(T t);
T read(PK id);
T update(T t);
void delete(T t);

}

接口(interface)实现

@Component
public class GenericDaoJpaImpl<T, PK extends Serializable>
implements GenericDao<T, PK> {

protected Class<T> entityClass;

@PersistenceContext
protected EntityManager entityManager;

public GenericDaoJpaImpl() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass()
.getGenericSuperclass();
this.entityClass = (Class<T>) genericSuperclass
.getActualTypeArguments()[0];
}

@Override
public T create(T t) {
this.entityManager.persist(t);
return t;
}

@Override
public T read(PK id) {
return this.entityManager.find(entityClass, id);
}

@Override
public T update(T t) {
return this.entityManager.merge(t);
}

@Override
public void delete(T t) {
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}

@Override
public void delete(Set<T> ts) {
for( T t : ts){
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}
}
}

异常

Caused by: 
org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [dao.GenericDaoJpaImpl]:
Constructor threw exception; nested exception is
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

如何解决这个问题,这个 ParameterizedType 是什么意思,为什么我们必须在构造函数中使用它?

当我评论构造函数时,除了 public T read(PK id) 我得到了 null pointer exception

    public GenericDaoJpaImpl() {
// ParameterizedType genericSuperclass = (ParameterizedType) getClass()
// .getGenericSuperclass();
// this.entityClass = (Class<T>) genericSuperclass
// .getActualTypeArguments()[0];
}

我是这样使用的:

@Autowired
private GenericDaoJpaImpl<AlerteAcheteur, Integer> acheteurAlerteDao;

我不想创建一个抽象类并像这样扩展它:

public class AlerteAcheteurGenericDaoJpaImpl extends GenericDaoJpaImpl<AlerteAcheteur, Integer> ... {

}

@Autowired
private AlerteAcheteurGenericDaoJpaImpl<AlerteAcheteur, Integer> acheteurAlerteDao;

最佳答案

不幸的是,没有办法让它完全按照您的意愿工作。

第 1 部分. 为什么它不起作用

请注意 GenericDaoJpaImpl 的确切声明-
GenericDaoJpaImpl<T, PK extends Serializable> implements GenericDao<T, PK> .

ClassCastException被抛出是因为 getClass().getGenericSuperclass()返回 Class<java.lang.Object> 的实例,即 Type ( java.lang.Class 实现了 java.lang.reflect.Type ),但不是 ParameterizedType .事实上,Class<java.lang.Object> 的一个实例由 getClass().getGenericSuperclass() 返回对于直接父类(super class)为 java.lang.Object 的每个类.因此,像这样的构造函数

public GenericDaoJpaImpl() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
}

适用于声明为 AlerteAcheteurGenericDaoJpaImpl extends GenericDaoJpaImpl<AlerteAcheteur, Integer> 的类.但这正是您不想声明您的 DAO 的方式。

片段 1,如果从您的 GenericDaoJpaImpl 运行, 将打印 TPK (它们都是 sun.reflect.generics.reflectiveObjects.TypeVariableImpl 的实例)。

片段 1

Type[] genericInterfaces = getClass().getGenericInterfaces();
ParameterizedType genericInterface = (ParameterizedType) genericInterfaces[0];
System.out.println(genericInterface.getActualTypeArguments()[0]);
System.out.println(genericInterface.getActualTypeArguments()[1]);

片段 2

@Bean(name = "alerteVendeurDao")
public GenericDao<AlerteVendeur, Long> alerteVendeurDao() {
return new GenericDaoJpaImpl<AlerteVendeur, Long>();
}

即使在 @Configuration 中有类似 Snippet 2 的内容-注释类,在运行时不可能知道是什么GenericDaoJpaImpl由于 type erasure 已参数化为.但是,如果片段 1 是从类似 AlerteAcheuteurDao implements GenericDao<AlerteAcheuteur, Long> 的东西执行的, class somepackage.entity.AlerteAcheteurclass java.lang.Long将被打印出来(因为这些参数是明确的并且在编译时已知)。

最后,组件扫描在逻辑上什至不适用于GenericDaoJpaImpl . bean 类 @Component - 带注释的类是“单例”范围的。除了只会创建一个实例之外,我们怎么知道这个单例 DAO 应该在哪个实体上运行?尽管如此,容器仍然能够实例化 GenericDaoJpaImpl ,因为在运行时类型信息已经被删除(type erasure!)。

此外,在相关情况下,建议使用更具体的 @Repository 注释 DAO。 , 而不是 @Component .

第 2 部分。什么可能是最好的选择?

在您的特定情况下,最好的办法是将实体类声明为构造函数参数。通过这种方式,可以创建许多特定于实体的 GenericDaoJpaImpl通过将适当的构造函数参数传递给每个实例,在 Spring 配置中创建实例。

GenericDaoJpaImpl.java

public class GenericDaoJpaImpl<T, PK extends Serializable> 
implements GenericDao<T, PK> {
private final Class<T> entityClass;

@PersistenceContext
protected EntityManager entityManager;

public GenericDaoJpaImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}

@Override
public T create(T t) {
this.entityManager.persist(t);
return t;
}

@Override
public T read(PK id) {
return this.entityManager.find(entityClass, id);
}

@Override
public T update(T t) {
return this.entityManager.merge(t);
}

@Override
public void delete(T t) {
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}

@Override
public void delete(Set<T> ts) {
for( T t : ts){
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}
}
}

AnnotationContextConfiguration.java

请注意,也可以通过 constructor-based dependency injection 在 XML 中执行相同的操作.

@Configuration
@ComponentScan("somepackage.service")// scan for services, but not for DAOs!
public class Config {

@Bean(autowire = Autowire.BY_NAME)
public GenericDaoJpaImpl<AlerteAcheteur, Long> alerteAcheteurDao() {
return new GenericDaoJpaImpl<AlerteAcheteur, Long>(AlerteAcheteur.class);
}

@Bean(autowire = Autowire.BY_NAME)
public GenericDao<AlerteVendeur, Long> alerteVendeurDao() {
return new GenericDaoJpaImpl<AlerteVendeur, Long>(AlerteVendeur.class);
}

// other DAOs

...
}

AlerteServiceImpl.java(怎么可能看起来像)

请注意字段名称很重要,因为 DAO 是按名称 Autowiring 的。如果您不想将字段命名为 alerteAcheteurDao , 你可以使用 @Qualifier @Autowired .

@Service
public class AlerteServiceImpl implements AlerteService {

@Autowired
private GenericDao<AlerteAcheteur, Long> alerteAcheteurDao;

@Autowired
private GenericDao<AlerteVendeur, Long> alerteVendeurDao;

...
}

这是一个非常优雅的解决方案。您不必像 AlerteAcheteurGenericDaoJpaImpl extends GenericDaoJpaImpl<AlerteAcheteur, Integer> 这样的垃圾邮件类.添加新实体后,您只需添加 GenericDaoJpaImpl 的新实例到 Spring 配置。

希望对您有所帮助。

关于java - ParameterizedType 和创建通用 dao,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31754803/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com