Browse Source

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.
pull/691/head
Mark Paluch 8 years ago
parent
commit
e28bede416
  1. 207
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java
  2. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java
  3. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java

207
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java

@ -48,16 +48,26 @@ import org.springframework.util.ObjectUtils; @@ -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<? extends MongoPersistentEntity<?>, 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,28 +122,63 @@ public class MongoExampleMapper { @@ -112,28 +122,63 @@ public class MongoExampleMapper {
return updateTypeRestrictions(result, example);
}
private static Document orConcatenate(Document source) {
List<Document> foo = new ArrayList<Document>(source.keySet().size());
private void applyPropertySpecs(String path, Document source, Class<?> probeType,
ExampleMatcherAccessor exampleSpecAccessor) {
for (String key : source.keySet()) {
foo.add(new Document(key, source.get(key)));
if (source == null) {
return;
}
return new Document("$or", foo);
}
Iterator<Map.Entry<String, Object>> iter = source.entrySet().iterator();
private Set<Class<?>> getTypesToMatch(Example<?> example) {
while (iter.hasNext()) {
Set<Class<?>> types = new HashSet<Class<?>>();
Map.Entry<String, Object> entry = iter.next();
String propertyPath = StringUtils.hasText(path) ? path + "." + entry.getKey() : entry.getKey();
String mappedPropertyPath = getMappedPropertyPath(propertyPath, probeType);
for (TypeInformation<?> reference : mappingContext.getManagedTypes()) {
if (example.getProbeType().isAssignableFrom(reference.getType())) {
types.add(reference.getType());
if (isEmptyIdProperty(entry)) {
iter.remove();
continue;
}
}
return types;
if (exampleSpecAccessor.isIgnoredPath(propertyPath) || exampleSpecAccessor.isIgnoredPath(mappedPropertyPath)) {
iter.remove();
continue;
}
StringMatcher stringMatcher = exampleSpecAccessor.getDefaultStringMatcher();
Object value = entry.getValue();
boolean ignoreCase = exampleSpecAccessor.isIgnoreCaseEnabled();
if (exampleSpecAccessor.hasPropertySpecifiers()) {
mappedPropertyPath = exampleSpecAccessor.hasPropertySpecifier(propertyPath) ? propertyPath
: getMappedPropertyPath(propertyPath, probeType);
stringMatcher = exampleSpecAccessor.getStringMatcherForPath(mappedPropertyPath);
ignoreCase = exampleSpecAccessor.isIgnoreCaseForPath(mappedPropertyPath);
}
// TODO: should a PropertySpecifier outrule the later on string matching?
if (exampleSpecAccessor.hasPropertySpecifier(mappedPropertyPath)) {
PropertyValueTransformer valueTransformer = exampleSpecAccessor.getValueTransformerForPath(mappedPropertyPath);
value = valueTransformer.convert(value);
if (value == null) {
iter.remove();
continue;
}
entry.setValue(value);
}
if (entry.getValue() instanceof String) {
applyStringMatcher(entry, stringMatcher, ignoreCase);
} else if (entry.getValue() instanceof Document) {
applyPropertySpecs(propertyPath, (Document) entry.getValue(), probeType, exampleSpecAccessor);
}
}
}
private String getMappedPropertyPath(String path, Class<?> probeType) {
@ -142,9 +187,9 @@ public class MongoExampleMapper { @@ -142,9 +187,9 @@ public class MongoExampleMapper {
Iterator<String> parts = Arrays.asList(path.split("\\.")).iterator();
final Stack<MongoPersistentProperty> stack = new Stack<MongoPersistentProperty>();
final Stack<MongoPersistentProperty> stack = new Stack<>();
List<String> resultParts = new ArrayList<String>();
List<String> resultParts = new ArrayList<>();
while (parts.hasNext()) {
@ -178,70 +223,64 @@ public class MongoExampleMapper { @@ -178,70 +223,64 @@ public class MongoExampleMapper {
return StringUtils.collectionToDelimitedString(resultParts, ".");
}
private void applyPropertySpecs(String path, Document source, Class<?> probeType,
ExampleMatcherAccessor exampleSpecAccessor) {
if (!(source instanceof Document)) {
return;
}
private Document updateTypeRestrictions(Document query, Example example) {
Iterator<Map.Entry<String, Object>> iter = ((Document) source).entrySet().iterator();
Document result = new Document();
while (iter.hasNext()) {
if (isTypeRestricting(example)) {
Map.Entry<String, Object> entry = iter.next();
String propertyPath = StringUtils.hasText(path) ? path + "." + entry.getKey() : entry.getKey();
String mappedPropertyPath = getMappedPropertyPath(propertyPath, probeType);
result.putAll(query);
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
return result;
}
if (isEmptyIdProperty(entry)) {
iter.remove();
continue;
for (Map.Entry<String, Object> entry : query.entrySet()) {
if (!this.converter.getTypeMapper().isTypeKey(entry.getKey())) {
result.put(entry.getKey(), entry.getValue());
}
}
if (exampleSpecAccessor.isIgnoredPath(propertyPath) || exampleSpecAccessor.isIgnoredPath(mappedPropertyPath)) {
iter.remove();
continue;
}
return result;
}
StringMatcher stringMatcher = exampleSpecAccessor.getDefaultStringMatcher();
Object value = entry.getValue();
boolean ignoreCase = exampleSpecAccessor.isIgnoreCaseEnabled();
private boolean isTypeRestricting(Example example) {
if (exampleSpecAccessor.hasPropertySpecifiers()) {
if (example.getMatcher() instanceof UntypedExampleMatcher) {
return false;
}
mappedPropertyPath = exampleSpecAccessor.hasPropertySpecifier(propertyPath) ? propertyPath
: getMappedPropertyPath(propertyPath, probeType);
if (example.getMatcher().getIgnoredPaths().isEmpty()) {
return true;
}
stringMatcher = exampleSpecAccessor.getStringMatcherForPath(mappedPropertyPath);
ignoreCase = exampleSpecAccessor.isIgnoreCaseForPath(mappedPropertyPath);
for (String path : example.getMatcher().getIgnoredPaths()) {
if (this.converter.getTypeMapper().isTypeKey(path)) {
return false;
}
}
// TODO: should a PropertySpecifier outrule the later on string matching?
if (exampleSpecAccessor.hasPropertySpecifier(mappedPropertyPath)) {
return true;
}
PropertyValueTransformer valueTransformer = exampleSpecAccessor.getValueTransformerForPath(mappedPropertyPath);
value = valueTransformer.convert(value);
if (value == null) {
iter.remove();
continue;
}
private Set<Class<?>> getTypesToMatch(Example<?> example) {
entry.setValue(value);
}
Set<Class<?>> types = new HashSet<>();
if (entry.getValue() instanceof String) {
applyStringMatcher(entry, stringMatcher, ignoreCase);
} else if (entry.getValue() instanceof Document) {
applyPropertySpecs(propertyPath, (Document) entry.getValue(), probeType, exampleSpecAccessor);
for (TypeInformation<?> reference : mappingContext.getManagedTypes()) {
if (example.getProbeType().isAssignableFrom(reference.getType())) {
types.add(reference.getType());
}
}
return types;
}
private boolean isEmptyIdProperty(Entry<String, Object> entry) {
private static boolean isEmptyIdProperty(Entry<String, Object> entry) {
return entry.getKey().equals("_id") && entry.getValue() == null || entry.getValue().equals(Optional.empty());
}
private void applyStringMatcher(Map.Entry<String, Object> entry, StringMatcher stringMatcher, boolean ignoreCase) {
private static void applyStringMatcher(Map.Entry<String, Object> entry, StringMatcher stringMatcher,
boolean ignoreCase) {
Document document = new Document();
@ -264,9 +303,20 @@ public class MongoExampleMapper { @@ -264,9 +303,20 @@ public class MongoExampleMapper {
}
}
private static Document orConcatenate(Document source) {
List<Document> 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
*/
@ -288,43 +338,4 @@ public class MongoExampleMapper { @@ -288,43 +338,4 @@ public class MongoExampleMapper {
return MatchMode.DEFAULT;
}
}
private Document updateTypeRestrictions(Document query, Example example) {
Document result = new Document();
if (isTypeRestricting(example)) {
result.putAll(query);
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
return result;
}
for (Map.Entry<String, Object> entry : query.entrySet()) {
if (!this.converter.getTypeMapper().isTypeKey(entry.getKey())) {
result.put(entry.getKey(), entry.getValue());
}
}
return result;
}
private boolean isTypeRestricting(Example example) {
if (example.getMatcher() instanceof UntypedExampleMatcher) {
return false;
}
if (example.getMatcher().getIgnoredPaths().isEmpty()) {
return true;
}
for (String path : example.getMatcher().getIgnoredPaths()) {
if (this.converter.getTypeMapper().isTypeKey(path)) {
return false;
}
}
return true;
}
}

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/UntypedExampleMatcher.java

@ -15,36 +15,29 @@ @@ -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 { @@ -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 { @@ -175,7 +168,7 @@ public class UntypedExampleMatcher implements ExampleMatcher {
return delegate.getDefaultStringMatcher();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.domain.ExampleMatcher#isIgnoreCaseEnabled()
*/

2
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java

@ -484,7 +484,7 @@ public class MongoExampleMapperUnitTests { @@ -484,7 +484,7 @@ public class MongoExampleMapperUnitTests {
}
@Test // DATAMONGO-1768
public void untypedExampleShouldNotInfereTypeRestriction() {
public void untypedExampleShouldNotInferTypeRestriction() {
WrapperDocument probe = new WrapperDocument();
probe.flatDoc = new FlatDocument();

Loading…
Cancel
Save