Did*_*r L 10 java hibernate spring-data-jpa
在一个新项目中,我们希望使用Spring Data JPA并为所有JPA实体定义接口,例如:
public interface Person extends Serializable {
void setId(Long id);
Long getId();
void setLastName(String lastName);
String getLastName();
void setFirstName(String firstName);
String getFirstName();
// ...
}
@Entity
@Table(name = "t_persons")
public class PersonEntity implements Person {
private static final long serialVersionUID = 1L;
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String firstName;
@Column
private String lastName;
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是,在声明基于类似接口的Spring Data存储库时
public interface PersonRepository extends JpaRepository<Person, Long> {
}
Run Code Online (Sandbox Code Playgroud)
Spring上下文无法初始化,原因是异常
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: interface com.example.Person
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:917)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:860)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:775)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489)
... 24 more
Caused by: java.lang.IllegalArgumentException: Not an managed type: interface com.example.Person
at org.hibernate.ejb.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:171)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:70)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:65)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:146)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:84)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:67)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:150)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:224)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:210)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:84)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1572)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1510)
... 34 more
Run Code Online (Sandbox Code Playgroud)
我没有找到任何依赖于接口而不是具体类型的Repository的例子,所以这有可能吗?如果是,怎么样?
似乎如果我们不能使用接口来声明存储库,那么根本不可能使用这些接口,因为我们最终会在服务中的每个地方都使用显式强制转换,甚至在我们处理泛型时立即进行未经检查的强制转换(List,Iterable......).
这是您的问题的解决方案。我不知道为什么Spring家伙决定将其存储库建立在具体的类上。但是至少他们使改变它成为可能。
repositoryFactoryBeanClass,EnableJpaRepositories例如:import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
/**
* @author goraczka
*/
@EnableJpaRepositories(
repositoryFactoryBeanClass = InterfaceBasedJpaRepositoryFactoryBean.class
)
public class DatabaseConfig {
}
Run Code Online (Sandbox Code Playgroud)
InterfaceBasedJpaRepositoryFactoryBean。这是一个Spring挂钩,用于为存储库bean创建自定义工厂。import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
/**
* @author goraczka
*/
public class InterfaceBasedJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
extends JpaRepositoryFactoryBean<T, S, ID> {
public InterfaceBasedJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new InterfaceBasedJpaRepositoryFactory(entityManager);
}
}
Run Code Online (Sandbox Code Playgroud)
EntityManager。import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.util.Assert;
import javax.persistence.EntityManager;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author goraczka
*/
public class InterfaceBasedJpaRepositoryFactory extends JpaRepositoryFactory {
private final Map<? extends Class<?>, ? extends Class<?>> interfaceToEntityClassMap;
private final EntityManager entityManager;
public InterfaceBasedJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
interfaceToEntityClassMap = entityManager
.getMetamodel()
.getEntities()
.stream()
.flatMap(et -> Arrays.stream(et.getJavaType().getInterfaces())
.map(it -> new AbstractMap.SimpleImmutableEntry<>(it, et.getJavaType())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (possibleDuplicateInterface, v) -> v));
}
@Override
@SuppressWarnings("unchecked")
public <T, ID> JpaEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
Assert.isTrue(domainClass.isInterface(), "You are using interface based jpa repository support. " +
"The entity type used in DAO should be an interface");
Class<T> domainInterface = domainClass;
Class<?> entityClass = interfaceToEntityClassMap.get(domainInterface);
Assert.notNull(entityClass, "Entity class for a interface" + domainInterface + " not found!");
return (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(entityClass, entityManager);
}
}
Run Code Online (Sandbox Code Playgroud)
不要因为任何错误而羞辱我。阅读此问题并意识到尚无解决方案后,我在10分钟内完成了操作。我真的需要一个。我尚未为此进行任何测试,但似乎可以工作。欢迎改进。
我遇到了同样的问题,并使用@NoRepositoryBean存储库接口解决了它,该存储库接口使用接口而不是具体的类(感谢该博客文章):
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface PersonRepository<P extends Person> extends JpaRepository<P, Long> {
// code all generic methods using fields in Person interface
}
Run Code Online (Sandbox Code Playgroud)
然后,使用扩展另一个的具体存储库:
public interface PersonEntityRepository extends PersonRepository<PersonEntity> {
// code all specific methods that use fields in PersonEntity class
}
Run Code Online (Sandbox Code Playgroud)
该注释至少存在于spring-data-commons-2.1.9.RELEASE.jar.
shl*_*i33 -2
接口 Person 缺少 @Entity 注释,因此不被识别为托管对象。我认为将 @Entity 注释放在 Person 接口上也无济于事,因为该注释不是继承的。我认为您应该忘记 Person 接口,或者只在存储库声明中使用 PersonEntity 。实际上并没有签入代码 - 如果这个答案是错误的,那么非常抱歉......
| 归档时间: |
|
| 查看次数: |
4477 次 |
| 最近记录: |