-
Notifications
You must be signed in to change notification settings - Fork 100
Description
Description
NPE in 1.6.9 / hibernate 6.2.13 for query by enum
Hi,
Following up after Zulip chat.
For a query filtering by enum, using spring data JPA, like:
int countEntitiesByStatus(Status status);
Status being an enum.
I get:
java.lang.NullPointerException: null
at java.base/java.lang.Class.isAssignableFrom(Native Method)
at com.blazebit.persistence.spring.data.impl.query.ParameterMetadataProviderImpl$ParameterMetadataImpl.prepare(ParameterMetadataProviderImpl.java:265)
at com.blazebit.persistence.spring.data.base.query.AbstractCriteriaQueryParameterBinder.bind(AbstractCriteriaQueryParameterBinder.java:79)
at com.blazebit.persistence.spring.data.base.query.ParameterBinder.bind(ParameterBinder.java:106)
at com.blazebit.persistence.spring.data.base.query.AbstractPartTreeBlazePersistenceQuery$CountQueryPreparer.invokeBinding(AbstractPartTreeBlazePersistenceQuery.java:540)
at com.blazebit.persistence.spring.data.base.query.AbstractPartTreeBlazePersistenceQuery$QueryPreparer.createQuery(AbstractPartTreeBlazePersistenceQuery.java:443)
at com.blazebit.persistence.spring.data.base.query.AbstractPartTreeBlazePersistenceQuery.doCreateQuery(AbstractPartTreeBlazePersistenceQuery.java:165)
at com.blazebit.persistence.spring.data.impl.query.PartTreeBlazePersistenceQuery.doCreateQuery(PartTreeBlazePersistenceQuery.java:195)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:239)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:223)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:149)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:137)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:72)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at com.blazebit.persistence.spring.data.repository.EntityViewReplacingMethodInterceptor.invoke(EntityViewReplacingMethodInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at com.blazebit.persistence.spring.data.base.repository.EntityViewAwareCrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(EntityViewAwareCrudMethodMetadataPostProcessor.java:143)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
at jdk.proxy2/jdk.proxy2.$Proxy199.countBundleEntitiesByStatus(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
It seems that the javatype can't be determine for enum types.
org.hibernate.query.sqm.tree.expression.AbstractSqmExpression#getJavaTypeDescriptor
returns null.
If I only pull the hibernate dependencies, everything looks good.
It only breaks when adding the BP deps and config
Expected behavior
It works on my machine! ;)
(Query executes without crashing)
Actual behavior
It doesn't work on my machine! ;)
(I get a NPE)
Steps to reproduce
Execute Unit test
Environment
Context: SB 3.1.5, Blaze persistence 1.6.9, Hibernate 6.2.13.
Version: 1.6.9
JPA-Provider: Spring-data
DBMS: Any
Application Server: Tomcat
I'm very sorry but I can't upload anything in my current env...Hence this C/P of classes... :/
package com.example.hibernatereproducer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HibernateReproducerApplication {
public static void main(String[] args) {
SpringApplication.run(HibernateReproducerApplication.class, args);
}
}
package com.example.hibernatereproducer;
import java.util.UUID;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "ENTITY")
public class MyEntity {
@Id
private UUID id;
@Column(name = "STATUS")
@Enumerated(EnumType.STRING)
private MyEntityStatus status;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
package com.example.hibernatereproducer;
public enum MyEntityStatus {
OK,
KO
}
package com.example.hibernatereproducer;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, UUID> {
int countMyEntitiesByStatus(MyEntityStatus status);
}
package com.example.hibernatereproducer;
import com.blazebit.persistence.Criteria;
import com.blazebit.persistence.CriteriaBuilderFactory;
import com.blazebit.persistence.integration.view.spring.EnableEntityViews;
import com.blazebit.persistence.spi.CriteriaBuilderConfiguration;
import com.blazebit.persistence.spring.data.impl.repository.BlazePersistenceRepositoryFactoryBean;
import com.blazebit.persistence.view.ConfigurationProperties;
import com.blazebit.persistence.view.EntityViewManager;
import com.blazebit.persistence.view.spi.EntityViewConfiguration;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.hibernatereproducer", repositoryFactoryBeanClass =
BlazePersistenceRepositoryFactoryBean.class)
@EnableEntityViews("com.example.hibernatereproducer")
public class PersistenceConfig {
@Bean
@Lazy(false)
public CriteriaBuilderFactory criteriaBuilderFactory(EntityManagerFactory entityManagerFactory) {
CriteriaBuilderConfiguration config = Criteria.getDefault();
return config.createCriteriaBuilderFactory(entityManagerFactory);
}
@Bean
@Lazy(false)
public EntityViewManager entityViewManager(CriteriaBuilderFactory criteriaBuilderFactory,
EntityViewConfiguration entityViewConfiguration) {
entityViewConfiguration.setProperty(ConfigurationProperties.PAGINATION_FORCE_USE_KEYSET, "true");
entityViewConfiguration.setProperty(ConfigurationProperties.PAGINATION_EXTRACT_ALL_KEYSETS, "true");
entityViewConfiguration.setProperty(ConfigurationProperties.PROXY_EAGER_LOADING, "true");
entityViewConfiguration.setProperty(ConfigurationProperties.MANAGED_TYPE_VALIDATION_DISABLED, "true");
return entityViewConfiguration.createEntityViewManager(criteriaBuilderFactory);
}
}
package com.example.hibernatereproducer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class HibernateReproducerApplicationTests {
@Autowired
private MyEntityRepository repository;
@Test
void countByStatus() {
assertThat(repository.countMyEntitiesByStatus(MyEntityStatus.OK)).isEqualTo(0);
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.5'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "com.blazebit:blaze-persistence-core-api-jakarta:1.6.9"
implementation "com.blazebit:blaze-persistence-core-impl-jakarta:1.6.9"
implementation "com.blazebit:blaze-persistence-integration-spring-data-webmvc-jakarta:1.6.9"
implementation "com.blazebit:blaze-persistence-integration-hibernate-6.2:1.6.9"
implementation "com.blazebit:blaze-persistence-integration-spring-data-3.1:1.6.9"
implementation "com.blazebit:blaze-persistence-integration-spring-hateoas-webmvc-jakarta:1.6.9"
implementation "com.blazebit:blaze-persistence-entity-view-processor-jakarta:1.6.9"
implementation "com.blazebit:blaze-apt-utils:0.1.21"
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}