From 26f725be0df69abccbd64e61f7a84f418ad7b9f2 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 2 Mar 2016 12:00:37 +0100 Subject: [PATCH] DATACMNS-810 - Polishing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed ExampleSpecification to ExampleMatcher and introduced a matching() factory method, dropping the dedicated override mechanism for types for now. Updated documentation accordingly. Used Lombok for constructor creation, field defaults, toString() as well as equals(…) and hashCode() implementations. Tweaked imports in unit tests. Renamed methods to express expected behavior. Original pull request: #153. --- lombok.config | 2 + src/main/asciidoc/query-by-example.adoc | 112 ++---- .../springframework/data/domain/Example.java | 90 ++--- .../{ExampleSpec.java => ExampleMatcher.java} | 210 ++++------- .../data/domain/TypedExampleSpec.java | 313 ----------------- .../core/support/ExampleMatcherAccessor.java | 157 +++++++++ .../core/support/ExampleSpecAccessor.java | 159 --------- .../data/domain/ExampleMatcherUnitTests.java | 183 ++++++++++ .../data/domain/ExampleSpecUnitTests.java | 220 ------------ .../data/domain/ExampleUnitTests.java | 49 +-- .../domain/TypedExampleSpecUnitTests.java | 231 ------------ ...SpecAccessorTypedExampleSpecUnitTests.java | 315 ----------------- ...ecAccessorUntypedExampleSpecUnitTests.java | 306 ---------------- ...ExampleSpecificationAccessorUnitTests.java | 328 ++++++++++++++++++ 14 files changed, 806 insertions(+), 1869 deletions(-) create mode 100644 lombok.config rename src/main/java/org/springframework/data/domain/{ExampleSpec.java => ExampleMatcher.java} (71%) delete mode 100644 src/main/java/org/springframework/data/domain/TypedExampleSpec.java create mode 100644 src/main/java/org/springframework/data/repository/core/support/ExampleMatcherAccessor.java delete mode 100644 src/main/java/org/springframework/data/repository/core/support/ExampleSpecAccessor.java create mode 100644 src/test/java/org/springframework/data/domain/ExampleMatcherUnitTests.java delete mode 100644 src/test/java/org/springframework/data/domain/ExampleSpecUnitTests.java delete mode 100644 src/test/java/org/springframework/data/domain/TypedExampleSpecUnitTests.java delete mode 100644 src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorTypedExampleSpecUnitTests.java delete mode 100644 src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorUntypedExampleSpecUnitTests.java create mode 100644 src/test/java/org/springframework/data/repository/core/support/ExampleSpecificationAccessorUnitTests.java diff --git a/lombok.config b/lombok.config new file mode 100644 index 000000000..e50c7ea43 --- /dev/null +++ b/lombok.config @@ -0,0 +1,2 @@ +lombok.nonNull.exceptionType = IllegalArgumentException +lombok.log.fieldName = LOG diff --git a/src/main/asciidoc/query-by-example.adoc b/src/main/asciidoc/query-by-example.adoc index 1c07fb3a3..50886c40e 100644 --- a/src/main/asciidoc/query-by-example.adoc +++ b/src/main/asciidoc/query-by-example.adoc @@ -12,8 +12,8 @@ Query by Example (QBE) is a user-friendly querying technique with a simple inter The Query by Example API consists of three parts: * Probe: That is the actual example of a domain object with populated fields. -* `ExampleSpec`: The `ExampleSpec` carries details on how to match particular fields. It can be reused across multiple Examples. `ExampleSpec` comes in two flavors: <> and <>. -* `Example`: An Example consists of the probe and the ExampleSpec. It is used to create the query. An `Example` takes a probe (usually the domain object or a subtype of it) and the `ExampleSpec`. +* `ExampleMatcher`: The `ExampleMatcher` carries details on how to match particular fields. It can be reused across multiple Examples. +* `Example`: An `Example` consists of the probe and the `ExampleMatcher`. It is used to create the query. Query by Example is suited for several use-cases but also comes with limitations: @@ -48,14 +48,13 @@ public class Person { ---- ==== -This is a simple domain object. You can use it to create an `Example`. By default, fields having `null` values are ignored, and strings are matched using the store specific defaults. Examples can be built by either using the `of` factory method or by using <>. `Example` is immutable. +This is a simple domain object. You can use it to create an `Example`. By default, fields having `null` values are ignored, and strings are matched using the store specific defaults. Examples can be built by either using the `of` factory method or by using <>. `Example` is immutable. .Simple Example ==== [source,java] ---- Person person = new Person(); <1> - person.setFirstname("Dave"); <2> Example example = Example.of(person); <3> @@ -65,9 +64,7 @@ Example example = Example.of(person); <3> <3> Create the `Example` ==== -NOTE: Property names of the sample object must correlate with the property names of the queried domain object. - -Examples can be executed ideally with Repositories. To do so, let your repository extend from `QueryByExampleExecutor`, here's an excerpt from the `QueryByExampleExecutor` interface: +Examples are ideally be executed with repositories. To do so, let your repository interface extend `QueryByExampleExecutor`. Here's an excerpt from the `QueryByExampleExecutor` interface: .The `QueryByExampleExecutor` ==== @@ -75,9 +72,9 @@ Examples can be executed ideally with Repositories. To do so, let your repositor ---- public interface QueryByExampleExecutor { - S findOne(Example example); + S findOne(Example example); - Iterable findAll(Example example); + Iterable findAll(Example example); // … more functionality omitted. } @@ -86,50 +83,44 @@ public interface QueryByExampleExecutor { You can read more about <> below. -[[query.by.example.examplespec]] -=== Example Spec +[[query.by.example.matcher]] +=== Example matchers -Examples are not limited to default settings. You can specify own defaults for string matching, null handling and property-specific settings using the `ExampleSpec`. `ExampleSpec` comes in two flavors: untyped and typed. By default `Example.of(Person.class)` uses an untyped `ExampleSpec`. Using untyped `ExampleSpec` will use the Repository entity information to determine the type to query and has no control over inheritance queries. Also, untyped `ExampleSpec` will use the probe type when using with a Template to determine the type to query. Read more about <> below. +Examples are not limited to default settings. You can specify own defaults for string matching, null handling and property-specific settings using the `ExampleMatcher`. `ExampleMatcher` comes in two flavors: untyped and typed. By default `Example.of(Person.class)` uses an untyped `ExampleMatcher`. Using untyped `ExampleMatcher` will use the Repository entity information to determine the type to query and has no control over inheritance queries. Also, untyped `ExampleMatcher` will use the probe type when using with a Template to determine the type to query. Read more about <> below. .Untyped Example Spec with customized matching ==== [source,java] ---- -Person person = new Person(); <1> +Person person = new Person(); <1> +person.setFirstname("Dave"); <2> -person.setFirstname("Dave"); <2> +ExampleMatcher matcher = ExampleMatcher.matching() <3> + .withIgnorePaths("lastname") <4> + .withIncludeNullValues() <5> + .withStringMatcherEnding(); <6> -ExampleSpec exampleSpec = ExampleSpec.untyped() <3> - - .withIgnorePaths("lastname") <4> - - .withIncludeNullValues() <5> - - .withStringMatcherEnding(); <6> - -Example example = Example.of(person, exampleSpec); <7> +Example example = Example.of(person, matcher); <7> ---- <1> Create a new instance of the domain object. <2> Set properties. -<3> Create an untyped `ExampleSpec`. The `ExampleSpec` is usable at this stage. -<4> Construct a new `ExampleSpec` to ignore the property path `lastname`. -<5> Construct a new `ExampleSpec` to ignore the property path `lastname` and to include null values. -<6> Construct a new `ExampleSpec` to ignore the property path `lastname`, to include null values, and use perform suffix string matching. -<7> Create a new `Example` based on the domain object and the configured `ExampleSpec`. +<3> Create an `ExampleMatcher` which is usable at this stage even without further configuration. +<4> Construct a new `ExampleMatcher` to ignore the property path `lastname`. +<5> Construct a new `ExampleMatcher` to ignore the property path `lastname` and to include null values. +<6> Construct a new `ExampleMatcher` to ignore the property path `lastname`, to include null values, and use perform suffix string matching. +<7> Create a new `Example` based on the domain object and the configured `ExampleMatcher`. ==== -`ExampleSpec` is immutable. Calls to `with…(…)` return a copy of `ExampleSpec` with the specific setting applied. Intermediate objects can be safely reused. An `ExampleSpec` can be used to create ad-hoc example specs or to be reused across the application as a specification for `Example`. You can use `ExampleSpec` as a template to configure a default behavior for your example spec. You also can derive from it a more specific `ExampleSpec` where you need to customize it. - You can specify behavior for individual properties (e.g. "firstname" and "lastname", "address.city" for nested properties). You can tune it with matching options and case sensitivity. .Configuring matcher options ==== [source,java] ---- -ExampleSpec exampleSpec = ExampleSpec.untyped() - .withMatcher("firstname", endsWith()) - .withMatcher("lastname", startsWith().ignoreCase()); +ExampleMatcher exampleSpec = ExampleMatcher.untyped() + .withMatcher("firstname", endsWith()) + .withMatcher("lastname", startsWith().ignoreCase()); } ---- ==== @@ -140,74 +131,35 @@ Another style to configure matcher options is by using Java 8 lambdas. This appr ==== [source,java] ---- -ExampleSpec exampleSpec = ExampleSpec.untyped() - .withMatcher("firstname", matcher -> matcher.endsWith()) - .withMatcher("firstname", matcher -> matcher.startsWith()); +ExampleMatcher exampleSpec = ExampleMatcher.untyped() + .withMatcher("firstname", matcher -> matcher.endsWith()) + .withMatcher("firstname", matcher -> matcher.startsWith()); } ---- ==== -Queries created by `Example` use a merged view of the configuration. Default matching settings can be set at `ExampleSpec` level while individual settings can be applied to particular property paths. Settings that are set on `ExampleSpec` are inherited by property path settings unless they are defined explicitly. Settings on a property patch have higher precedence than default settings. +Queries created by `Example` use a merged view of the configuration. Default matching settings can be set at `ExampleMatcher` level while individual settings can be applied to particular property paths. Settings that are set on `ExampleMatcher` are inherited by property path settings unless they are defined explicitly. Settings on a property patch have higher precedence than default settings. [cols="1,2", options="header"] -.Scope of `ExampleSpec` settings +.Scope of `ExampleMatcher` settings |=== | Setting | Scope | Null-handling -| `ExampleSpec` +| `ExampleMatcher` | String matching -| `ExampleSpec` and property path +| `ExampleMatcher` and property path | Ignoring properties | Property path | Case sensitivity -| `ExampleSpec` and property path +| `ExampleMatcher` and property path | Value transformation | Property path |=== -[[query.by.example.examplespec.typed]] -==== Typed Example Spec -You have now seen the usage of untyped `ExampleSpec`. The second flavor of `ExampleSpec` is typed which adds more control over the result type. When executing an `Example` containing a typed `ExampleSpec` the type of the `ExampleSpec` is used as domain type. Control over the domain type is useful in particular when querying along the inheritance hierarchy or the repository contains multiple types within one table/collection/keyspace. - -.Sample Person object -==== -[source,java] ----- -public class SpecialPerson extends Person { - - // … more functionality omitted. -} ----- -==== - -.Typed Example Spec with customized matching -==== -[source,java] ----- -QueryByExampleExecutor personRepository = … ; - -Person person = new Person(); <1> - -person.setFirstname("Dave"); <2> - -ExampleSpec exampleSpec = ExampleSpec.typed(SpecialPerson.class); <3> - -Example example = Example.of(person, exampleSpec); <4> - -List result = personRepository.findAll(example); <5> - ----- -<1> Create a new instance of the domain object. -<2> Set properties. -<3> Create a typed `ExampleSpec` for `SpecialPerson` that extends `Person`. -<4> Construct a new `Example` using the typed `ExampleSpec` and the `Person` probe. -<5> Run a query to select all instances of `SpecialPerson` in the repository. Note that the result type is the base class `Person`. -==== - diff --git a/src/main/java/org/springframework/data/domain/Example.java b/src/main/java/org/springframework/data/domain/Example.java index 3fa95c20e..d419768a0 100644 --- a/src/main/java/org/springframework/data/domain/Example.java +++ b/src/main/java/org/springframework/data/domain/Example.java @@ -15,84 +15,51 @@ */ package org.springframework.data.domain; -import org.springframework.util.Assert; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + import org.springframework.util.ClassUtils; /** * Support for query by example (QBE). An {@link Example} takes a {@code probe} to define the example. Matching options - * and type safety can be tuned using {@link ExampleSpec}. {@link Example} uses {@link ExampleSpec#untyped()} - * {@link ExampleSpec} by default. - *

