2013-03-21 2 views
2

Я попытался использовать Spring Data jpa с помощью генериков, но одно и то же исключение обрабатывается при выполнении модульного теста. здесь является исключением:Не удалось использовать поле autowire при модульном тестировании

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:

импорт java.io.Serializable;

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 Попробуйте добавить это в свой unitTest @ComponentScan ("tn.moussi"), если используете Spring 3.1 или новее – freshbm

+0

Вы работаете в учебник? Я не уверен, что это возможно. –

+0

no Я запускаю это в существующем проекте не из учебника –

ответ

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

общий метод используется несколько раз в нескольких интерфейсах. Я хочу оптимизировать разработку, чтобы не повторять метод несколько раз. заключается в том, что в этом направлении есть сокращение? –

+0

@ user2194541 Я не могу сказать точно, но я не думаю, что есть решение или, по крайней мере, один, использующий ваш подход. Я написал твиттер в Oliver Geirke (Spring), может быть, мы получим некоторый вклад. –

+0

большое спасибо. я надеюсь, что :) –

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); 

Обратите внимание, что ваше StackTrace адрес с помощью следующего отчета:

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 from Post t, где t.title =: TITLE») T findByTitle (@Param («TITLE») Название строки); к моему PostRepository и он работает. какой провайдер должен использовать для обнаружения дженериков? –

+0

, потому что общий метод используется в несколько раз больше, чем 15, я хочу его развить только один раз –

+0

Возможно, вы захотите сделать это без spring-data-jpa с помощью API JPA Criteria API, который идеально подходит для задач, требующих создания сложного запрос. – Alex

1

Это не сработает, как вы ожидаете. Хотя конкретные классы наследуют метод и позволяют нам узнать о конкретном типе возврата во время выполнения, мы не можем (не можем) выполнять любые генерические замены для заданных вручную запросов. Причина этого в том, что по существу нет способа узнать о том, действительно ли вы ссылаетесь на генерический тип из запроса (прочитайте: T в вашем запросе может означать что угодно, просто посмотрев на запрос).

Опция, которую вы имеете, представляет собой специализированные именованные запросы для каждого конкретного типа T, такие как TypeA.findByTitle, TypeB.findByTitle и так далее. Затем мы будем использовать их для возврата метода, унаследованного в конкретные интерфейсы репозитория. Кроме того, вы можете захотеть аннотировать интерфейс GenericRepository с помощью @NoRepositoryBean, чтобы предотвратить его захват при сканировании компонентов. Ознакомьтесь с деталями об этом в reference documentation.

+0

Спасибо за объяснение, даже подумал, что я не оригинальный плакат. Вы упомянули, что конкретный тип возвращаемого значения может быть определен во время выполнения, является ли это наследованием? Который позволит вам использовать отражение, например: '(ParameterizedType) getClass(). GetGenericSuperclass()). GetActualTypeArguments() [0];' –

+0

Поблагодарите Оливера за объяснение, я удалю аннотацию @query, и я буду следовать справочная документация для решения проблемы –