From 41bfd415caad3aa340b49e8e7ba45fe5d8bd45af Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 5 May 2025 14:13:17 +0200 Subject: [PATCH] Polishing. Add fix to Update, Delete, and PredicateSpecification. Reformat code. Refine tests. See #3849 Original pull request: #3856 --- .../data/jpa/domain/DeleteSpecification.java | 6 +++--- .../data/jpa/domain/PredicateSpecification.java | 6 +++--- .../data/jpa/domain/UpdateSpecification.java | 6 +++--- .../data/jpa/domain/DeleteSpecificationUnitTests.java | 11 +++++++++++ .../jpa/domain/PredicateSpecificationUnitTests.java | 11 +++++++++++ .../data/jpa/domain/UpdateSpecificationUnitTests.java | 11 +++++++++++ 6 files changed, 42 insertions(+), 9 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java index 32278c7ba..4c7deb638 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java @@ -24,9 +24,9 @@ import java.io.Serializable; import java.util.Arrays; import java.util.stream.StreamSupport; -import org.springframework.lang.CheckReturnValue; - import org.jspecify.annotations.Nullable; + +import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; import org.springframework.util.Assert; @@ -159,7 +159,7 @@ public interface DeleteSpecification extends Serializable { return (root, delete, builder) -> { Predicate predicate = spec.toPredicate(root, delete, builder); - return predicate != null ? builder.not(predicate) : null; + return predicate != null ? builder.not(predicate) : builder.disjunction(); }; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/PredicateSpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/PredicateSpecification.java index 5d9bd5106..daa39b9ba 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/PredicateSpecification.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/PredicateSpecification.java @@ -23,9 +23,9 @@ import java.io.Serializable; import java.util.Arrays; import java.util.stream.StreamSupport; -import org.springframework.lang.CheckReturnValue; - import org.jspecify.annotations.Nullable; + +import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; import org.springframework.util.Assert; @@ -113,7 +113,7 @@ public interface PredicateSpecification extends Serializable { return (root, builder) -> { Predicate predicate = spec.toPredicate(root, builder); - return predicate != null ? builder.not(predicate) : null; + return predicate != null ? builder.not(predicate) : builder.disjunction(); }; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/UpdateSpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/UpdateSpecification.java index 9b4b9f5e4..1a27d428a 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/UpdateSpecification.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/UpdateSpecification.java @@ -24,9 +24,9 @@ import java.io.Serializable; import java.util.Arrays; import java.util.stream.StreamSupport; -import org.springframework.lang.CheckReturnValue; - import org.jspecify.annotations.Nullable; + +import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; import org.springframework.util.Assert; @@ -180,7 +180,7 @@ public interface UpdateSpecification extends Serializable { return (root, update, builder) -> { Predicate predicate = spec.toPredicate(root, update, builder); - return predicate != null ? builder.not(predicate) : null; + return predicate != null ? builder.not(predicate) : builder.disjunction(); }; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/DeleteSpecificationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/DeleteSpecificationUnitTests.java index 02e59fa2d..8dfcb33ba 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/DeleteSpecificationUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/DeleteSpecificationUnitTests.java @@ -160,6 +160,17 @@ class DeleteSpecificationUnitTests implements Serializable { verify(builder).or(firstPredicate, secondPredicate); } + @Test // GH-3849 + void notWithNullPredicate() { + + when(builder.disjunction()).thenReturn(mock(Predicate.class)); + + DeleteSpecification notSpec = DeleteSpecification.not((r, q, cb) -> null); + + assertThat(notSpec.toPredicate(root, delete, builder)).isNotNull(); + verify(builder).disjunction(); + } + static class SerializableSpecification implements Serializable, DeleteSpecification { @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/PredicateSpecificationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/PredicateSpecificationUnitTests.java index f0cd8ca08..d11d61d0a 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/PredicateSpecificationUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/PredicateSpecificationUnitTests.java @@ -158,6 +158,17 @@ class PredicateSpecificationUnitTests implements Serializable { verify(builder).or(firstPredicate, secondPredicate); } + @Test // GH-3849 + void notWithNullPredicate() { + + when(builder.disjunction()).thenReturn(mock(Predicate.class)); + + PredicateSpecification notSpec = PredicateSpecification.not((r, cb) -> null); + + assertThat(notSpec.toPredicate(root, builder)).isNotNull(); + verify(builder).disjunction(); + } + static class SerializableSpecification implements Serializable, PredicateSpecification { @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/UpdateSpecificationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/UpdateSpecificationUnitTests.java index 540cc91e4..61c788d14 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/UpdateSpecificationUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/UpdateSpecificationUnitTests.java @@ -160,6 +160,17 @@ class UpdateSpecificationUnitTests implements Serializable { verify(builder).or(firstPredicate, secondPredicate); } + @Test // GH-3849 + void notWithNullPredicate() { + + when(builder.disjunction()).thenReturn(mock(Predicate.class)); + + UpdateSpecification notSpec = UpdateSpecification.not((r, q, cb) -> null); + + assertThat(notSpec.toPredicate(root, update, builder)).isNotNull(); + verify(builder).disjunction(); + } + static class SerializableSpecification implements Serializable, UpdateSpecification { @Override