Skip to content

Commit de22f2d

Browse files
author
Thomas Darimont
committed
DATAMONGO-941 - Add support for Update $min.
Moved construction of validators to KeywordFactory. Reduced nesting in Keyword validation.
1 parent 415e8c2 commit de22f2d

File tree

1 file changed

+93
-82
lines changed
  • spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert

1 file changed

+93
-82
lines changed

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

Lines changed: 93 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public QueryMapper(MongoConverter converter) {
106106
public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
107107

108108
if (isNestedKeyword(query)) {
109-
return getMappedKeyword(keywordFor(query, entity, mappingContext), entity);
109+
return getMappedKeyword(keywordFor(query, entity, null, mappingContext), entity);
110110
}
111111

112112
DBObject result = new BasicDBObject();
@@ -124,8 +124,7 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity)
124124
}
125125

126126
if (isKeyword(key)) {
127-
result.putAll(getMappedKeyword(new Keyword(query, key, new KeywordContext(null, entity, mappingContext)),
128-
entity));
127+
result.putAll(getMappedKeyword(keywordFor(key, query.get(key), entity, null, mappingContext), entity));
129128
continue;
130129
}
131130

@@ -531,41 +530,17 @@ protected boolean isKeyword(String candidate) {
531530
static class Keyword {
532531

533532
private static final String N_OR_PATTERN = "\\$.*or";
534-
private List<Validator> validators;
535533
private final String key;
536534
private final Object value;
537535
private final KeywordContext context;
536+
private final List<Validator> validators;
538537

539-
private static final Validator MIN_OPERATOR_VALIDATOR = KeywordParameterTypeValidator.whitelist(Byte.class,
540-
Short.class, Integer.class, Long.class, Float.class, Double.class, Date.class);
541-
542-
public Keyword(DBObject dbo, KeywordContext context) {
543-
this(dbo, assertAndReturnOnlySingleKey(dbo), context);
544-
}
545-
546-
public Keyword(DBObject dbo, String key, KeywordContext context) {
538+
public Keyword(String key, Object value, KeywordContext context, List<Validator> validators) {
547539

548540
this.key = key;
549-
this.value = dbo.get(key);
541+
this.value = value;
550542
this.context = context;
551-
this.validators = createValidators(key);
552-
}
553-
554-
private List<Validator> createValidators(String key) {
555-
556-
if (key.equalsIgnoreCase("$min")) {
557-
return Arrays.asList(MIN_OPERATOR_VALIDATOR);
558-
}
559-
560-
return Collections.<Validator> emptyList();
561-
}
562-
563-
static String assertAndReturnOnlySingleKey(DBObject dbo) {
564-
565-
Set<String> keys = dbo.keySet();
566-
Assert.isTrue(keys.size() == 1, "Can only use a single value DBObject!");
567-
568-
return keys.iterator().next();
543+
this.validators = validators;
569544
}
570545

571546
/**
@@ -682,24 +657,55 @@ public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentPropert
682657
* @author Christoph Strobl
683658
* @since 1.7
684659
*/
685-
static class KeywordFactory {
660+
static enum KeywordFactory {
661+
662+
INSTANCE;
663+
664+
private static final Validator VALID_MIN_OPERATOR_TYPES_VALIDATOR = KeywordParameterTypeValidator.whitelist(
665+
Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Date.class);
686666

687667
static Keyword keywordFor(DBObject source,
688668
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
689-
return keywordFor(source, (MongoPersistentEntity<?>) null, mappingContext);
669+
return keywordFor(source, (MongoPersistentEntity<?>) null, null, mappingContext);
690670
}
691671

692-
static Keyword keywordFor(DBObject source, MongoPersistentEntity<?> entity,
672+
static Keyword keywordFor(DBObject source, MongoPersistentProperty property,
693673
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
694-
return new Keyword(source, new KeywordContext(null, entity, mappingContext));
674+
return keywordFor(source, null, property, mappingContext);
695675
}
696676

697-
static Keyword keywordFor(DBObject source, MongoPersistentProperty property,
677+
static Keyword keywordFor(DBObject source, MongoPersistentEntity<?> entity, MongoPersistentProperty property,
698678
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
699679

700-
KeywordContext context = new KeywordContext(property, property == null ? null
680+
String key = assertAndReturnOnlySingleKey(source);
681+
return keywordFor(key, source.get(key), entity, property, mappingContext);
682+
}
683+
684+
static Keyword keywordFor(String key, Object value, MongoPersistentEntity<?> entity,
685+
MongoPersistentProperty property,
686+
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
687+
688+
KeywordContext context = new KeywordContext(property, property == null ? entity
701689
: (MongoPersistentEntity<?>) property.getOwner(), mappingContext);
702-
return new Keyword(source, context);
690+
691+
return new Keyword(key, value, context, INSTANCE.getValidatorsFor(key));
692+
}
693+
694+
private List<Validator> getValidatorsFor(String key) {
695+
696+
if (key.equalsIgnoreCase("$min")) {
697+
return Arrays.asList(VALID_MIN_OPERATOR_TYPES_VALIDATOR);
698+
}
699+
700+
return Collections.<Validator> emptyList();
701+
}
702+
703+
static String assertAndReturnOnlySingleKey(DBObject dbo) {
704+
705+
Set<String> keys = dbo.keySet();
706+
Assert.isTrue(keys.size() == 1, "Can only use a single value DBObject!");
707+
708+
return keys.iterator().next();
703709
}
704710
}
705711

@@ -732,21 +738,25 @@ public void validate(Object target, Errors errors) {
732738
*/
733739
static class KeywordParameterTypeValidator extends KeywordValidator {
734740

741+
enum Mode {
742+
WHITE_LIST, BLACK_LIST;
743+
}
744+
735745
private final Set<Class<?>> types;
736-
private final boolean invert;
746+
private final Mode mode;
737747

738-
private KeywordParameterTypeValidator(boolean invert, Class<?>... supportedTypes) {
748+
private KeywordParameterTypeValidator(Mode mode, Class<?>... supportedTypes) {
739749

740-
this.invert = invert;
750+
this.mode = mode;
741751
this.types = new HashSet<Class<?>>(Arrays.asList(supportedTypes));
742752
}
743753

744754
public static KeywordParameterTypeValidator whitelist(Class<?>... supportedTypes) {
745-
return new KeywordParameterTypeValidator(false, supportedTypes);
755+
return new KeywordParameterTypeValidator(Mode.WHITE_LIST, supportedTypes);
746756
}
747757

748758
public static KeywordParameterTypeValidator blacklist(Class<?>... unsupportedTypes) {
749-
return new KeywordParameterTypeValidator(true, unsupportedTypes);
759+
return new KeywordParameterTypeValidator(Mode.BLACK_LIST, unsupportedTypes);
750760
}
751761

752762
private void doValidate(Object candidate, Errors errors) {
@@ -768,15 +778,11 @@ private void doValidate(Object candidate, Errors errors) {
768778

769779
Class<?> typeToValidate = ClassUtils.isAssignable(MongoPersistentProperty.class, candidate.getClass()) ? ((MongoPersistentProperty) candidate)
770780
.getActualType() : candidate.getClass();
781+
boolean givenTypeContainedInTypes = types.contains(ClassUtils.resolvePrimitiveIfNecessary(typeToValidate));
771782

772-
if (types.contains(ClassUtils.resolvePrimitiveIfNecessary(typeToValidate))) {
773-
if (invert) {
774-
errors.reject("", String.format("Using %s is not supported for %s.", typeToValidate, errors.getObjectName()));
775-
}
776-
} else {
777-
if (!invert) {
778-
errors.reject("", String.format("Using %s is not supported for %s.", typeToValidate, errors.getObjectName()));
779-
}
783+
if ((Mode.BLACK_LIST.equals(mode) && givenTypeContainedInTypes)
784+
|| (Mode.WHITE_LIST.equals(mode) && !givenTypeContainedInTypes)) {
785+
errors.reject("", String.format("Using %s is not supported for %s.", typeToValidate, errors.getObjectName()));
780786
}
781787
}
782788

@@ -791,53 +797,58 @@ public void validate(Keyword target, Errors errors) {
791797
return;
792798
}
793799

794-
if (target.isDBObjectValue()) {
800+
if (!target.isDBObjectValue()) {
795801

796-
DBObject dbo = (DBObject) target.getValue();
802+
MongoPersistentProperty propertyToUse = target.getContext().getProperty();
797803

798-
Iterator<?> keysIterator = dbo.toMap().keySet().iterator();
799-
while (keysIterator.hasNext()) {
804+
if (propertyToUse == null && target.getContext().getEntity() != null) {
805+
propertyToUse = target.getContext().getEntity().getPersistentProperty(errors.getObjectName());
806+
}
800807

801-
String propertyName = keysIterator.next().toString();
808+
doValidate(propertyToUse, errors);
809+
return;
810+
}
802811

803-
if (StringUtils.countOccurrencesOf(propertyName, ".") == 0) {
804-
doValidate(target.getContext().getEntity().getPersistentProperty(propertyName), errors);
805-
continue;
806-
}
812+
DBObject dbo = (DBObject) target.getValue();
807813

808-
MongoPersistentEntity<?> propertyScope = target.getContext().getEntity();
814+
Iterator<?> keysIterator = dbo.keySet().iterator();
815+
while (keysIterator.hasNext()) {
816+
validatePropertyPath(keysIterator.next().toString(), target.getContext(), errors);
817+
}
818+
}
809819

810-
Iterator<String> partsIterator = Arrays.asList(propertyName.split("\\.")).iterator();
811-
while (partsIterator.hasNext()) {
820+
private void validatePropertyPath(String propertyPath, KeywordContext context, Errors errors) {
812821

813-
MongoPersistentProperty property = (MongoPersistentProperty) propertyScope
814-
.getPersistentProperty(partsIterator.next());
822+
if (StringUtils.countOccurrencesOf(propertyPath, ".") == 0) {
823+
doValidate(context.getEntity().getPersistentProperty(propertyPath), errors);
824+
return;
825+
}
815826

816-
if (!partsIterator.hasNext()) {
817-
doValidate(property, errors);
818-
continue;
819-
}
827+
MongoPersistentEntity<?> persistentEntity = context.getEntity();
820828

821-
if (property != null && property.isEntity() && partsIterator.hasNext()) {
829+
Iterator<String> partsIterator = Arrays.asList(propertyPath.split("\\.")).iterator();
830+
while (partsIterator.hasNext()) {
822831

823-
propertyScope = target.getContext().getMappingContext().getPersistentEntity(property.getActualType());
832+
MongoPersistentProperty persistentProperty = (MongoPersistentProperty) persistentEntity
833+
.getPersistentProperty(partsIterator.next());
824834

825-
if (propertyScope == null) {
826-
break;
827-
}
828-
}
829-
}
835+
if (persistentProperty == null) {
836+
continue;
837+
}
830838

839+
if (!partsIterator.hasNext()) {
840+
doValidate(persistentProperty, errors);
841+
return;
831842
}
832-
} else {
833843

834-
MongoPersistentProperty propertyToUse = target.getContext().getProperty();
844+
if (persistentProperty.isEntity() && partsIterator.hasNext()) {
835845

836-
if (propertyToUse == null && target.getContext().getEntity() != null) {
837-
propertyToUse = target.getContext().getEntity().getPersistentProperty(errors.getObjectName());
838-
}
846+
persistentEntity = context.getMappingContext().getPersistentEntity(persistentProperty.getActualType());
839847

840-
doValidate(propertyToUse, errors);
848+
if (persistentEntity == null) {
849+
return;
850+
}
851+
}
841852
}
842853
}
843854
}

0 commit comments

Comments
 (0)