2013-03-21 43 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

相關問題