Skip to content

Query by enum throws NPE #1817

@ask4gilles

Description

@ask4gilles

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()
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions