Spring 带有自定义 entityManagerFactory 和 Query 注释的 validateQuery 中的数据 JPA NPE
Spring data JPA NPE in validateQuery with custom entityManagerFactory and Query annotation
我正在使用 spring-boot-starter-parent 1.2.0.RELEASE 开发 Spring 引导项目。我正在尝试配置 spring 通过 spring SpringJtaSessionContext 扩展使用 Hibernate 的 JTASssionContext。
在我的 @Configuration
class 中,我返回配置的 JTA LocalContainerEntityManagerFactoryBean
。
@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = JpaRepositoryFactoryBean.class)
@EntityScan(basePackageClasses = Event.class)
public class JPAConfig {
@Autowired
private DataSource dataSource;
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setJtaDataSource( dataSource );
localContainerEntityManagerFactoryBean.setJpaVendorAdapter( jpaVendorAdapter );
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.current_session_context_class", "jta");
properties.put("javax.persistence.transactionType", "JTA");
properties.put( "hibernate.dialect", "org.hibernate.dialect.SQLServerDialect" );
properties.put( "hibernate.format_sql", "true" );
properties.put( "hibernate.ejb.naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy");
localContainerEntityManagerFactoryBean.setJpaPropertyMap( properties );
return localContainerEntityManagerFactoryBean;
}
}
一切似乎都已连接好,但我 运行 进入 org.springframework.data.jpa.repository.query.SimpleJpaQuery
内部的 NPE
/**
* Validates the given query for syntactical correctness.
*
* @param query
* @param em
*/
private final void validateQuery(String query, String errorMessage) {
if (getQueryMethod().isProcedureQuery()) {
return;
}
EntityManager validatingEm = null;
try {
validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager();
....
对 getEntityManager().getEntityManagerFactory().createEntityManager();
的调用导致 NPE 似乎来自 createEntityManager()
为 getEntityManager()
提供的 class 似乎是我在 JPAConfig 中定义的 LocalContainerEntityManagerFactoryBean
。提供的 EntityManagerFactory
似乎是 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
。好像 createEntityManager() 里面的东西是空的。
这导致以下堆栈跟踪
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract com.vnomicscorp.dw.model.Event com.vnomicscorp.dw.webservice.repo.EventRepository.findByCompositeKey(com.vnomicscorp.dw.model.Vehicle,com.vnomicscorp.dw.model.EventType,long)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:87)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:70)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:51)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:137)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:202)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:80)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:357)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:192)
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:1625)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
... 240 more
Caused by: java.lang.NullPointerException
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:76)
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:118)
at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:210)
at org.hibernate.jpa.internal.EntityManagerImpl.<init>(EntityManagerImpl.java:91)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.internalCreateEntityManager(EntityManagerFactoryImpl.java:345)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
at sun.reflect.GeneratedMethodAccessor48.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:388)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:541)
at com.sun.proxy.$Proxy76.createEntityManager(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:80)
... 253 more
由线引起的是指向这个方法反射调用
Object retVal = method.invoke(this.nativeEntityManagerFactory, args);
我还应该补充一点,我正在使用 Spring 数据休息并且还有 RepositoryRestMvcConfiguration
class。
@Configuration
public class RestRepoConfig extends RepositoryRestMvcConfiguration {
@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Employee.class, Vehicle.class, Customer.class, VehicleMake.class, VehicleModel.class, Event.class);
}
}
尝试使用添加的方法验证 PagingAndSortingRepository
时抛出 NPE。
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
@Query("SELECT e FROM Event AS e WHERE e.vehicle = :vehicle AND e.startTime <= :endTime AND e.endTime >= :startTime")
public Iterable<Event> findByTimeperiod(@Param("vehicle") Vehicle vehicle,
@Param("startTime") long startTime,
@Param("endTime") long endTime);
@Query("SELECT e FROM Event AS e WHERE e.vehicle = :vehicle AND e.eventType = :eventType AND e.startTime = :startTime")
public Event findByCompositeKey(@Param("vehicle") Vehicle vehicle,
@Param("eventType") EventType eventType,
@Param("startTime") long startTime);
}
Andy Wilkinson 的评论很到位。由于配置问题,问题是空事务管理器。
我正在使用 spring-boot-starter-parent 1.2.0.RELEASE 开发 Spring 引导项目。我正在尝试配置 spring 通过 spring SpringJtaSessionContext 扩展使用 Hibernate 的 JTASssionContext。
在我的 @Configuration
class 中,我返回配置的 JTA LocalContainerEntityManagerFactoryBean
。
@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = JpaRepositoryFactoryBean.class)
@EntityScan(basePackageClasses = Event.class)
public class JPAConfig {
@Autowired
private DataSource dataSource;
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setJtaDataSource( dataSource );
localContainerEntityManagerFactoryBean.setJpaVendorAdapter( jpaVendorAdapter );
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.current_session_context_class", "jta");
properties.put("javax.persistence.transactionType", "JTA");
properties.put( "hibernate.dialect", "org.hibernate.dialect.SQLServerDialect" );
properties.put( "hibernate.format_sql", "true" );
properties.put( "hibernate.ejb.naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy");
localContainerEntityManagerFactoryBean.setJpaPropertyMap( properties );
return localContainerEntityManagerFactoryBean;
}
}
一切似乎都已连接好,但我 运行 进入 org.springframework.data.jpa.repository.query.SimpleJpaQuery
/**
* Validates the given query for syntactical correctness.
*
* @param query
* @param em
*/
private final void validateQuery(String query, String errorMessage) {
if (getQueryMethod().isProcedureQuery()) {
return;
}
EntityManager validatingEm = null;
try {
validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager();
....
对 getEntityManager().getEntityManagerFactory().createEntityManager();
的调用导致 NPE 似乎来自 createEntityManager()
为 getEntityManager()
提供的 class 似乎是我在 JPAConfig 中定义的 LocalContainerEntityManagerFactoryBean
。提供的 EntityManagerFactory
似乎是 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
。好像 createEntityManager() 里面的东西是空的。
这导致以下堆栈跟踪
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract com.vnomicscorp.dw.model.Event com.vnomicscorp.dw.webservice.repo.EventRepository.findByCompositeKey(com.vnomicscorp.dw.model.Vehicle,com.vnomicscorp.dw.model.EventType,long)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:87)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:70)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:51)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:137)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:202)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:80)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:357)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:192)
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:1625)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
... 240 more
Caused by: java.lang.NullPointerException
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:76)
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:118)
at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:210)
at org.hibernate.jpa.internal.EntityManagerImpl.<init>(EntityManagerImpl.java:91)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.internalCreateEntityManager(EntityManagerFactoryImpl.java:345)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
at sun.reflect.GeneratedMethodAccessor48.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:388)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:541)
at com.sun.proxy.$Proxy76.createEntityManager(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:80)
... 253 more
由线引起的是指向这个方法反射调用
Object retVal = method.invoke(this.nativeEntityManagerFactory, args);
我还应该补充一点,我正在使用 Spring 数据休息并且还有 RepositoryRestMvcConfiguration
class。
@Configuration
public class RestRepoConfig extends RepositoryRestMvcConfiguration {
@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Employee.class, Vehicle.class, Customer.class, VehicleMake.class, VehicleModel.class, Event.class);
}
}
尝试使用添加的方法验证 PagingAndSortingRepository
时抛出 NPE。
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
@Query("SELECT e FROM Event AS e WHERE e.vehicle = :vehicle AND e.startTime <= :endTime AND e.endTime >= :startTime")
public Iterable<Event> findByTimeperiod(@Param("vehicle") Vehicle vehicle,
@Param("startTime") long startTime,
@Param("endTime") long endTime);
@Query("SELECT e FROM Event AS e WHERE e.vehicle = :vehicle AND e.eventType = :eventType AND e.startTime = :startTime")
public Event findByCompositeKey(@Param("vehicle") Vehicle vehicle,
@Param("eventType") EventType eventType,
@Param("startTime") long startTime);
}
Andy Wilkinson 的评论很到位。由于配置问题,问题是空事务管理器。