Spring JpaRepository 使用通用实体
Spring JpaRepository using generic entity
我正在尝试实现一个像这样的通用 DAO,以便将它与非常相似的 X 实体(id、代码、描述)一起使用:
@Repository
public interface GenericDao<T> extends JpaRepository<T, Long> {
T findByCode(String code);
T findById(Long id);
}
我的一个实体是这样的:
@Getter
@Setter
@Entity
@Table(name = "TEST")
public class Test {...}
我有一个需要使用 Dao 的服务:
@Service
public class TestServiceImpl implements TestService {
private GenericDao<Test> testDao;
@Autowired
public TestServiceImpl(GenericDao<Test> testDao) {
this.testDao = testDao;
}
}
当我使用 SpringBoot 启动我的应用程序时,应用程序没有启动,错误是:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1127)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 23 more
Caused by: java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:67)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:89)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:172)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 34 more
你不能这样做。
Spring 尝试在启动时 创建您的存储库,而不是在自动装配时。但是 Spring 完全不知道应该使用什么样的通用参数。所以它试图用 Object
实例化这个存储库。但是 Object
不是实体,所以你得到相应的错误。
结论:您的存储库必须是特定类型的,但不是通用的。
您可以通过一些调整来完成您想要完成的事情。
不要使用 @Repository 标记您的 GenericDao 并照此使用它,而是使用 @NoRepositoryBean 注释。正如 JavaDocs 所述,Spring JPA 将尝试初始化附加到 JpaRepository 的任何内容,但 @NoRepositoryBean 允许您创建不会初始化的中间扩展,您的真实存储库可以从中扩展。您只需要确保任何实现您的 GenericDao class 的东西确实为 T.
提供了一个参数
这意味着您还必须实现 GenericDao 的扩展,它实际上将具有 @Repository 注释,并且您在服务中使用这些 daos 代替泛型。所以您的代码将如下所示:
通用道:
@NoRepositoryBean
public interface GenericDao<T> extends JpaRepository<T, Long> {
T findByCode(String code);
T findById(Long id);
}
TestDao,您将添加一个新的 class 参数化实现:
@Repository
public interface TestDao extends GenericDao<Test> {
}
和服务:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
@Autowired
public TestServiceImpl(TestDao testDao) {
this.testDao = testDao;
}
}
我正在尝试实现一个像这样的通用 DAO,以便将它与非常相似的 X 实体(id、代码、描述)一起使用:
@Repository
public interface GenericDao<T> extends JpaRepository<T, Long> {
T findByCode(String code);
T findById(Long id);
}
我的一个实体是这样的:
@Getter
@Setter
@Entity
@Table(name = "TEST")
public class Test {...}
我有一个需要使用 Dao 的服务:
@Service
public class TestServiceImpl implements TestService {
private GenericDao<Test> testDao;
@Autowired
public TestServiceImpl(GenericDao<Test> testDao) {
this.testDao = testDao;
}
}
当我使用 SpringBoot 启动我的应用程序时,应用程序没有启动,错误是:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1127)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 23 more
Caused by: java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:67)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:89)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:172)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 34 more
你不能这样做。
Spring 尝试在启动时 创建您的存储库,而不是在自动装配时。但是 Spring 完全不知道应该使用什么样的通用参数。所以它试图用 Object
实例化这个存储库。但是 Object
不是实体,所以你得到相应的错误。
结论:您的存储库必须是特定类型的,但不是通用的。
您可以通过一些调整来完成您想要完成的事情。
不要使用 @Repository 标记您的 GenericDao 并照此使用它,而是使用 @NoRepositoryBean 注释。正如 JavaDocs 所述,Spring JPA 将尝试初始化附加到 JpaRepository 的任何内容,但 @NoRepositoryBean 允许您创建不会初始化的中间扩展,您的真实存储库可以从中扩展。您只需要确保任何实现您的 GenericDao class 的东西确实为 T.
提供了一个参数这意味着您还必须实现 GenericDao 的扩展,它实际上将具有 @Repository 注释,并且您在服务中使用这些 daos 代替泛型。所以您的代码将如下所示:
通用道:
@NoRepositoryBean
public interface GenericDao<T> extends JpaRepository<T, Long> {
T findByCode(String code);
T findById(Long id);
}
TestDao,您将添加一个新的 class 参数化实现:
@Repository
public interface TestDao extends GenericDao<Test> {
}
和服务:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
@Autowired
public TestServiceImpl(TestDao testDao) {
this.testDao = testDao;
}
}