From 4c17e295ab9361ab55a35d2dc1bdc124abf64387 Mon Sep 17 00:00:00 2001 From: Sebastian Staudt Date: Wed, 24 Oct 2018 06:37:52 +0200 Subject: [PATCH] DATAJPA-1449 - Removal of `Specifications`. `Specifications` is deprecated since 2.0. This removes it completely. * Moves static helper code into a private helper class. * Removes references to `Specifications` from `Specification`. Original pull request: #300. --- .../data/jpa/domain/Specification.java | 14 +- .../jpa/domain/SpecificationComposition.java | 56 +++++++ .../data/jpa/domain/Specifications.java | 153 ------------------ .../jpa/domain/SpecificationsUnitTests.java | 145 ----------------- 4 files changed, 64 insertions(+), 304 deletions(-) create mode 100644 src/main/java/org/springframework/data/jpa/domain/SpecificationComposition.java delete mode 100644 src/main/java/org/springframework/data/jpa/domain/Specifications.java delete mode 100644 src/test/java/org/springframework/data/jpa/domain/SpecificationsUnitTests.java diff --git a/src/main/java/org/springframework/data/jpa/domain/Specification.java b/src/main/java/org/springframework/data/jpa/domain/Specification.java index 271b5facb..d7c87573d 100644 --- a/src/main/java/org/springframework/data/jpa/domain/Specification.java +++ b/src/main/java/org/springframework/data/jpa/domain/Specification.java @@ -15,7 +15,8 @@ */ package org.springframework.data.jpa.domain; -import static org.springframework.data.jpa.domain.Specifications.CompositionType.*; +import static org.springframework.data.jpa.domain.SpecificationComposition.*; +import static org.springframework.data.jpa.domain.SpecificationComposition.CompositionType.*; import java.io.Serializable; @@ -35,11 +36,12 @@ import org.springframework.lang.Nullable; * @author Sebastian Staudt * @author Mark Paluch */ -@SuppressWarnings("deprecation") public interface Specification extends Serializable { long serialVersionUID = 1L; + Specification EMPTY_SPEC = (root, query, criteriaBuilder) -> null; + /** * Negates the given {@link Specification}. * @@ -49,7 +51,7 @@ public interface Specification extends Serializable { * @since 2.0 */ static Specification not(Specification spec) { - return Specifications.negated(spec); + return negated(spec); } /** @@ -61,7 +63,7 @@ public interface Specification extends Serializable { * @since 2.0 */ static Specification where(Specification spec) { - return Specifications.where(spec); + return spec == null ? EMPTY_SPEC : spec; } /** @@ -72,7 +74,7 @@ public interface Specification extends Serializable { * @since 2.0 */ default Specification and(Specification other) { - return Specifications.composed(this, other, AND); + return composed(this, other, AND); } /** @@ -83,7 +85,7 @@ public interface Specification extends Serializable { * @since 2.0 */ default Specification or(Specification other) { - return Specifications.composed(this, other, OR); + return composed(this, other, OR); } /** diff --git a/src/main/java/org/springframework/data/jpa/domain/SpecificationComposition.java b/src/main/java/org/springframework/data/jpa/domain/SpecificationComposition.java new file mode 100644 index 000000000..e8cc266f4 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/domain/SpecificationComposition.java @@ -0,0 +1,56 @@ +package org.springframework.data.jpa.domain; + +import org.springframework.lang.Nullable; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Predicate; + +/** + * Helper class to support specification compositions + * + * @author Sebastian Staudt + * @see Specification + */ +class SpecificationComposition { + + /** + * Enum for the composition types for {@link Predicate}s. Can not be turned into lambdas as we need to be + * serializable. + * + * @author Thomas Darimont + */ + enum CompositionType { + + AND { + @Override + public Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs) { + return builder.and(lhs, rhs); + } + }, + + OR { + @Override + public Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs) { + return builder.or(lhs, rhs); + } + }; + + abstract Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs); + } + + static Specification negated(@Nullable Specification spec) { + return (root, query, builder) -> spec == null ? null : builder.not(spec.toPredicate(root, query, builder)); + } + + static Specification composed(@Nullable Specification lhs, @Nullable Specification rhs, CompositionType compositionType) { + + return (root, query, builder) -> { + + Predicate otherPredicate = rhs == null ? null : rhs.toPredicate(root, query, builder); + Predicate thisPredicate = lhs == null ? null : lhs.toPredicate(root, query, builder); + + return thisPredicate == null ? otherPredicate + : otherPredicate == null ? thisPredicate : compositionType.combine(builder, thisPredicate, otherPredicate); + }; + } +} diff --git a/src/main/java/org/springframework/data/jpa/domain/Specifications.java b/src/main/java/org/springframework/data/jpa/domain/Specifications.java deleted file mode 100644 index a910e5a4e..000000000 --- a/src/main/java/org/springframework/data/jpa/domain/Specifications.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2008-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.jpa.domain; - -import static org.springframework.data.jpa.domain.Specifications.CompositionType.*; - -import java.io.Serializable; - -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; - -import org.springframework.lang.Nullable; - -/** - * Helper class to easily combine {@link Specification} instances. - * - * @author Oliver Gierke - * @author Thomas Darimont - * @author Sebastian Staudt - * @author Mark Paluch - * @deprecated since 2.0, use factory methods on {@link Specification} instead. - */ -@Deprecated -public class Specifications implements Specification, Serializable { - - private static final long serialVersionUID = 1L; - - private final @Nullable Specification spec; - - /** - * Creates a new {@link Specifications} wrapper for the given {@link Specification}. - * - * @param spec can be {@literal null}. - */ - Specifications(@Nullable Specification spec) { - this.spec = spec; - } - - /** - * Simple static factory method to add some syntactic sugar around a {@link Specification}. - * - * @deprecated since 2.0, use {@link Specification#where} instead - * @param type parameter for the specification parameter. - * @param spec can be {@literal null}. - * @return a new Specifcations instance. Guaranteed to be not {@code null}. - */ - @Deprecated - public static Specifications where(@Nullable Specification spec) { - return new Specifications<>(spec); - } - - /** - * ANDs the given {@link Specification} to the current one. - * - * @deprecated since 2.0, use {@link Specification#and} instead - * @param other can be {@literal null}. - * @return a new Specifications instance combining this and the parameter instance. Guaranteed to be not {@code null}. - */ - @Deprecated - public Specifications and(@Nullable Specification other) { - return new Specifications<>(composed(spec, other, AND)); - } - - /** - * ORs the given specification to the current one. - * - * @deprecated since 2.0, use {@link Specification#or} instead - * @param other can be {@literal null}. - * @return a new Specifications instance combining this and the parameter instance. Guaranteed to be not {@code null}. - */ - @Deprecated - public Specifications or(@Nullable Specification other) { - return new Specifications<>(composed(spec, other, OR)); - } - - /** - * Negates the given {@link Specification}. - * - * @deprecated since 2.0, use {@link Specification#not} instead - * @param type parameter for the specification parameter. - * @param spec can be {@literal null}. - * @return a new Specifications instance combining this and the parameter instance. Guaranteed to be not {@code null}. - */ - @Deprecated - public static Specifications not(@Nullable Specification spec) { - return new Specifications<>(negated(spec)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.jpa.domain.Specification#toPredicate(javax.persistence.criteria.Root, javax.persistence.criteria.CriteriaQuery, javax.persistence.criteria.CriteriaBuilder) - */ - @Nullable - public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder builder) { - return spec == null ? null : spec.toPredicate(root, query, builder); - } - - /** - * Enum for the composition types for {@link Predicate}s. Can not be turned into lambdas as we need to be - * serializable. - * - * @author Thomas Darimont - */ - enum CompositionType { - - AND { - @Override - public Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs) { - return builder.and(lhs, rhs); - } - }, - - OR { - @Override - public Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs) { - return builder.or(lhs, rhs); - } - }; - - abstract Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs); - } - - static Specification negated(@Nullable Specification spec) { - return (root, query, builder) -> spec == null ? null : builder.not(spec.toPredicate(root, query, builder)); - } - - static Specification composed(@Nullable Specification lhs, @Nullable Specification rhs, CompositionType compositionType) { - - return (root, query, builder) -> { - - Predicate otherPredicate = rhs == null ? null : rhs.toPredicate(root, query, builder); - Predicate thisPredicate = lhs == null ? null : lhs.toPredicate(root, query, builder); - - return thisPredicate == null ? otherPredicate - : otherPredicate == null ? thisPredicate : compositionType.combine(builder, thisPredicate, otherPredicate); - }; - } -} diff --git a/src/test/java/org/springframework/data/jpa/domain/SpecificationsUnitTests.java b/src/test/java/org/springframework/data/jpa/domain/SpecificationsUnitTests.java deleted file mode 100644 index c2e6861a7..000000000 --- a/src/test/java/org/springframework/data/jpa/domain/SpecificationsUnitTests.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.jpa.domain; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.jpa.domain.Specifications.*; -import static org.springframework.util.SerializationUtils.*; - -import java.io.Serializable; - -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * @author Oliver Gierke - * @author Thomas Darimont - */ -@RunWith(MockitoJUnitRunner.class) -public class SpecificationsUnitTests { - - Specification mockSpec; - @Mock(extraInterfaces = Serializable.class) Root root; - @Mock(extraInterfaces = Serializable.class) CriteriaQuery query; - @Mock(extraInterfaces = Serializable.class) CriteriaBuilder builder; - - @Mock(extraInterfaces = Serializable.class) Predicate predicate; - - @Before - @SuppressWarnings("unchecked") - public void setUp() { - - mockSpec = (Specification) mock(Specification.class, withSettings().serializable()); - - when(mockSpec.toPredicate(root, query, builder)).thenReturn(predicate); - } - - @Test // DATAJPA-300 - public void createsSpecificationsFromNull() { - - Specifications specification = where(null); - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(nullValue())); - } - - @Test // DATAJPA-300 - public void negatesNullSpecToNull() { - - Specifications specification = not((Specification) null); - - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(nullValue())); - } - - @Test // DATAJPA-300 - public void andConcatenatesSpecToNullSpec() { - - Specifications specification = where(null); - specification = specification.and(mockSpec); - - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(predicate)); - } - - @Test // DATAJPA-300 - public void andConcatenatesNullSpecToSpec() { - - Specifications specification = where(mockSpec); - specification = specification.and(null); - - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(predicate)); - } - - @Test // DATAJPA-300 - public void orConcatenatesSpecToNullSpec() { - - Specifications specification = where(null); - specification = specification.or(mockSpec); - - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(predicate)); - } - - @Test // DATAJPA-300 - public void orConcatenatesNullSpecToSpec() { - - Specifications specification = where(mockSpec); - specification = specification.or(null); - - assertThat(specification, is(notNullValue())); - assertThat(specification.toPredicate(root, query, builder), is(predicate)); - } - - @Test // DATAJPA-523 - public void specificationsShouldBeSerializable() { - - Specifications specification = where(mockSpec); - specification = specification.and(mockSpec); - - assertThat(specification, is(notNullValue())); - - @SuppressWarnings("unchecked") - Specifications transferedSpecification = (Specifications) deserialize(serialize(specification)); - - assertThat(transferedSpecification, is(notNullValue())); - } - - @Test // DATAJPA-523 - public void complexSpecificationsShouldBeSerializable() { - - Specifications specification = where(mockSpec); - specification = Specifications.not(specification.and(mockSpec).or(mockSpec)); - - assertThat(specification, is(notNullValue())); - - @SuppressWarnings("unchecked") - Specifications transferedSpecification = (Specifications) deserialize(serialize(specification)); - - assertThat(transferedSpecification, is(notNullValue())); - } - -}