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; + } +}