- * This class is immutable. + * and type safety can be tuned using {@link ExampleMatcher}. * * @author Christoph Strobl * @author Mark Paluch - * @param + * @author Oliver Gierke + * @param the type of the probe. * @since 1.12 */ +@ToString +@EqualsAndHashCode +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Example { - private final T probe; - private final ExampleSpec exampleSpec; + private final @NonNull T probe; + private final @NonNull ExampleMatcher matcher; /** * Create a new {@link Example} including all non-null properties by default. * - * @param probe The probe to use. Must not be {@literal null}. - */ - @SuppressWarnings("unchecked") - private Example(T probe) { - - Assert.notNull(probe, "Probe must not be null!"); - - this.probe = probe; - this.exampleSpec = ExampleSpec.untyped(); - } - - /** - * Create a new {@link Example} including all non-null properties by default. - * - * @param probe The probe to use. Must not be {@literal null}. - * @param exampleSpec The example specification to use. Must not be {@literal null}. - */ - private Example(T probe, ExampleSpec exampleSpec) { - - Assert.notNull(probe, "Probe must not be null!"); - - this.probe = probe; - this.exampleSpec = exampleSpec; - } - - /** - * Create a new {@link Example} including all non-null properties by default using an untyped {@link ExampleSpec}. - * * @param probe must not be {@literal null}. * @return */ public static Example of(T probe) { - return new Example(probe); + return new Example(probe, ExampleMatcher.matching()); } /** - * Create a new {@link Example} with a configured untyped {@link ExampleSpec}. + * Create a new {@link Example} using the given {@link ExampleMatcher}. * * @param probe must not be {@literal null}. - * @param exampleSpec must not be {@literal null}. + * @param matcher must not be {@literal null}. * @return */ - public static Example of(T probe, ExampleSpec exampleSpec) { - return new Example(probe, exampleSpec); - } - - /** - * Create a new {@link Example} with a configured {@link TypedExampleSpec}. - * - * @param probe must not be {@literal null}. - * @param exampleSpec must not be {@literal null}. - * @return - */ - public static Example of(S probe, TypedExampleSpec exampleSpec) { - return new Example(probe, exampleSpec); + public static Example of(T probe, ExampleMatcher matcher) { + return new Example(probe, matcher); } /** @@ -105,12 +72,12 @@ public class Example { } /** - * Get the {@link ExampleSpec} used. + * Get the {@link ExampleMatcher} used. * * @return never {@literal null}. */ - public ExampleSpec getExampleSpec() { - return exampleSpec; + public ExampleMatcher getMatcher() { + return matcher; } /** @@ -124,17 +91,4 @@ public class Example { public Class getProbeType() { return (Class) ClassUtils.getUserClass(probe.getClass()); } - - /** - * Get the actual result type for the query. The result type can be different when using {@link TypedExampleSpec}. - * - * @return - * @see ClassUtils#getUserClass(Class) - */ - @SuppressWarnings("unchecked") - public Class getResultType() { - return (Class) (exampleSpec instanceof TypedExampleSpec ? ((TypedExampleSpec) exampleSpec).getType() - : getProbeType()); - } - } diff --git a/src/main/java/org/springframework/data/domain/ExampleSpec.java b/src/main/java/org/springframework/data/domain/ExampleMatcher.java similarity index 71% rename from src/main/java/org/springframework/data/domain/ExampleSpec.java rename to src/main/java/org/springframework/data/domain/ExampleMatcher.java index 9d8051fab..ecced45ee 100644 --- a/src/main/java/org/springframework/data/domain/ExampleSpec.java +++ b/src/main/java/org/springframework/data/domain/ExampleMatcher.java @@ -15,6 +15,12 @@ */ package org.springframework.data.domain; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.experimental.FieldDefaults; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -27,10 +33,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.util.Assert; /** - * Specification for property path matching to use in query by example (QBE). An {@link ExampleSpec} can be created for - * a {@link Class object type}. Instances of {@link ExampleSpec} can be either {@link #untyped()} or + * Specification for property path matching to use in query by example (QBE). An {@link ExampleMatcher} can be created + * for a {@link Class object type}. Instances of {@link ExampleMatcher} can be either {@link #matching()} or * {@link #typed(Class)} and settings can be tuned {@code with...} methods in a fluent style. {@code with...} methods - * return a copy of the {@link ExampleSpec} instance with the specified setting. Null-handling defaults to + * return a copy of the {@link ExampleMatcher} instance with the specified setting. Null-handling defaults to * {@link NullHandler#IGNORE} and case-sensitive {@link StringMatcher#DEFAULT} string matching. *

* This class is immutable. @@ -40,61 +46,40 @@ import org.springframework.util.Assert; * @param * @since 1.12 */ -public class ExampleSpec { +@ToString +@EqualsAndHashCode +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class ExampleMatcher { - protected final NullHandler nullHandler; - protected final StringMatcher defaultStringMatcher; - protected final boolean defaultIgnoreCase; - protected final PropertySpecifiers propertySpecifiers; - protected final Set ignoredPaths; + NullHandler nullHandler; + StringMatcher defaultStringMatcher; + PropertySpecifiers propertySpecifiers; + Set ignoredPaths; + boolean defaultIgnoreCase; - ExampleSpec() { - - this.nullHandler = NullHandler.IGNORE; - this.defaultStringMatcher = StringMatcher.DEFAULT; - this.propertySpecifiers = new PropertySpecifiers(); - this.defaultIgnoreCase = false; - this.ignoredPaths = Collections.emptySet(); - } - - ExampleSpec(NullHandler nullHandler, StringMatcher defaultStringMatcher, PropertySpecifiers propertySpecifiers, - Set ignoredPaths, boolean defaultIgnoreCase) { - - this.nullHandler = nullHandler; - this.defaultStringMatcher = defaultStringMatcher; - this.propertySpecifiers = propertySpecifiers; - this.ignoredPaths = Collections.unmodifiableSet(ignoredPaths); - this.defaultIgnoreCase = defaultIgnoreCase; + private ExampleMatcher() { + this(NullHandler.IGNORE, StringMatcher.DEFAULT, new PropertySpecifiers(), Collections. emptySet(), false); } /** - * Create a new untyped {@link ExampleSpec} including all non-null properties by default. + * Create a new untyped {@link ExampleMatcher} including all non-null properties by default. * * @param type must not be {@literal null}. * @return */ - public static ExampleSpec untyped() { - return new ExampleSpec(); + public static ExampleMatcher matching() { + return new ExampleMatcher(); } /** - * Create a new {@link TypedExampleSpec} including all non-null properties by default. - * - * @param type must not be {@literal null}. - * @return - */ - public static TypedExampleSpec typed(Class type) { - return new TypedExampleSpec(type); - } - - /** - * Returns a copy of this {@link ExampleSpec} with the specified {@code propertyPaths}. This instance is immutable and - * unaffected by this method call. + * Returns a copy of this {@link ExampleMatcher} with the specified {@code propertyPaths}. This instance is immutable + * and unaffected by this method call. * * @param ignoredPaths must not be {@literal null} and not empty. * @return */ - public ExampleSpec withIgnorePaths(String... ignoredPaths) { + public ExampleMatcher withIgnorePaths(String... ignoredPaths) { Assert.notEmpty(ignoredPaths, "IgnoredPaths must not be empty!"); Assert.noNullElements(ignoredPaths, "IgnoredPaths must not contain null elements!"); @@ -102,83 +87,54 @@ public class ExampleSpec { Set newIgnoredPaths = new LinkedHashSet(this.ignoredPaths); newIgnoredPaths.addAll(Arrays.asList(ignoredPaths)); - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, newIgnoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, newIgnoredPaths, + defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with the specified string matching of {@link StringMatcher#STARTING}. + * Returns a copy of this {@link ExampleMatcher} with the specified string matching of {@code defaultStringMatcher}. * This instance is immutable and unaffected by this method call. * - * @return - */ - public ExampleSpec withStringMatcherStarting() { - return new ExampleSpec(nullHandler, StringMatcher.STARTING, propertySpecifiers, ignoredPaths, defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link ExampleSpec} with the specified string matching of {@link StringMatcher#ENDING}. This - * instance is immutable and unaffected by this method call. - * - * @return - */ - public ExampleSpec withStringMatcherEnding() { - return new ExampleSpec(nullHandler, StringMatcher.ENDING, propertySpecifiers, ignoredPaths, defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link ExampleSpec} with the specified string matching of {@link StringMatcher#CONTAINING}. - * This instance is immutable and unaffected by this method call. - * - * @return - */ - public ExampleSpec withStringMatcherContaining() { - return new ExampleSpec(nullHandler, StringMatcher.CONTAINING, propertySpecifiers, ignoredPaths, defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link ExampleSpec} with the specified string matching of {@code defaultStringMatcher}. This - * instance is immutable and unaffected by this method call. - * * @param defaultStringMatcher must not be {@literal null}. * @return */ - public ExampleSpec withStringMatcher(StringMatcher defaultStringMatcher) { + public ExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher) { Assert.notNull(ignoredPaths, "DefaultStringMatcher must not be empty!"); - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with ignoring case sensitivity by default. This instance is immutable + * Returns a copy of this {@link ExampleMatcher} with ignoring case sensitivity by default. This instance is immutable * and unaffected by this method call. * * @return */ - public ExampleSpec withIgnoreCase() { + public ExampleMatcher withIgnoreCase() { return withIgnoreCase(true); } /** - * Returns a copy of this {@link ExampleSpec} with {@code defaultIgnoreCase}. This instance is immutable and + * Returns a copy of this {@link ExampleMatcher} with {@code defaultIgnoreCase}. This instance is immutable and * unaffected by this method call. * * @param defaultIgnoreCase * @return */ - public ExampleSpec withIgnoreCase(boolean defaultIgnoreCase) { - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + public ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase) { + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with the specified {@code GenericPropertyMatcher} for the + * Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the * {@code propertyPath}. This instance is immutable and unaffected by this method call. * * @param propertyPath must not be {@literal null}. * @param matcherConfigurer callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}. * @return */ - public ExampleSpec withMatcher(String propertyPath, MatcherConfigurer matcherConfigurer) { + public ExampleMatcher withMatcher(String propertyPath, MatcherConfigurer matcherConfigurer) { Assert.hasText(propertyPath, "PropertyPath must not be empty!"); Assert.notNull(matcherConfigurer, "MatcherConfigurer must not be empty!"); @@ -190,14 +146,14 @@ public class ExampleSpec { } /** - * Returns a copy of this {@link ExampleSpec} with the specified {@code GenericPropertyMatcher} for the + * Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the * {@code propertyPath}. This instance is immutable and unaffected by this method call. * * @param propertyPath must not be {@literal null}. * @param genericPropertyMatcher callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}. * @return */ - public ExampleSpec withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher) { + public ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher) { Assert.hasText(propertyPath, "PropertyPath must not be empty!"); Assert.notNull(genericPropertyMatcher, "GenericPropertyMatcher must not be empty!"); @@ -219,18 +175,18 @@ public class ExampleSpec { propertySpecifiers.add(propertySpecifier); - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with the specified {@code PropertyValueTransformer} for the + * Returns a copy of this {@link ExampleMatcher} with the specified {@code PropertyValueTransformer} for the * {@code propertyPath}. * * @param propertyPath must not be {@literal null}. * @param propertyValueTransformer must not be {@literal null}. * @return */ - public ExampleSpec withTransformer(String propertyPath, PropertyValueTransformer propertyValueTransformer) { + public ExampleMatcher withTransformer(String propertyPath, PropertyValueTransformer propertyValueTransformer) { Assert.hasText(propertyPath, "PropertyPath must not be empty!"); Assert.notNull(propertyValueTransformer, "PropertyValueTransformer must not be empty!"); @@ -240,17 +196,17 @@ public class ExampleSpec { propertySpecifiers.add(propertySpecifier.withValueTransformer(propertyValueTransformer)); - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with ignore case sensitivity for the {@code propertyPaths}. This + * Returns a copy of this {@link ExampleMatcher} with ignore case sensitivity for the {@code propertyPaths}. This * instance is immutable and unaffected by this method call. * * @param propertyPaths must not be {@literal null} and not empty. * @return */ - public ExampleSpec withIgnoreCase(String... propertyPaths) { + public ExampleMatcher withIgnoreCase(String... propertyPaths) { Assert.notEmpty(propertyPaths, "PropertyPaths must not be empty!"); Assert.noNullElements(propertyPaths, "PropertyPaths must not contain null elements!"); @@ -262,10 +218,10 @@ public class ExampleSpec { propertySpecifiers.add(propertySpecifier.withIgnoreCase(true)); } - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } - protected PropertySpecifier getOrCreatePropertySpecifier(String propertyPath, PropertySpecifiers propertySpecifiers) { + private PropertySpecifier getOrCreatePropertySpecifier(String propertyPath, PropertySpecifiers propertySpecifiers) { if (propertySpecifiers.hasSpecifierForPath(propertyPath)) { return propertySpecifiers.getForPath(propertyPath); @@ -275,38 +231,38 @@ public class ExampleSpec { } /** - * Returns a copy of this {@link ExampleSpec} with treatment for {@literal null} values of {@link NullHandler#INCLUDE} - * . This instance is immutable and unaffected by this method call. + * Returns a copy of this {@link ExampleMatcher} with treatment for {@literal null} values of + * {@link NullHandler#INCLUDE} . This instance is immutable and unaffected by this method call. * * @return */ - public ExampleSpec withIncludeNullValues() { - return new ExampleSpec(NullHandler.INCLUDE, defaultStringMatcher, propertySpecifiers, ignoredPaths, + public ExampleMatcher withIncludeNullValues() { + return new ExampleMatcher(NullHandler.INCLUDE, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with treatment for {@literal null} values of {@link NullHandler#IGNORE}. - * This instance is immutable and unaffected by this method call. + * Returns a copy of this {@link ExampleMatcher} with treatment for {@literal null} values of + * {@link NullHandler#IGNORE}. This instance is immutable and unaffected by this method call. * * @return */ - public ExampleSpec withIgnoreNullValues() { - return new ExampleSpec(NullHandler.IGNORE, defaultStringMatcher, propertySpecifiers, ignoredPaths, + public ExampleMatcher withIgnoreNullValues() { + return new ExampleMatcher(NullHandler.IGNORE, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** - * Returns a copy of this {@link ExampleSpec} with the specified {@code nullHandler}. This instance is immutable and - * unaffected by this method call. + * Returns a copy of this {@link ExampleMatcher} with the specified {@code nullHandler}. This instance is immutable + * and unaffected by this method call. * * @param nullHandler must not be {@literal null}. * @return */ - public ExampleSpec withNullHandler(NullHandler nullHandler) { + public ExampleMatcher withNullHandler(NullHandler nullHandler) { Assert.notNull(nullHandler, "NullHandler must not be null!"); - return new ExampleSpec(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); + return new ExampleMatcher(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); } /** @@ -314,16 +270,16 @@ public class ExampleSpec { * * @return never {@literal null} */ - public ExampleSpec.NullHandler getNullHandler() { + public ExampleMatcher.NullHandler getNullHandler() { return nullHandler; } /** - * Get defined {@link ExampleSpec.StringMatcher}. + * Get defined {@link ExampleMatcher.StringMatcher}. * * @return never {@literal null}. */ - public ExampleSpec.StringMatcher getDefaultStringMatcher() { + public ExampleMatcher.StringMatcher getDefaultStringMatcher() { return defaultStringMatcher; } @@ -350,7 +306,7 @@ public class ExampleSpec { } /** - * @return the {@link PropertySpecifiers} within the {@link ExampleSpec}. + * @return the {@link PropertySpecifiers} within the {@link ExampleMatcher}. */ public PropertySpecifiers getPropertySpecifiers() { return propertySpecifiers; @@ -538,7 +494,6 @@ public class ExampleSpec { this.valueTransformer = propertyValueTransformer; return this; } - } /** @@ -620,7 +575,6 @@ public class ExampleSpec { public static GenericPropertyMatcher regex() { return new GenericPropertyMatcher().regex(); } - } /** @@ -660,15 +614,13 @@ public class ExampleSpec { /** * Allows to transform the property value before it is used in the query. */ - public static interface PropertyValueTransformer extends Converter { - // TODO: should we use the converter interface directly or not at all? - } + public static interface PropertyValueTransformer extends Converter {} /** * @author Christoph Strobl * @since 1.12 */ - public static enum NoOpPropertyValueTransformer implements ExampleSpec.PropertyValueTransformer { + public static enum NoOpPropertyValueTransformer implements ExampleMatcher.PropertyValueTransformer { INSTANCE; @@ -676,7 +628,6 @@ public class ExampleSpec { public Object convert(Object source) { return source; } - } /** @@ -685,13 +636,14 @@ public class ExampleSpec { * @author Christoph Strobl * @since 1.12 */ + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public static class PropertySpecifier { - private final String path; - - private final StringMatcher stringMatcher; - private final Boolean ignoreCase; - private final PropertyValueTransformer valueTransformer; + String path; + StringMatcher stringMatcher; + Boolean ignoreCase; + PropertyValueTransformer valueTransformer; /** * Creates new {@link PropertySpecifier} for given path. @@ -708,15 +660,6 @@ public class ExampleSpec { this.valueTransformer = NoOpPropertyValueTransformer.INSTANCE; } - private PropertySpecifier(String path, StringMatcher stringMatcher, Boolean ignoreCase, - PropertyValueTransformer valueTransformer) { - - this.path = path; - this.stringMatcher = stringMatcher; - this.ignoreCase = ignoreCase; - this.valueTransformer = valueTransformer; - } - /** * Creates a new {@link PropertySpecifier} containing all values from the current instance and sets * {@link StringMatcher} in the returned instance. @@ -797,7 +740,6 @@ public class ExampleSpec { public Object transformValue(Object source) { return getPropertyValueTransformer().convert(source); } - } /** @@ -810,9 +752,7 @@ public class ExampleSpec { private final Map propertySpecifiers = new LinkedHashMap(); - PropertySpecifiers() { - - } + PropertySpecifiers() {} PropertySpecifiers(PropertySpecifiers propertySpecifiers) { this.propertySpecifiers.putAll(propertySpecifiers.propertySpecifiers); @@ -839,7 +779,5 @@ public class ExampleSpec { public Collection getSpecifiers() { return propertySpecifiers.values(); } - } - } diff --git a/src/main/java/org/springframework/data/domain/TypedExampleSpec.java b/src/main/java/org/springframework/data/domain/TypedExampleSpec.java deleted file mode 100644 index 1fb17b19a..000000000 --- a/src/main/java/org/springframework/data/domain/TypedExampleSpec.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2016 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.domain; - -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * A {@code TypedExampleSpec} is a special {@link ExampleSpec} that holds information of the type to query for. - * - * @author Mark Paluch - * @since 1.12 - */ -public class TypedExampleSpec extends ExampleSpec { - - protected final Class type; - - TypedExampleSpec(Class type) { - super(); - - Assert.notNull(type, "Type must not be null!"); - - this.type = type; - } - - TypedExampleSpec(Class type, NullHandler nullHandler, StringMatcher defaultStringMatcher, - PropertySpecifiers propertySpecifiers, Set ignoredPaths, boolean defaultIgnoreCase) { - - super(nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, defaultIgnoreCase); - - Assert.notNull(type, "Type must not be null!"); - this.type = type; - } - - /** - * Create a new {@link TypedExampleSpec} for the {@code type} including all non-null properties by default. - * - * @param type must not be {@literal null}. - * @return - */ - public static TypedExampleSpec of(Class type) { - return new TypedExampleSpec(type); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified {@code propertyPaths}. This instance is - * immutable and unaffected by this method call. - * - * @param ignoredPaths must not be {@literal null} and not empty. - * @return - */ - @Override - public TypedExampleSpec withIgnorePaths(String... ignoredPaths) { - - Assert.notEmpty(ignoredPaths, "IgnoredPaths must not be empty!"); - Assert.noNullElements(ignoredPaths, "IgnoredPaths must not contain null elements!"); - - Set newIgnoredPaths = new LinkedHashSet(this.ignoredPaths); - newIgnoredPaths.addAll(Arrays.asList(ignoredPaths)); - - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, newIgnoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified string matching of - * {@link StringMatcher#STARTING}. This instance is immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withStringMatcherStarting() { - return new TypedExampleSpec(type, nullHandler, StringMatcher.STARTING, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified string matching of {@link StringMatcher#ENDING}. - * This instance is immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withStringMatcherEnding() { - return new TypedExampleSpec(type, nullHandler, StringMatcher.ENDING, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified string matching of - * {@link StringMatcher#CONTAINING}. This instance is immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withStringMatcherContaining() { - return new TypedExampleSpec(type, nullHandler, StringMatcher.CONTAINING, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified string matching of {@code defaultStringMatcher}. - * This instance is immutable and unaffected by this method call. - * - * @param defaultStringMatcher must not be {@literal null}. - * @return - */ - @Override - public TypedExampleSpec withStringMatcher(StringMatcher defaultStringMatcher) { - - Assert.notNull(ignoredPaths, "DefaultStringMatcher must not be empty!"); - - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with ignoring case sensitivity by default. This instance is - * immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withIgnoreCase() { - return withIgnoreCase(true); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with {@code defaultIgnoreCase}. This instance is immutable and - * unaffected by this method call. - * - * @param defaultIgnoreCase - * @return - */ - @Override - public TypedExampleSpec withIgnoreCase(boolean defaultIgnoreCase) { - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified {@code GenericPropertyMatcher} for the - * {@code propertyPath}. This instance is immutable and unaffected by this method call. - * - * @param propertyPath must not be {@literal null}. - * @param matcherConfigurer callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}. - * @return - */ - @Override - public TypedExampleSpec withMatcher(String propertyPath, - MatcherConfigurer matcherConfigurer) { - - Assert.hasText(propertyPath, "PropertyPath must not be empty!"); - Assert.notNull(matcherConfigurer, "MatcherConfigurer must not be empty!"); - - GenericPropertyMatcher genericPropertyMatcher = new GenericPropertyMatcher(); - matcherConfigurer.configureMatcher(genericPropertyMatcher); - - return withMatcher(propertyPath, genericPropertyMatcher); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified {@code GenericPropertyMatcher} for the - * {@code propertyPath}. This instance is immutable and unaffected by this method call. - * - * @param propertyPath must not be {@literal null}. - * @param genericPropertyMatcher callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}. - * @return - */ - @Override - public TypedExampleSpec withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher) { - - Assert.hasText(propertyPath, "PropertyPath must not be empty!"); - Assert.notNull(genericPropertyMatcher, "GenericPropertyMatcher must not be empty!"); - - PropertySpecifiers propertySpecifiers = new PropertySpecifiers(this.propertySpecifiers); - PropertySpecifier propertySpecifier = new PropertySpecifier(propertyPath); - - if (genericPropertyMatcher.ignoreCase != null) { - propertySpecifier = propertySpecifier.withIgnoreCase(genericPropertyMatcher.ignoreCase); - } - - if (genericPropertyMatcher.stringMatcher != null) { - propertySpecifier = propertySpecifier.withStringMatcher(genericPropertyMatcher.stringMatcher); - } - - if (genericPropertyMatcher.valueTransformer != null) { - propertySpecifier = propertySpecifier.withValueTransformer(genericPropertyMatcher.valueTransformer); - } - - propertySpecifiers.add(propertySpecifier); - - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified {@code PropertyValueTransformer} for the - * {@code propertyPath}. - * - * @param propertyPath must not be {@literal null}. - * @param propertyValueTransformer must not be {@literal null}. - * @return - */ - @Override - public TypedExampleSpec withTransformer(String propertyPath, PropertyValueTransformer propertyValueTransformer) { - - Assert.hasText(propertyPath, "PropertyPath must not be empty!"); - Assert.notNull(propertyValueTransformer, "PropertyValueTransformer must not be empty!"); - - PropertySpecifiers propertySpecifiers = new PropertySpecifiers(this.propertySpecifiers); - PropertySpecifier propertySpecifier = getOrCreatePropertySpecifier(propertyPath, propertySpecifiers); - - propertySpecifiers.add(propertySpecifier.withValueTransformer(propertyValueTransformer)); - - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with ignore case sensitivity for the {@code propertyPaths}. This - * instance is immutable and unaffected by this method call. - * - * @param propertyPaths must not be {@literal null} and not empty. - * @return - */ - @Override - public TypedExampleSpec withIgnoreCase(String... propertyPaths) { - - Assert.notEmpty(propertyPaths, "PropertyPaths must not be empty!"); - Assert.noNullElements(propertyPaths, "PropertyPaths must not contain null elements!"); - - PropertySpecifiers propertySpecifiers = new PropertySpecifiers(this.propertySpecifiers); - - for (String propertyPath : propertyPaths) { - PropertySpecifier propertySpecifier = getOrCreatePropertySpecifier(propertyPath, propertySpecifiers); - propertySpecifiers.add(propertySpecifier.withIgnoreCase(true)); - } - - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with treatment for {@literal null} values of - * {@link NullHandler#INCLUDE} . This instance is immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withIncludeNullValues() { - return new TypedExampleSpec(type, NullHandler.INCLUDE, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with treatment for {@literal null} values of - * {@link NullHandler#IGNORE}. This instance is immutable and unaffected by this method call. - * - * @return - */ - @Override - public TypedExampleSpec withIgnoreNullValues() { - return new TypedExampleSpec(type, NullHandler.IGNORE, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Returns a copy of this {@link TypedExampleSpec} with the specified {@code nullHandler}. This instance is immutable - * and unaffected by this method call. - * - * @param nullHandler must not be {@literal null}. - * @return - */ - @Override - public TypedExampleSpec withNullHandler(NullHandler nullHandler) { - - Assert.notNull(nullHandler, "NullHandler must not be null!"); - return new TypedExampleSpec(type, nullHandler, defaultStringMatcher, propertySpecifiers, ignoredPaths, - defaultIgnoreCase); - } - - /** - * Get the actual type for the {@link TypedExampleSpec} used. This is usually the given class, but the original class - * in case of a CGLIB-generated subclass. - * - * @return - * @see ClassUtils#getUserClass(Class) - */ - @SuppressWarnings("unchecked") - public Class getType() { - return (Class) ClassUtils.getUserClass(type); - } - -} diff --git a/src/main/java/org/springframework/data/repository/core/support/ExampleMatcherAccessor.java b/src/main/java/org/springframework/data/repository/core/support/ExampleMatcherAccessor.java new file mode 100644 index 000000000..b3b4350c3 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/core/support/ExampleMatcherAccessor.java @@ -0,0 +1,157 @@ +/* + * Copyright 2016 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.repository.core.support; + +import java.util.Collection; + +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.domain.ExampleMatcher.PropertySpecifier; + +/** + * Accessor for the {@link ExampleMatcher} to use in modules that support query by example (QBE) querying. + * + * @author Mark Paluch + * @author Oliver Gierke + * @since 1.12 + */ +public class ExampleMatcherAccessor { + + private final ExampleMatcher specification; + + public ExampleMatcherAccessor(ExampleMatcher specification) { + this.specification = specification; + } + + /** + * Returns the {@link PropertySpecifier}s of the underlying {@link ExampleMatcher}. + * + * @return unmodifiable {@link Collection} of {@link ExampleMatcher.PropertySpecifier}s. + */ + public Collection getPropertySpecifiers() { + return specification.getPropertySpecifiers().getSpecifiers(); + } + + /** + * Returns whether the underlying {@link ExampleMatcher} contains a {@link PropertySpecifier} for the given path. + * + * @param path the dot-path identifying a property. + * @return {@literal true} in case {@link ExampleMatcher.PropertySpecifier} defined for given path. + */ + public boolean hasPropertySpecifier(String path) { + return specification.getPropertySpecifiers().hasSpecifierForPath(path); + } + + /** + * Get the {@link ExampleMatcher.PropertySpecifier} for given path.
+ * Please check if {@link #hasPropertySpecifier(String)} to avoid running into {@literal null} values. + * + * @param path Dot-Path to property. + * @return {@literal null} when no {@link ExampleMatcher.PropertySpecifier} defined for path. + */ + public ExampleMatcher.PropertySpecifier getPropertySpecifier(String path) { + return specification.getPropertySpecifiers().getForPath(path); + } + + /** + * @return true if at least one {@link ExampleMatcher.PropertySpecifier} defined. + */ + public boolean hasPropertySpecifiers() { + return specification.getPropertySpecifiers().hasValues(); + } + + /** + * Get the {@link ExampleMatcher.StringMatcher} for a given path or return the default one if none defined. + * + * @param path + * @return never {@literal null}. + */ + public ExampleMatcher.StringMatcher getStringMatcherForPath(String path) { + + if (!hasPropertySpecifier(path)) { + return specification.getDefaultStringMatcher(); + } + + ExampleMatcher.PropertySpecifier specifier = getPropertySpecifier(path); + return specifier.getStringMatcher() != null ? specifier.getStringMatcher() + : specification.getDefaultStringMatcher(); + } + + /** + * Get defined null handling. + * + * @return never {@literal null} + */ + public ExampleMatcher.NullHandler getNullHandler() { + return specification.getNullHandler(); + } + + /** + * Get defined {@link ExampleMatcher.StringMatcher}. + * + * @return never {@literal null}. + */ + public ExampleMatcher.StringMatcher getDefaultStringMatcher() { + return specification.getDefaultStringMatcher(); + } + + /** + * @return {@literal true} if {@link String} should be matched with ignore case option. + */ + public boolean isIgnoreCaseEnabled() { + return specification.isIgnoreCaseEnabled(); + } + + /** + * @param path + * @return return {@literal true} if path was set to be ignored. + */ + public boolean isIgnoredPath(String path) { + return specification.isIgnoredPath(path); + } + + /** + * Get the ignore case flag for a given path or return the default one if none defined. + * + * @param path + * @return never {@literal null}. + */ + public boolean isIgnoreCaseForPath(String path) { + + if (!hasPropertySpecifier(path)) { + return specification.isIgnoreCaseEnabled(); + } + + ExampleMatcher.PropertySpecifier specifier = getPropertySpecifier(path); + return specifier.getIgnoreCase() != null ? specifier.getIgnoreCase().booleanValue() + : specification.isIgnoreCaseEnabled(); + } + + /** + * Get the ignore case flag for a given path or return {@link ExampleMatcher.NoOpPropertyValueTransformer} if none + * defined. + * + * @param path + * @return never {@literal null}. + */ + public ExampleMatcher.PropertyValueTransformer getValueTransformerForPath(String path) { + + if (!hasPropertySpecifier(path)) { + return ExampleMatcher.NoOpPropertyValueTransformer.INSTANCE; + } + + return getPropertySpecifier(path).getPropertyValueTransformer(); + } +} diff --git a/src/main/java/org/springframework/data/repository/core/support/ExampleSpecAccessor.java b/src/main/java/org/springframework/data/repository/core/support/ExampleSpecAccessor.java deleted file mode 100644 index 3afc2b90f..000000000 --- a/src/main/java/org/springframework/data/repository/core/support/ExampleSpecAccessor.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2016 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.repository.core.support; - -import java.util.Collection; - -import org.springframework.data.domain.ExampleSpec; -import org.springframework.data.domain.TypedExampleSpec; - -/** - * Accessor for the {@link ExampleSpec} to use in modules that support query by example (QBE) querying. - * - * @author Mark Paluch - * @since 1.12 - */ -public class ExampleSpecAccessor { - - private final ExampleSpec exampleSpec; - - public ExampleSpecAccessor(ExampleSpec exampleSpec) { - this.exampleSpec = exampleSpec; - } - - /** - * @return unmodifiable {@link Collection} of {@link ExampleSpec.PropertySpecifier}s. - */ - public Collection getPropertySpecifiers() { - return exampleSpec.getPropertySpecifiers().getSpecifiers(); - } - - /** - * @param path Dot-Path to property. - * @return {@literal true} in case {@link ExampleSpec.PropertySpecifier} defined for given path. - */ - public boolean hasPropertySpecifier(String path) { - return exampleSpec.getPropertySpecifiers().hasSpecifierForPath(path); - } - - /** - * Get the {@link ExampleSpec.PropertySpecifier} for given path.
- * Please check if {@link #hasPropertySpecifier(String)} to avoid running into {@literal null} values. - * - * @param path Dot-Path to property. - * @return {@literal null} when no {@link ExampleSpec.PropertySpecifier} defined for path. - */ - public ExampleSpec.PropertySpecifier getPropertySpecifier(String path) { - return exampleSpec.getPropertySpecifiers().getForPath(path); - } - - /** - * @return true if at least one {@link ExampleSpec.PropertySpecifier} defined. - */ - public boolean hasPropertySpecifiers() { - return exampleSpec.getPropertySpecifiers().hasValues(); - } - - /** - * Get the {@link ExampleSpec.StringMatcher} for a given path or return the default one if none defined. - * - * @param path - * @return never {@literal null}. - */ - public ExampleSpec.StringMatcher getStringMatcherForPath(String path) { - - if (!hasPropertySpecifier(path)) { - return exampleSpec.getDefaultStringMatcher(); - } - - ExampleSpec.PropertySpecifier specifier = getPropertySpecifier(path); - return specifier.getStringMatcher() != null ? specifier.getStringMatcher() : exampleSpec.getDefaultStringMatcher(); - } - - /** - * Get defined null handling. - * - * @return never {@literal null} - */ - public ExampleSpec.NullHandler getNullHandler() { - return exampleSpec.getNullHandler(); - } - - /** - * Get defined {@link ExampleSpec.StringMatcher}. - * - * @return never {@literal null}. - */ - public ExampleSpec.StringMatcher getDefaultStringMatcher() { - return exampleSpec.getDefaultStringMatcher(); - } - - /** - * @return {@literal true} if {@link String} should be matched with ignore case option. - */ - public boolean isIgnoreCaseEnabled() { - return exampleSpec.isIgnoreCaseEnabled(); - } - - /** - * @param path - * @return return {@literal true} if path was set to be ignored. - */ - public boolean isIgnoredPath(String path) { - return exampleSpec.isIgnoredPath(path); - } - - /** - * Get the ignore case flag for a given path or return the default one if none defined. - * - * @param path - * @return never {@literal null}. - */ - public boolean isIgnoreCaseForPath(String path) { - - if (!hasPropertySpecifier(path)) { - return exampleSpec.isIgnoreCaseEnabled(); - } - - ExampleSpec.PropertySpecifier specifier = getPropertySpecifier(path); - return specifier.getIgnoreCase() != null ? specifier.getIgnoreCase().booleanValue() - : exampleSpec.isIgnoreCaseEnabled(); - } - - /** - * Get the ignore case flag for a given path or return {@link ExampleSpec.NoOpPropertyValueTransformer} if none - * defined. - * - * @param path - * @return never {@literal null}. - */ - public ExampleSpec.PropertyValueTransformer getValueTransformerForPath(String path) { - - if (!hasPropertySpecifier(path)) { - return ExampleSpec.NoOpPropertyValueTransformer.INSTANCE; - } - - return getPropertySpecifier(path).getPropertyValueTransformer(); - } - - /** - * @return {@literal true} if the {@link ExampleSpec} is typed. - */ - public boolean isTyped() { - return exampleSpec instanceof TypedExampleSpec; - } - -} diff --git a/src/test/java/org/springframework/data/domain/ExampleMatcherUnitTests.java b/src/test/java/org/springframework/data/domain/ExampleMatcherUnitTests.java new file mode 100644 index 000000000..62cbefbf8 --- /dev/null +++ b/src/test/java/org/springframework/data/domain/ExampleMatcherUnitTests.java @@ -0,0 +1,183 @@ +/* + * Copyright 2016 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.domain; + +import static org.hamcrest.Matchers.*; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; +import static org.springframework.data.domain.ExampleMatcher.*; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.data.domain.ExampleMatcher.NullHandler; +import org.springframework.data.domain.ExampleMatcher.StringMatcher; + +/** + * Unit test for {@link ExampleMatcher}. + * + * @author Mark Paluch + * @soundtrack K2 - Der Berg Ruft (Club Mix) + */ +public class ExampleMatcherUnitTests { + + ExampleMatcher matcher; + + @Before + public void setUp() throws Exception { + matcher = matching(); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void defaultStringMatcherShouldReturnDefault() throws Exception { + assertThat(matcher.getDefaultStringMatcher(), is(StringMatcher.DEFAULT)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldReturnFalseByDefault() throws Exception { + assertThat(matcher.isIgnoreCaseEnabled(), is(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoredPathsIsEmptyByDefault() throws Exception { + assertThat(matcher.getIgnoredPaths(), is(empty())); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void nullHandlerShouldReturnIgnoreByDefault() throws Exception { + assertThat(matcher.getNullHandler(), is(NullHandler.IGNORE)); + } + + /** + * @see DATACMNS-810 + */ + @Test(expected = UnsupportedOperationException.class) + public void ignoredPathsIsNotModifiable() throws Exception { + matcher.getIgnoredPaths().add("¯\\_(ツ)_/¯"); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldReturnTrueWhenIgnoreCaseEnabled() throws Exception { + + matcher = matching().withIgnoreCase(); + + assertThat(matcher.isIgnoreCaseEnabled(), is(true)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldReturnTrueWhenIgnoreCaseSet() throws Exception { + + matcher = matching().withIgnoreCase(true); + + assertThat(matcher.isIgnoreCaseEnabled(), is(true)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void nullHandlerShouldReturnInclude() throws Exception { + + matcher = matching().withIncludeNullValues(); + + assertThat(matcher.getNullHandler(), is(NullHandler.INCLUDE)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void nullHandlerShouldReturnIgnore() throws Exception { + + matcher = matching().withIgnoreNullValues(); + + assertThat(matcher.getNullHandler(), is(NullHandler.IGNORE)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void nullHandlerShouldReturnConfiguredValue() throws Exception { + + matcher = matching().withNullHandler(NullHandler.INCLUDE); + + assertThat(matcher.getNullHandler(), is(NullHandler.INCLUDE)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoredPathsShouldReturnCorrectProperties() throws Exception { + + matcher = matching().withIgnorePaths("foo", "bar", "baz"); + + assertThat(matcher.getIgnoredPaths(), contains("foo", "bar", "baz")); + assertThat(matcher.getIgnoredPaths(), hasSize(3)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoredPathsShouldReturnUniqueProperties() throws Exception { + + matcher = matching().withIgnorePaths("foo", "bar", "foo"); + + assertThat(matcher.getIgnoredPaths(), contains("foo", "bar")); + assertThat(matcher.getIgnoredPaths(), hasSize(2)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void withCreatesNewInstance() throws Exception { + + matcher = matching().withIgnorePaths("foo", "bar", "foo"); + ExampleMatcher configuredExampleSpec = matcher.withIgnoreCase(); + + assertThat(matcher, is(not(sameInstance(configuredExampleSpec)))); + assertThat(matcher.getIgnoredPaths(), hasSize(2)); + assertThat(matcher.isIgnoreCaseEnabled(), is(false)); + + assertThat(configuredExampleSpec.getIgnoredPaths(), hasSize(2)); + assertThat(configuredExampleSpec.isIgnoreCaseEnabled(), is(true)); + } + + static class Person { + + String firstname; + } +} diff --git a/src/test/java/org/springframework/data/domain/ExampleSpecUnitTests.java b/src/test/java/org/springframework/data/domain/ExampleSpecUnitTests.java deleted file mode 100644 index fbd2fcca3..000000000 --- a/src/test/java/org/springframework/data/domain/ExampleSpecUnitTests.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2016 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.domain; - -import static org.hamcrest.Matchers.*; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.data.domain.ExampleSpec.NullHandler; -import org.springframework.data.domain.ExampleSpec.StringMatcher; - -/** - * Unit test for {@link ExampleSpec}. - * - * @author Mark Paluch - * @soundtrack K2 - Der Berg Ruft (Club Mix) - */ -public class ExampleSpecUnitTests { - - ExampleSpec exampleSpec; - - @Before - public void setUp() throws Exception { - exampleSpec = ExampleSpec.untyped(); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnDefault() throws Exception { - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.DEFAULT)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnContainingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.untyped().withStringMatcherContaining(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnStartingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.untyped().withStringMatcherStarting(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.STARTING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnEndingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.untyped().withStringMatcherEnding(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.ENDING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnFalseByDefault() throws Exception { - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsIsEmptyByDefault() throws Exception { - assertThat(exampleSpec.getIgnoredPaths(), is(empty())); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnIgnoreByDefault() throws Exception { - assertThat(exampleSpec.getNullHandler(), is(NullHandler.IGNORE)); - } - - /** - * @see DATACMNS-810 - */ - @Test(expected = UnsupportedOperationException.class) - public void ignoredPathsIsNotModifiable() throws Exception { - exampleSpec.getIgnoredPaths().add("¯\\_(ツ)_/¯"); - } - - /** - * @see DATACMNS-810 - */ - @Test(expected = IllegalArgumentException.class) - public void defaultExampleSpecWithoutTypeFails() throws Exception { - ExampleSpec.typed(null); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseEnabled() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase(); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseSet() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase(true); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnInclude() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIncludeNullValues(); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnIgnore() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnoreNullValues(); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.IGNORE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnConfiguredValue() throws Exception { - - exampleSpec = ExampleSpec.untyped().withNullHandler(NullHandler.INCLUDE); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsShouldReturnCorrectProperties() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnorePaths("foo", "bar", "baz"); - - assertThat(exampleSpec.getIgnoredPaths(), contains("foo", "bar", "baz")); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(3)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsShouldReturnUniqueProperties() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnorePaths("foo", "bar", "foo"); - - assertThat(exampleSpec.getIgnoredPaths(), contains("foo", "bar")); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(2)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void withCreatesNewInstance() throws Exception { - - exampleSpec = ExampleSpec.untyped().withIgnorePaths("foo", "bar", "foo"); - ExampleSpec configuredExampleSpec = exampleSpec.withIgnoreCase(); - - assertThat(exampleSpec, is(not(sameInstance(configuredExampleSpec)))); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(2)); - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - - assertThat(configuredExampleSpec.getIgnoredPaths(), hasSize(2)); - assertThat(configuredExampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - static class Person { - - String firstname; - } -} diff --git a/src/test/java/org/springframework/data/domain/ExampleUnitTests.java b/src/test/java/org/springframework/data/domain/ExampleUnitTests.java index 8cff9970e..acee1adfb 100644 --- a/src/test/java/org/springframework/data/domain/ExampleUnitTests.java +++ b/src/test/java/org/springframework/data/domain/ExampleUnitTests.java @@ -15,9 +15,8 @@ */ package org.springframework.data.domain; -import static org.hamcrest.core.IsEqual.*; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; -import static org.springframework.data.domain.Example.*; import org.junit.Before; import org.junit.Test; @@ -27,11 +26,12 @@ import org.junit.Test; * * @author Christoph Strobl * @author Mark Paluch + * @author Oliver Gierke */ public class ExampleUnitTests { - private Person person; - private Example example; + Person person; + Example example; @Before public void setUp() { @@ -39,14 +39,14 @@ public class ExampleUnitTests { person = new Person(); person.firstname = "rand"; - example = of(person); + example = Example.of(person); } /** * @see DATACMNS-810 */ @Test(expected = IllegalArgumentException.class) - public void exampleOfNullThrowsException() { + public void rejectsNullProbe() { Example.of(null); } @@ -54,44 +54,11 @@ public class ExampleUnitTests { * @see DATACMNS-810 */ @Test - public void getSampleTypeRetunsSampleObjectsClass() { - assertThat(example.getProbeType(), equalTo(Person.class)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void createTypedExample() { - - Example example = of(new Person(), ExampleSpec.typed(Contact.class)); - - assertThat(example.getProbeType(), equalTo(Person.class)); - assertThat(example.getResultType(), equalTo((Class) Contact.class)); - assertThat(example.getProbeType(), equalTo(Person.class)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void createUntypedExample() { - - Example example = of(new Person(), ExampleSpec.untyped()); - - assertThat(example.getProbeType(), equalTo(Person.class)); - assertThat(example.getResultType(), equalTo((Class) Person.class)); - assertThat(example.getProbeType(), equalTo(Person.class)); - } - - static class Contact { - - String label; + public void retunsSampleObjectsClassAsProbeType() { + assertThat(example.getProbeType(), is(equalTo(Person.class))); } static class Person { - String firstname; } - } diff --git a/src/test/java/org/springframework/data/domain/TypedExampleSpecUnitTests.java b/src/test/java/org/springframework/data/domain/TypedExampleSpecUnitTests.java deleted file mode 100644 index aea31209a..000000000 --- a/src/test/java/org/springframework/data/domain/TypedExampleSpecUnitTests.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2016 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.domain; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.*; -import static org.hamcrest.Matchers.*; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.sameInstance; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.data.domain.ExampleSpec.NullHandler; -import org.springframework.data.domain.ExampleSpec.StringMatcher; - -/** - * Unit test for {@link ExampleSpec}. - * - * @author Mark Paluch - * @soundtrack Harmonic Rush - The Dark Side of Persia (ahmed romel remix) - */ -public class TypedExampleSpecUnitTests { - - TypedExampleSpec exampleSpec; - - @Before - public void setUp() throws Exception { - exampleSpec = ExampleSpec.typed(Person.class); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void typeShouldReturnConfiguredType() throws Exception { - assertThat(exampleSpec.getType(), equalTo(Person.class)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnDefault() throws Exception { - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.DEFAULT)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnContainingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcherContaining(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnStartingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcherStarting(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.STARTING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnEndingWhenConfigured() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcherEnding(); - assertThat(exampleSpec.getDefaultStringMatcher(), is(StringMatcher.ENDING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnFalseByDefault() throws Exception { - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsIsEmptyByDefault() throws Exception { - assertThat(exampleSpec.getIgnoredPaths(), is(empty())); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnIgnoreByDefault() throws Exception { - assertThat(exampleSpec.getNullHandler(), is(NullHandler.IGNORE)); - } - - /** - * @see DATACMNS-810 - */ - @Test(expected = UnsupportedOperationException.class) - public void ignoredPathsIsNotModifiable() throws Exception { - exampleSpec.getIgnoredPaths().add("¯\\_(ツ)_/¯"); - } - - /** - * @see DATACMNS-810 - */ - @Test(expected = IllegalArgumentException.class) - public void defaultExampleSpecWithoutTypeFails() throws Exception { - ExampleSpec.typed(null); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseEnabled() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase(); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseSet() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase(true); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnInclude() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIncludeNullValues(); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnIgnore() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreNullValues(); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.IGNORE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnConfiguredValue() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withNullHandler(NullHandler.INCLUDE); - - assertThat(exampleSpec.getNullHandler(), is(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsShouldReturnCorrectProperties() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnorePaths("foo", "bar", "baz"); - - assertThat(exampleSpec.getIgnoredPaths(), contains("foo", "bar", "baz")); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(3)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoredPathsShouldReturnUniqueProperties() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnorePaths("foo", "bar", "foo"); - - assertThat(exampleSpec.getIgnoredPaths(), contains("foo", "bar")); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(2)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void withCreatesNewInstance() throws Exception { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnorePaths("foo", "bar", "foo"); - TypedExampleSpec configuredExampleSpec = exampleSpec.withIgnoreCase(); - - assertThat(exampleSpec, is(not(sameInstance(configuredExampleSpec)))); - assertThat(exampleSpec.getIgnoredPaths(), hasSize(2)); - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - - assertThat(configuredExampleSpec.getIgnoredPaths(), hasSize(2)); - assertThat(configuredExampleSpec.isIgnoreCaseEnabled(), is(true)); - } - - static class Person { - - String firstname; - } -} diff --git a/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorTypedExampleSpecUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorTypedExampleSpecUnitTests.java deleted file mode 100644 index 195d6fb22..000000000 --- a/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorTypedExampleSpecUnitTests.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2016 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.repository.core.support; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.data.domain.ExampleSpec; -import org.springframework.data.domain.ExampleSpec.GenericPropertyMatcher; -import org.springframework.data.domain.ExampleSpec.GenericPropertyMatchers; -import org.springframework.data.domain.ExampleSpec.MatcherConfigurer; -import org.springframework.data.domain.ExampleSpec.NoOpPropertyValueTransformer; -import org.springframework.data.domain.ExampleSpec.NullHandler; -import org.springframework.data.domain.ExampleSpec.PropertyValueTransformer; -import org.springframework.data.domain.ExampleSpec.StringMatcher; -import org.springframework.data.domain.TypedExampleSpec; - -/** - * Test for {@link ExampleSpecAccessor}. - * - * @author Mark Paluch - * @soundtrack Cabballero - Dancing With Tears In My Eyes (Dance Maxi) - */ -public class ExampleSpecAccessorTypedExampleSpecUnitTests { - - private Person person; - private TypedExampleSpec exampleSpec; - private ExampleSpecAccessor exampleSpecAccessor; - - @Before - public void setUp() { - - person = new Person(); - person.firstname = "rand"; - - exampleSpec = ExampleSpec.typed(Person.class); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void isTypedShouldReturnTrue() { - assertThat(exampleSpecAccessor.isTyped(), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnDefault() { - assertThat(exampleSpecAccessor.getDefaultStringMatcher(), equalTo(StringMatcher.DEFAULT)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnInclude() { - - exampleSpec = ExampleSpec.typed(Person.class).withIncludeNullValues(); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getNullHandler(), equalTo(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldIgnorePaths() { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnorePaths("firstname"); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoredPath("firstname"), equalTo(true)); - assertThat(exampleSpecAccessor.isIgnoredPath("lastname"), equalTo(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultStringMatcherForPathThatDoesNotHavePropertySpecifier() { - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), - equalTo(exampleSpec.getDefaultStringMatcher())); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseConfiguredStringMatcherAsDefaultForPathThatDoesNotHavePropertySpecifier() { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcher(StringMatcher.CONTAINING); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase().withMatcher("firstname", - new GenericPropertyMatcher().contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), equalTo(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseConfiguredIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase().withMatcher("firstname", - new GenericPropertyMatcher().contains().caseSensitive()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), equalTo(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherStarting() { - - exampleSpec = ExampleSpec.typed(Person.class).withMatcher("firstname", GenericPropertyMatchers.startsWith()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherContaining() { - - exampleSpec = ExampleSpec.typed(Person.class).withMatcher("firstname", GenericPropertyMatchers.contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherRegex() { - - exampleSpec = ExampleSpec.typed(Person.class).withMatcher("firstname", GenericPropertyMatchers.regex()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.REGEX)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldFavorStringMatcherDefinedForPathOverConfiguredDefaultStringMatcher() { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcher(StringMatcher.ENDING) - .withMatcher("firstname", new GenericPropertyMatcher().contains()) - .withMatcher("address.city", new GenericPropertyMatcher().startsWith()) - .withMatcher("lastname", new MatcherConfigurer() { - @Override - public void configureMatcher(GenericPropertyMatcher matcher) { - matcher.ignoreCase(); - } - }); - - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getPropertySpecifiers(), hasSize(3)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("lastname"), equalTo(StringMatcher.ENDING)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("unknownProperty"), equalTo(StringMatcher.ENDING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultStringMatcherForPathThatHasPropertySpecifierWithoutStringMatcher() { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcher(StringMatcher.STARTING).withMatcher("firstname", - new MatcherConfigurer() { - @Override - public void configureMatcher(GenericPropertyMatcher matcher) { - matcher.ignoreCase(); - } - }); - - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("unknownProperty"), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnFalseByDefault() { - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseIsEnabled() { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase(); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseEnabled(), is(true)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldFavorPathSpecificSettings() { - - exampleSpec = ExampleSpec.typed(Person.class).withIgnoreCase("firstname"); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void getValueTransformerForPathReturnsNoOpValueTransformerByDefault() { - assertThat(exampleSpecAccessor.getValueTransformerForPath("firstname"), - instanceOf(NoOpPropertyValueTransformer.class)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void getValueTransformerForPathReturnsConfigurtedTransformerForPath() { - - PropertyValueTransformer transformer = new PropertyValueTransformer() { - - @Override - public Object convert(Object source) { - return source.toString(); - } - }; - - exampleSpec = ExampleSpec.typed(Person.class).withTransformer("firstname", transformer); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getValueTransformerForPath("firstname"), equalTo(transformer)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void hasPropertySpecifiersReturnsFalseIfNoneDefined() { - assertThat(exampleSpecAccessor.hasPropertySpecifiers(), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void hasPropertySpecifiersReturnsTrueWhenAtLeastOneIsSet() { - - exampleSpec = ExampleSpec.typed(Person.class).withStringMatcher(StringMatcher.STARTING).withMatcher("firstname", - new GenericPropertyMatcher().contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.hasPropertySpecifiers(), is(true)); - } - - static class Person { - - String firstname; - } - -} diff --git a/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorUntypedExampleSpecUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorUntypedExampleSpecUnitTests.java deleted file mode 100644 index c7536b93a..000000000 --- a/src/test/java/org/springframework/data/repository/core/support/ExampleSpecAccessorUntypedExampleSpecUnitTests.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2016 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.repository.core.support; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.data.domain.ExampleSpec; -import org.springframework.data.domain.ExampleSpec.GenericPropertyMatcher; -import org.springframework.data.domain.ExampleSpec.GenericPropertyMatchers; -import org.springframework.data.domain.ExampleSpec.MatcherConfigurer; -import org.springframework.data.domain.ExampleSpec.NoOpPropertyValueTransformer; -import org.springframework.data.domain.ExampleSpec.NullHandler; -import org.springframework.data.domain.ExampleSpec.PropertyValueTransformer; -import org.springframework.data.domain.ExampleSpec.StringMatcher; - -/** - * Test for {@link ExampleSpecAccessor}. - * - * @author Mark Paluch - * @soundtrack Alex Wackii and Tolga Uzulmez - Diamond Rush (original mix) - */ -public class ExampleSpecAccessorUntypedExampleSpecUnitTests { - - private Person person; - private ExampleSpec exampleSpec; - private ExampleSpecAccessor exampleSpecAccessor; - - @Before - public void setUp() { - - person = new Person(); - person.firstname = "rand"; - - exampleSpec = ExampleSpec.untyped(); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void defaultStringMatcherShouldReturnDefault() { - assertThat(exampleSpecAccessor.getDefaultStringMatcher(), equalTo(StringMatcher.DEFAULT)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void nullHandlerShouldReturnInclude() { - - exampleSpec = ExampleSpec.untyped().withIncludeNullValues(); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getNullHandler(), equalTo(NullHandler.INCLUDE)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldIgnorePaths() { - - exampleSpec = ExampleSpec.untyped().withIgnorePaths("firstname"); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoredPath("firstname"), equalTo(true)); - assertThat(exampleSpecAccessor.isIgnoredPath("lastname"), equalTo(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultStringMatcherForPathThatDoesNotHavePropertySpecifier() { - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), - equalTo(exampleSpec.getDefaultStringMatcher())); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseConfiguredStringMatcherAsDefaultForPathThatDoesNotHavePropertySpecifier() { - - exampleSpec = ExampleSpec.untyped().withStringMatcher(StringMatcher.CONTAINING); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase().withMatcher("firstname", - new GenericPropertyMatcher().contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), equalTo(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseConfiguredIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase().withMatcher("firstname", - new GenericPropertyMatcher().contains().caseSensitive()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), equalTo(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherStarting() { - - exampleSpec = ExampleSpec.untyped().withMatcher("firstname", GenericPropertyMatchers.startsWith()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherContaining() { - - exampleSpec = ExampleSpec.untyped().withMatcher("firstname", GenericPropertyMatchers.contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherRegex() { - - exampleSpec = ExampleSpec.untyped().withMatcher("firstname", GenericPropertyMatchers.regex()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.REGEX)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldFavorStringMatcherDefinedForPathOverConfiguredDefaultStringMatcher() { - - exampleSpec = ExampleSpec.untyped().withStringMatcher(StringMatcher.ENDING) - .withMatcher("firstname", new GenericPropertyMatcher().contains()) - .withMatcher("address.city", new GenericPropertyMatcher().startsWith()) - .withMatcher("lastname", new MatcherConfigurer() { - @Override - public void configureMatcher(GenericPropertyMatcher matcher) { - matcher.ignoreCase(); - } - }); - - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getPropertySpecifiers(), hasSize(3)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("lastname"), equalTo(StringMatcher.ENDING)); - assertThat(exampleSpecAccessor.getStringMatcherForPath("unknownProperty"), equalTo(StringMatcher.ENDING)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void exampleShouldUseDefaultStringMatcherForPathThatHasPropertySpecifierWithoutStringMatcher() { - - exampleSpec = ExampleSpec.untyped().withStringMatcher(StringMatcher.STARTING).withMatcher("firstname", - new MatcherConfigurer() { - @Override - public void configureMatcher(GenericPropertyMatcher matcher) { - matcher.ignoreCase(); - } - }); - - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("unknownProperty"), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnFalseByDefault() { - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldReturnTrueWhenIgnoreCaseIsEnabled() { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase(); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.isIgnoreCaseEnabled(), is(true)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void ignoreCaseShouldFavorPathSpecificSettings() { - - exampleSpec = ExampleSpec.untyped().withIgnoreCase("firstname"); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpec.isIgnoreCaseEnabled(), is(false)); - assertThat(exampleSpecAccessor.isIgnoreCaseForPath("firstname"), is(true)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void getValueTransformerForPathReturnsNoOpValueTransformerByDefault() { - assertThat(exampleSpecAccessor.getValueTransformerForPath("firstname"), - instanceOf(NoOpPropertyValueTransformer.class)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void getValueTransformerForPathReturnsConfigurtedTransformerForPath() { - - PropertyValueTransformer transformer = new PropertyValueTransformer() { - - @Override - public Object convert(Object source) { - return source.toString(); - } - }; - - exampleSpec = ExampleSpec.untyped().withTransformer("firstname", transformer); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.getValueTransformerForPath("firstname"), equalTo(transformer)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void hasPropertySpecifiersReturnsFalseIfNoneDefined() { - assertThat(exampleSpecAccessor.hasPropertySpecifiers(), is(false)); - } - - /** - * @see DATACMNS-810 - */ - @Test - public void hasPropertySpecifiersReturnsTrueWhenAtLeastOneIsSet() { - - exampleSpec = ExampleSpec.untyped().withStringMatcher(StringMatcher.STARTING).withMatcher("firstname", - new GenericPropertyMatcher().contains()); - exampleSpecAccessor = new ExampleSpecAccessor(exampleSpec); - - assertThat(exampleSpecAccessor.hasPropertySpecifiers(), is(true)); - } - - static class Person { - - String firstname; - } - -} diff --git a/src/test/java/org/springframework/data/repository/core/support/ExampleSpecificationAccessorUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/ExampleSpecificationAccessorUnitTests.java new file mode 100644 index 000000000..945fe1f74 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/core/support/ExampleSpecificationAccessorUnitTests.java @@ -0,0 +1,328 @@ +/* + * Copyright 2016 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.repository.core.support; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*; +import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.contains; +import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatcher; +import org.springframework.data.domain.ExampleMatcher.MatcherConfigurer; +import org.springframework.data.domain.ExampleMatcher.NoOpPropertyValueTransformer; +import org.springframework.data.domain.ExampleMatcher.NullHandler; +import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer; +import org.springframework.data.domain.ExampleMatcher.StringMatcher; + +/** + * Unit tests for {@link ExampleMatcherAccessor}. + * + * @author Oliver Gierke + * @author Mark Paluch + * @soundtrack Ron Spielman Trio - Fretboard Highway (Electric Tales) + */ +@SuppressWarnings("unused") +public class ExampleSpecificationAccessorUnitTests { + + Person person; + ExampleMatcher specification; + ExampleMatcherAccessor exampleSpecificationAccessor; + + @Before + public void setUp() { + + person = new Person(); + person.firstname = "rand"; + + specification = ExampleMatcher.matching(); + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void defaultStringMatcherShouldReturnDefault() { + assertThat(exampleSpecificationAccessor.getDefaultStringMatcher(), is(StringMatcher.DEFAULT)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void nullHandlerShouldReturnInclude() { + + specification = ExampleMatcher.matching().// + withIncludeNullValues(); + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getNullHandler(), is(NullHandler.INCLUDE)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldIgnorePaths() { + + specification = ExampleMatcher.matching().withIgnorePaths("firstname"); + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.isIgnoredPath("firstname"), is(true)); + assertThat(exampleSpecificationAccessor.isIgnoredPath("lastname"), is(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefaultStringMatcherForPathThatDoesNotHavePropertySpecifier() { + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), + is(specification.getDefaultStringMatcher())); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseConfiguredStringMatcherAsDefaultForPathThatDoesNotHavePropertySpecifier() { + + specification = ExampleMatcher.matching().// + withStringMatcher(StringMatcher.CONTAINING); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), is(StringMatcher.CONTAINING)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefaultIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { + + specification = ExampleMatcher.matching().// + withIgnoreCase().// + withMatcher("firstname", contains()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), is(true)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseConfiguredIgnoreCaseForPathThatDoesHavePropertySpecifierWithMatcher() { + + specification = ExampleMatcher.matching().// + withIgnoreCase().// + withMatcher("firstname", contains().caseSensitive()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), equalTo(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherStarting() { + + specification = ExampleMatcher.matching().// + withMatcher("firstname", startsWith()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherContaining() { + + specification = ExampleMatcher.matching().// + withMatcher("firstname", contains()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefinedStringMatcherForPathThatDoesHavePropertySpecifierWithStringMatcherRegex() { + + specification = ExampleMatcher.matching().// + withMatcher("firstname", regex()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.REGEX)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldFavorStringMatcherDefinedForPathOverConfiguredDefaultStringMatcher() { + + specification = ExampleMatcher.matching().withStringMatcher(StringMatcher.ENDING) + .withMatcher("firstname", contains()).withMatcher("address.city", startsWith()) + .withMatcher("lastname", new MatcherConfigurer() { + @Override + public void configureMatcher(GenericPropertyMatcher matcher) { + matcher.ignoreCase(); + } + }); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getPropertySpecifiers(), hasSize(3)); + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.CONTAINING)); + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("lastname"), equalTo(StringMatcher.ENDING)); + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("unknownProperty"), equalTo(StringMatcher.ENDING)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void exampleShouldUseDefaultStringMatcherForPathThatHasPropertySpecifierWithoutStringMatcher() { + + specification = ExampleMatcher.matching().// + withStringMatcher(StringMatcher.STARTING).// + withMatcher("firstname", new MatcherConfigurer() { + @Override + public void configureMatcher(GenericPropertyMatcher matcher) { + matcher.ignoreCase(); + } + }); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getStringMatcherForPath("firstname"), equalTo(StringMatcher.STARTING)); + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), is(true)); + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("unknownProperty"), is(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldReturnFalseByDefault() { + + assertThat(specification.isIgnoreCaseEnabled(), is(false)); + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), is(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldReturnTrueWhenIgnoreCaseIsEnabled() { + + specification = ExampleMatcher.matching().// + withIgnoreCase(); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.isIgnoreCaseEnabled(), is(true)); + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), is(true)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void ignoreCaseShouldFavorPathSpecificSettings() { + + specification = ExampleMatcher.matching().// + withIgnoreCase("firstname"); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(specification.isIgnoreCaseEnabled(), is(false)); + assertThat(exampleSpecificationAccessor.isIgnoreCaseForPath("firstname"), is(true)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void getValueTransformerForPathReturnsNoOpValueTransformerByDefault() { + assertThat(exampleSpecificationAccessor.getValueTransformerForPath("firstname"), + instanceOf(NoOpPropertyValueTransformer.class)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void getValueTransformerForPathReturnsConfigurtedTransformerForPath() { + + PropertyValueTransformer transformer = new PropertyValueTransformer() { + + @Override + public Object convert(Object source) { + return source.toString(); + } + }; + + specification = ExampleMatcher.matching().// + withTransformer("firstname", transformer); + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.getValueTransformerForPath("firstname"), equalTo(transformer)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void hasPropertySpecifiersReturnsFalseIfNoneDefined() { + assertThat(exampleSpecificationAccessor.hasPropertySpecifiers(), is(false)); + } + + /** + * @see DATACMNS-810 + */ + @Test + public void hasPropertySpecifiersReturnsTrueWhenAtLeastOneIsSet() { + + specification = ExampleMatcher.matching().// + withStringMatcher(StringMatcher.STARTING).// + withMatcher("firstname", contains()); + + exampleSpecificationAccessor = new ExampleMatcherAccessor(specification); + + assertThat(exampleSpecificationAccessor.hasPropertySpecifiers(), is(true)); + } + + static class Person { + String firstname; + } +}