2013-03-21 62 views
2

我试图用泛型的Spring Data jpa,但是当我运行单元测试时会处理相同的异常。 这里是个例外:当单元测试时无法自动装入字段

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tn.moussi.PostRepositorytest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: tn.moussi.repositories.PostRepository tn.moussi.PostRepositorytest.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'postRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: tn.moussi.repositories.PostRepository tn.moussi.PostRepositorytest.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'postRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284) 
    ... 26 more 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'postRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:149) 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1442) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:876) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478) 
    ... 28 more 
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1364) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:294) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365) 
    at com.sun.proxy.$Proxy22.createQuery(Unknown Source) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) 
    at com.sun.proxy.$Proxy20.createQuery(Unknown Source) 
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:69) 
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.fromQueryAnnotation(SimpleJpaQuery.java:132) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:114) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:160) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:280) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:148) 
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:125) 
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:41) 
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142) 
    ... 36 more 
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:180) 
    at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:110) 
    at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.java:93) 
    at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:324) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3291) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3180) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:706) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:562) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299) 
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247) 
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:248) 
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183) 
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) 
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:105) 
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80) 
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168) 
    at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:221) 
    at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:199) 
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1735) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:291) 
    ... 58 more 

,这是Java代码:

的Bean;

import org.springframework.data.jpa.repository.JpaRepository; 
import org.springframework.data.jpa.repository.Query; 
import org.springframework.data.repository.query.Param; 


public interface GenericRepository<T,ID extends Serializable> extends JpaRepository<T, ID> { 

    @Query("select t from T t where t.title = :TITLE") 
    T findByTitle(@Param("TITLE") String title); 

} 

import org.springframework.stereotype.Repository; 

import tn.moussi.entities.Post; 

@Repository("postRepository") 
public interface PostRepository extends GenericRepository< Post, Integer> { 


} 

单元测试:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = "classpath:META-INF/application-context.xml") 
public class PostRepositorytest { 


    @Autowired 
    @Qualifier(value="postRepository") 
    PostRepository repository; 

    @Test 
    public void test() { 
     Post post = new Post(); 
     post.setPostDate(new Date()); 
     post.setTitle("first post"); 

     repository.save(post); 

     Post dbpost = repository.findByTitle(post.getTitle()); 
     assertNotNull(dbpost); 
     System.out.println(dbpost.getTitle()); 

    } 

} 

实体类发表:

@Entity 
@Table(name="POST") 
public class Post{ 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="POST_ID") 
    Integer postId; 

    @Column(name="TITLE") 
    String title; 
    @Column(name="POST_DATE") 
    Date postDate; 

    public Integer getPostId() { 
     return postId; 
    } 
    public void setPostId(Integer postId) { 
     this.postId = postId; 
    } 
    public String getTitle() { 
     return title; 
    } 
    public void setTitle(String title) { 
     this.title = title; 
    } 
    public Date getPostDate() { 
     return postDate; 
    } 
    public void setPostDate(Date postDate) { 
     this.postDate = postDate; 
    } 
} 

的应用上下文文件

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" 
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> 

<!-- database --> 
<jdbc:embedded-database id="datasource" type="H2"></jdbc:embedded-database> 

<!-- Entity manager --> 
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="datasource"/> 
     <property name="persistenceUnitName" value="moussi-tutorial"/> 
</bean> 

<!-- Transaction Manager --> 
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 

<!-- Jap repositories --> 
<jpa:repositories base-package="tn.moussi"></jpa:repositories> 

<context:annotation-config/> 
    <context:component-scan base-package="tn.moussi" /> 

</beans> 

persistence.xml文件:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> 

    <persistence-unit name="moussi-tutorial" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 

    <properties> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> 
     <property name="hibernate.hbm2ddl.auto" value="create-drop"/> 
     <property name="hibernate.show_sql" value="true"/> 
     </properties> 
    </persistence-unit> 

</persistence> 
+0

