From e28bede416e4ddac19a35dc239388afc90b9cac4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Aug 2017 16:35:38 +0200 Subject: [PATCH] DATAMONGO-1768 - Polishing. Use Lombok to generate constructors. Extend javadocs. Make methods static/reorder methods where possible. Use diamond syntax where possible. Formatting. Original pull request: #496. --- .../core/convert/MongoExampleMapper.java | 231 +++++++++--------- .../core/query/UntypedExampleMatcher.java | 27 +- .../convert/MongoExampleMapperUnitTests.java | 2 +- 3 files changed, 132 insertions(+), 128 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java index 8d9039441..493d0ddfd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java @@ -48,16 +48,26 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** + * Mapper from {@link Example} to a query {@link Document}. + * * @author Christoph Strobl * @author Mark Paluch * @author Jens Schauder * @since 1.8 + * @see Example + * @see org.springframework.data.domain.ExampleMatcher + * @see UntypedExampleMatcher */ public class MongoExampleMapper { private final MappingContext, MongoPersistentProperty> mappingContext; private final MongoConverter converter; + /** + * Create a new {@link MongoTypeMapper} given {@link MongoConverter}. + * + * @param converter must not be {@literal null}. + */ public MongoExampleMapper(MongoConverter converter) { this.converter = converter; @@ -112,80 +122,14 @@ public class MongoExampleMapper { return updateTypeRestrictions(result, example); } - private static Document orConcatenate(Document source) { - - List foo = new ArrayList(source.keySet().size()); - - for (String key : source.keySet()) { - foo.add(new Document(key, source.get(key))); - } - - return new Document("$or", foo); - } - - private Set> getTypesToMatch(Example example) { - - Set> types = new HashSet>(); - - for (TypeInformation reference : mappingContext.getManagedTypes()) { - if (example.getProbeType().isAssignableFrom(reference.getType())) { - types.add(reference.getType()); - } - } - - return types; - } - - private String getMappedPropertyPath(String path, Class probeType) { - - MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(probeType); - - Iterator parts = Arrays.asList(path.split("\\.")).iterator(); - - final Stack stack = new Stack(); - - List resultParts = new ArrayList(); - - while (parts.hasNext()) { - - String part = parts.next(); - MongoPersistentProperty prop = entity.getPersistentProperty(part); - - if (prop == null) { - - entity.doWithProperties((PropertyHandler) property -> { - if (property.getFieldName().equals(part)) { - stack.push(property); - } - }); - - if (stack.isEmpty()) { - return ""; - } - - prop = stack.pop(); - } - - resultParts.add(prop.getName()); - - if (prop.isEntity() && mappingContext.hasPersistentEntityFor(prop.getActualType())) { - entity = mappingContext.getRequiredPersistentEntity(prop.getActualType()); - } else { - break; - } - } - - return StringUtils.collectionToDelimitedString(resultParts, "."); - } - private void applyPropertySpecs(String path, Document source, Class probeType, ExampleMatcherAccessor exampleSpecAccessor) { - if (!(source instanceof Document)) { + if (source == null) { return; } - Iterator> iter = ((Document) source).entrySet().iterator(); + Iterator> iter = source.entrySet().iterator(); while (iter.hasNext()) { @@ -237,56 +181,46 @@ public class MongoExampleMapper { } } - private boolean isEmptyIdProperty(Entry entry) { - return entry.getKey().equals("_id") && entry.getValue() == null || entry.getValue().equals(Optional.empty()); - } + private String getMappedPropertyPath(String path, Class probeType) { - private void applyStringMatcher(Map.Entry entry, StringMatcher stringMatcher, boolean ignoreCase) { + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(probeType); - Document document = new Document(); + Iterator parts = Arrays.asList(path.split("\\.")).iterator(); - if (StringMatcher.DEFAULT == stringMatcher) { + final Stack stack = new Stack<>(); - if (ignoreCase) { - document.put("$regex", Pattern.quote((String) entry.getValue())); - entry.setValue(document); + List resultParts = new ArrayList<>(); + + while (parts.hasNext()) { + + String part = parts.next(); + MongoPersistentProperty prop = entity.getPersistentProperty(part); + + if (prop == null) { + + entity.doWithProperties((PropertyHandler) property -> { + if (property.getFieldName().equals(part)) { + stack.push(property); + } + }); + + if (stack.isEmpty()) { + return ""; + } + + prop = stack.pop(); } - } else { - String expression = MongoRegexCreator.INSTANCE.toRegularExpression((String) entry.getValue(), - toMatchMode(stringMatcher)); - document.put("$regex", expression); - entry.setValue(document); + resultParts.add(prop.getName()); + + if (prop.isEntity() && mappingContext.hasPersistentEntityFor(prop.getActualType())) { + entity = mappingContext.getRequiredPersistentEntity(prop.getActualType()); + } else { + break; + } } - if (ignoreCase) { - document.put("$options", "i"); - } - } - - /** - * Return the {@link MatchMode} for the given {@link StringMatcher}. - * - * @param matcher must not be {@literal null}. - * @return - */ - private static MatchMode toMatchMode(StringMatcher matcher) { - - switch (matcher) { - case CONTAINING: - return MatchMode.CONTAINING; - case STARTING: - return MatchMode.STARTING_WITH; - case ENDING: - return MatchMode.ENDING_WITH; - case EXACT: - return MatchMode.EXACT; - case REGEX: - return MatchMode.REGEX; - case DEFAULT: - default: - return MatchMode.DEFAULT; - } + return StringUtils.collectionToDelimitedString(resultParts, "."); } private Document updateTypeRestrictions(Document query, Example example) { @@ -327,4 +261,81 @@ public class MongoExampleMapper { return true; } + + private Set> getTypesToMatch(Example example) { + + Set> types = new HashSet<>(); + + for (TypeInformation reference : mappingContext.getManagedTypes()) { + if (example.getProbeType().isAssignableFrom(reference.getType())) { + types.add(reference.getType()); + } + } + + return types; + } + + private static boolean isEmptyIdProperty(Entry entry) { + return entry.getKey().equals("_id") && entry.getValue() == null || entry.getValue().equals(Optional.empty()); + } + + private static void applyStringMatcher(Map.Entry entry, StringMatcher stringMatcher, + boolean ignoreCase) { + + Document document = new Document(); + + if (StringMatcher.DEFAULT == stringMatcher) { + + if (ignoreCase) { + document.put("$regex", Pattern.quote((String) entry.getValue())); + entry.setValue(document); + } + } else { + + String expression = MongoRegexCreator.INSTANCE.toRegularExpression((String) entry.getValue(), + toMatchMode(stringMatcher)); + document.put("$regex", expression); + entry.setValue(document); + } + + if (ignoreCase) { + document.put("$options", "i"); + } + } + + private static Document orConcatenate(Document source) { + + List or = new ArrayList<>(source.keySet().size()); + + for (String key : source.keySet()) { + or.add(new Document(key, source.get(key))); + } + + return new Document("$or", or); + } + + /** + * Return the {@link MatchMode} for the given {@link StringMatcher}. + * + * @param matcher must not be {@literal null}. + * @return + */ + private static MatchMode toMatchMode(StringMatcher matcher) { + + switch (matcher) { + case CONTAINING: + return MatchMode.CONTAINING; + case STARTING: + return MatchMode.STARTING_WITH; + case ENDING: + return MatchMode.ENDING_WITH; + case EXACT: + return MatchMode.EXACT; + case REGEX: + return MatchMode.REGEX; + case DEFAULT: + default: + return MatchMode.DEFAULT; + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java index 34a031441..893fff69c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java @@ -15,36 +15,29 @@ */ package org.springframework.data.mongodb.core.query; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.Set; import org.springframework.data.domain.ExampleMatcher; -import org.springframework.util.Assert; /** * {@link ExampleMatcher} implementation for query by example (QBE). Unlike plain {@link ExampleMatcher} this untyped - * counterpart does not enforce a strict type match when executing the query. This allows to use totally unrelated - * example documents as references for querying collections as long as the used field/property names match. + * counterpart does not enforce type matching when executing the query. This allows to query unrelated example documents + * as references for querying collections as long as the used field/property names match. * * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ @EqualsAndHashCode +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class UntypedExampleMatcher implements ExampleMatcher { - private final ExampleMatcher delegate; - - /** - * Creates new {@link UntypedExampleMatcher}. - * - * @param delegate must not be {@literal null}. - */ - private UntypedExampleMatcher(ExampleMatcher delegate) { - - Assert.notNull(delegate, "Delegate must not be null!"); - this.delegate = delegate; - } + private final @NonNull ExampleMatcher delegate; /* * (non-Javadoc) @@ -167,7 +160,7 @@ public class UntypedExampleMatcher implements ExampleMatcher { return delegate.getNullHandler(); } - /* + /* * (non-Javadoc) * @see org.springframework.data.domain.ExampleMatcher#getDefaultStringMatcher() */ @@ -175,7 +168,7 @@ public class UntypedExampleMatcher implements ExampleMatcher { return delegate.getDefaultStringMatcher(); } - /* + /* * (non-Javadoc) * @see org.springframework.data.domain.ExampleMatcher#isIgnoreCaseEnabled() */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java index 8e8ba379e..21249ab47 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java @@ -484,7 +484,7 @@ public class MongoExampleMapperUnitTests { } @Test // DATAMONGO-1768 - public void untypedExampleShouldNotInfereTypeRestriction() { + public void untypedExampleShouldNotInferTypeRestriction() { WrapperDocument probe = new WrapperDocument(); probe.flatDoc = new FlatDocument();