不幸的是,没有任何方法可以使其完全按照您的要求工作。
第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()``java.lang.Object
public GenericDaoJpaImpl() { ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];}适用于声明为的类
alerteAcheteurGenericDaoJpaImpl extendsGenericDaoJpaImpl<alerteAcheteur, Integer>。但这正是您不希望声明DAO的方式。
摘录1(如果是从您运行的
GenericDaoJpaImpl)将打印
T和
PK(它们都是的实例
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是从类似的代码执行的
alerteAcheuteurDaoimplements GenericDao<alerteAcheuteur, Long>,
classsomepackage.entity.alerteAcheteur并且
classjava.lang.Long将被打印(因为这些参数是明确的,并且在编译时是已知的)。
最后,组件扫描甚至在逻辑上都不适用于
GenericDaoJpaImpl。带
@Component注释类的Bean 是“
Singleton”作用域的。除了将只创建一个实例这一事实之外,我们如何知道该单例DAO应该在哪个实体上运行?尽管如此,容器仍然能够实例化
GenericDaoJpaImpl,因为在运行时类型信息已经被擦除(类型擦除!)。
此外,在相关情况下,建议使用更具体的注释DAO
@Repository,而不是
@Component。
第2部分。什么是最好的选择?
在您的特定情况下,最好的选择是将实体类声明为构造函数参数。这样,可以
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。
@Servicepublic class alerteServiceImpl implements alerteService { @Autowired private GenericDao<alerteAcheteur, Long> alerteAcheteurDao; @Autowired private GenericDao<alerteVendeur, Long> alerteVendeurDao; ...}这是一个非常优雅的解决方案。您不必发送垃圾邮件之类的消息
alerteAcheteurGenericDaoJpaImpl extendsGenericDaoJpaImpl<alerteAcheteur,Integer>。添加新实体后,您只需
GenericDaoJpaImpl向Spring配置添加新实例。
我希望这会有所帮助。



