Skip to content

NullPointerException in Query.setParameter(…) binding null to IN parameters #4112

@AntipovAndrey

Description

@AntipovAndrey

When upgrading from Spring Boot 3.x to 4.0.0, a NullPointerException is thrown if an empty collection of entities is passed to a repository method that uses an IN clause.

@SpringBootApplication
class Runner(
  private val parentRepository: ParentRepository,
) : ApplicationRunner {
  override fun run(args: ApplicationArguments) {
    parentRepository.findByChildIn(ArrayList()) // <----  Cannot invoke "Object.getClass()" because "value" is null
  }
}

@Repository
interface ParentRepository : JpaRepository<ParentEntity, UUID> {
  fun findByChildIn(children: List<ChildEntity>): ParentEntity?
}

This used to work fine with Spring Boot 3.x.
With Spring Boot 4.0.0 it fails.

From what I can see, this is caused by the following Hibernate issue: https://hibernate.atlassian.net/browse/HHH-19926

Environment

Spring Boot: 4.0.0
Spring Data JPA: 4.0.0
Hibernate: 7.1.8
JDK: 21

Full stacktrace:

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "value" is null
	at org.hibernate.type.descriptor.java.spi.EntityJavaType.isInstance(EntityJavaType.java:54) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.spi.AbstractCommonQueryContract.isInstance(AbstractCommonQueryContract.java:829) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.spi.AbstractCommonQueryContract.multipleBinding(AbstractCommonQueryContract.java:811) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.spi.AbstractCommonQueryContract.setParameter(AbstractCommonQueryContract.java:795) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.setParameter(AbstractSelectionQuery.java:636) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.sqm.internal.SqmQueryImpl.setParameter(SqmQueryImpl.java:1069) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.hibernate.query.sqm.internal.SqmQueryImpl.setParameter(SqmQueryImpl.java:120) ~[hibernate-core-7.1.8.Final.jar:7.1.8.Final]
	at org.springframework.data.jpa.repository.query.QueryParameterSetter$BindableQuery.setParameter(QueryParameterSetter.java:303) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.QueryParameterSetter$NamedOrIndexedQueryParameterSetter.setParameter(QueryParameterSetter.java:107) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.QueryParameterSetter$NamedOrIndexedQueryParameterSetter.setParameter(QueryParameterSetter.java:95) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:87) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:79) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:100) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.invokeBinding(PartTreeJpaQuery.java:364) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:247) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:122) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:264) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:328) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:99) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:164) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:154) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:169) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:167) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:146) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:69) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:370) ~[spring-tx-7.0.1.jar:7.0.1]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-7.0.1.jar:7.0.1]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:135) ~[spring-tx-7.0.1.jar:7.0.1]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:137) ~[spring-data-jpa-4.0.0.jar:4.0.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.data.util.NullnessMethodInvocationValidator.invoke(NullnessMethodInvocationValidator.java:99) ~[spring-data-commons-4.0.0.jar:4.0.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-7.0.1.jar:7.0.1]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:222) ~[spring-aop-7.0.1.jar:7.0.1]
	at jdk.proxy2/jdk.proxy2.$Proxy126.findByChildIn(Unknown Source) ~[na:na]
	at com.jetbrains.demo.Runner.run(SpringBoot4Application.kt:25) ~[main/:na]
	at org.springframework.boot.SpringApplication.lambda$callRunner$0(SpringApplication.java:797) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:82) ~[spring-core-7.0.1.jar:7.0.1]
	at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-7.0.1.jar:7.0.1]
	at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:86) ~[spring-core-7.0.1.jar:7.0.1]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.boot.SpringApplication.lambda$callRunners$0(SpringApplication.java:785) ~[spring-boot-4.0.0.jar:4.0.0]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
	at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:785) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:328) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1374) ~[spring-boot-4.0.0.jar:4.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-4.0.0.jar:4.0.0]
	at com.jetbrains.demo.SpringBoot4ApplicationKt.main(SpringBoot4Application.kt:65) ~[main/:na]

Entities definitions

@Entity
@Table(name = "parent_table")
class ParentEntity(
  val name: String
) {

  @ManyToOne
  @JoinColumn(name = "child_id")
  lateinit var child: ChildEntity

  @Id
  @GeneratedValue
  @UuidGenerator
  lateinit var id: UUID
}

@Entity
@Table(name = "child_table")
class ChildEntity(
  val label: String
) {
  @Id
  @GeneratedValue
  @UuidGenerator
  lateinit var id: UUID
}

build.gradle.kts

plugins {
  kotlin("jvm") version "2.2.21"
  kotlin("plugin.spring") version "2.2.21"
  kotlin("plugin.jpa") version "2.2.21"
  id("org.springframework.boot") version "4.0.0"
  id("io.spring.dependency-management") version "1.1.7"
}

group = "com.jetbrains"
version = "0.0.1-SNAPSHOT"
description = "spring-boot-4"

java {
  toolchain {
    languageVersion = JavaLanguageVersion.of(21)
  }
}

repositories {
  mavenCentral()
}

dependencies {
  implementation("org.springframework.boot:spring-boot-starter-webmvc")
  implementation("org.springframework.boot:spring-boot-starter-data-jpa")
  runtimeOnly("org.postgresql:postgresql")

  implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
  implementation("org.jetbrains.kotlin:kotlin-reflect")
  testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
  testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
  testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

kotlin {
  compilerOptions {
    freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
  }
}

tasks.withType<Test> {
  useJUnitPlatform()
}

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions