spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.93k stars 1.39k forks source link

SimpleJpaRepository.delete(Specification<T> spec) throws NullPointerException [Kotlin] #3439

Closed ASaludo closed 2 months ago

ASaludo commented 2 months ago

Hello,

I have a problem using JpaSpecificationExecutor.delete using a Specification Object

I'm using Kotlin and the @Nullable on top of the toPredicate function of Specification used line 477 with the null parameter of query seemed to be the problem

java.lang.NullPointerException: Parameter specified as non-null is null: ... at org.springframework.data.jpa.repository.support.SimpleJpaRepository.delete(SimpleJpaRepository.java:477)

christophstrobl commented 2 months ago

Thanks for reporting. Care to give us a bit more context of what you're trying to archive? I do see a potential nullability contract violation with Specification#toPredicate when no CriteriaQuery is present due to CriteriaBuilder#createCriteriaDelete(Class) not implementing it.

ASaludo commented 2 months ago

I'll give you all details : Spring-jata-jpa : 3.2.5 Kotlin : 1.9.23

I'm trying to play this code :

    fun isToDelete(): Specification<Request> {
        return Specification<Entity> { root, _, builder ->
            LocalDateTime.now().minusDays(120)?.let { builder.lessThanOrEqualTo(root.get("date"), it) }
        }
    }
    fun delete() = entityRepository.delete(isToDelete())

But on the code of SimpleJpaRepository that implement the JpaSpecificationExecutor I hit the following line of code :

Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);`

with that interface :

    @Nullable
    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

I suspect that Kotlin don't take @Nullable when compiling those java class and a NPE happen because "null" is literally passed to a non null parameter.

mp911de commented 2 months ago

That's a shortcoming of the Specification vs. Criteria Query design. Specifications have been designed for select queries and at some point, we enabled these for delete usage. We cannot provide a CriteriaQuery as CriteriaDelete isn't assignable into it. It's a duplicate of #3036.

At some point, we need to revisit our arrangement and find a path forward.

gbrehmer commented 1 week ago

this means delete(spec) is currently not supported with kotlin or is there any known workaround?