http://stackoverflow.com/questions/7914363/injection-of-autowired-dependencies-failed如果使用Spring 3.1或更高版本,尝试将此添加到您的unitTest @ComponentScan(“tn.moussi”) – freshbm 2013-03-21 10:11:30

+0

您是否在使用一个教程?我不确定这是可能的。 – 2013-03-21 10:16:31

+0

不,我在一个现有的项目中运行,而不是从一个教程 – 2013-03-21 10:44:33

回答

0

我不确定这是可能的。问题是通用参数T对于每个接口都不相同。在您的@Query中,T在注释的值元素select t from T...中静态定义。在普通的JPA查询中,实体的类型将在查询中指定。就像如下:

@Query("select t from Book t where t.title = :TITLE") 
Book findByTitle(@Param("TITLE") String title); 

如果扩展接口被允许,春数据将需要足够的智慧来确定泛型参数T在运行时(其类型是针对与仿制药的谷物,因为大多数操作是编译时)。然后,它需要将此类型替换为@Query批注的值元素中的静态定义的查询。我还没有看到有证据表明这是可能的。

+0

通用方法在多个接口中多次使用。 我想多次优化开发不重复的方法。 是这个方向上有溶液吗? – 2013-03-21 10:45:43

+0

@ user2194541我不能肯定地说,但我不认为有解决方案或至少有一个使用您的方法。我在Oliver Geirke(Spring)发布了这个消息,也许我们会得到一些意见。 – 2013-03-21 10:54:37

+0

非常感谢。我希望:) – 2013-03-21 10:58:09

0

我可能会想这是因为你的JPA提供者无法处理查询您的GenericRepository接口:

select t from T t where t.title = :TITLE 

为了了解这是否是一个根本原因还是没有 - 尝试引入另一findByTitle2方法在PostRepository,解决了明确命名的实体:

@Query("select t from Post t where t.title = :TITLE") 
T findByTitle(@Param("TITLE") String title); 

注意,与以下报告您的堆栈跟踪此地址10

QuerySyntaxException: T is not mapped [select t from T t where t.title = :TITLE] 

我不知道这样的查询参数select t from T t where t.title = :TITLE是否可能在所有的 - 因为在Java泛型实现细节的并不总是能够提取出正确的参数化类型信息在运行时决定什么类型是在一定的使用点你的应用程序。

+0

我添加了@Query(“选择t从邮政t where t.title =:TITLE”) T findByTitle(@Param(“TITLE”)String title);到我的PostRepository,它的作品。我应该使用哪个提供者来检测泛型? – 2013-03-21 10:55:17

+0

,因为泛型方法使用的次数超过15次,我只想开发它一次 – 2013-03-21 10:56:16

+0

您可能希望在不使用spring-data-jpa的情况下通过使用JPA Criteria API来完成它,该API非常适合需要构建复杂查询。 – Alex 2013-03-21 11:49:47

1

这不会像你期望的那样工作。虽然具体类继承了方法,并允许我们在运行时查找具体的返回类型,但我们没有(不能)为手动定义的查询做任何泛型替换。这是因为基本上没有办法找出你是否真的在查询中引用了泛型类型(阅读:查询中的T可能本质上意味着什么,只是查看查询)。

您拥有的选项是为每个具体类型的T引入专用命名查询,如TypeA.findByTitleTypeB.findByTitle等。然后我们将使用这些来支持继承到具体存储库接口的方法。此外,您可能想要使用@NoRepositoryBean注释GenericRepository接口,以防止在组件扫描期间拾取接口。阅读关于reference documentation的详细信息。

+0

感谢您的解释,甚至认为我不是原始的海报。你提到的具体返回类型可以在运行时确定,是由于继承?这将允许你使用反射:'(ParameterizedType)getClass()。getGenericSuperclass())。getActualTypeArguments()[0];' – 2013-03-21 12:07:26

+0

谢谢你Oliver的解释,我将删除@query注释,参考文档来解决问题 – 2013-03-21 12:23:52

相关问题