ParameterizedType并创建通用dao

我尝试使用此通用代码,因为我不想为数据库中的每个实体创建一个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);

}

接口的印象

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

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

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

}

@Autowired

private AlerteAcheteurGenericDaoJpaImpl<AlerteAcheteur, Integer> acheteurAlerteDao;

回答:

不幸的是,没有任何方法可以使其完全按照您的要求工作。

回答:

需要注意的确切声明GenericDaoJpaImpl-

GenericDaoJpaImpl<T, PK extends Serializable> implements GenericDao<T, PK>

ClassCastException之所以抛出,是因为getClass().getGenericSuperclass()返回的实例(Class<java.lang.Object>Typejava.lang.Class实现java.lang.reflect.Type),但是不是)ParameterizedType。实际上,对于每个直接超类为的类,Class<java.lang.Object>将由的实例返回。因此,像getClass().getGenericSuperclass()``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>();

}

即使存在Snippet

2中带@Configuration注释的类之类的内容,在运行时也无法知道GenericDaoJpaImpl由于类型Erase导致参数化了。但是,如果代码片段1是从类似的代码执行的AlerteAcheuteurDao

implements GenericDao<AlerteAcheuteur, Long>class

somepackage.entity.AlerteAcheteur并且class

java.lang.Long将被打印(因为这些参数是明确的,并且在编译时是已知的)。

最后,组件扫描甚至在逻辑上都不适用于GenericDaoJpaImpl。带@Component注释类的Bean 是“

Singleton”作用域的。除了将只创建一个实例这一事实之外,我们如何知道该单例DAO应该在哪个实体上运行?尽管如此,容器仍然能够实例化GenericDaoJpaImpl,因为在运行时类型信息已经被擦除(类型擦除!)。

此外,在相关情况下,建议使用更具体的注释DAO

@Repository,而不是@Component

回答:

在您的特定情况下,最好的选择是将实体类声明为构造函数参数。这样,可以GenericDaoJpaImpl通过将适当的构造函数参数传递给每个实例来在Spring配置中创建大量特定于实体的实例。

通用DaoJpaImpl.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

请注意,也可以通过基于构造函数的依赖注入在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通过名称自动连接。如果你不希望类似名称的字段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配置添加新实例。

我希望这会有所帮助。

以上是 ParameterizedType并创建通用dao 的全部内容, 来源链接: utcz.com/qa/405477.html

回到顶部