diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java
index 0f28588d5..c1c430117 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java
@@ -21,7 +21,7 @@ import java.util.Optional;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
-import org.springframework.data.mongodb.core.validation.ValidatorDefinition;
+import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.util.Optionals;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -43,7 +43,7 @@ public class CollectionOptions {
private @Nullable Long size;
private @Nullable Boolean capped;
private @Nullable Collation collation;
- private Validator validator;
+ private ValidationOptions validationOptions;
/**
* Constructs a new CollectionOptions instance.
@@ -56,17 +56,17 @@ public class CollectionOptions {
*/
@Deprecated
public CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped) {
- this(size, maxDocuments, capped, null, Validator.none());
+ this(size, maxDocuments, capped, null, ValidationOptions.none());
}
private CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped,
- @Nullable Collation collation, Validator validator) {
+ @Nullable Collation collation, ValidationOptions validationOptions) {
this.maxDocuments = maxDocuments;
this.size = size;
this.capped = capped;
this.collation = collation;
- this.validator = validator;
+ this.validationOptions = validationOptions;
}
/**
@@ -80,7 +80,7 @@ public class CollectionOptions {
Assert.notNull(collation, "Collation must not be null!");
- return new CollectionOptions(null, null, null, collation, Validator.none());
+ return new CollectionOptions(null, null, null, collation, ValidationOptions.none());
}
/**
@@ -90,7 +90,7 @@ public class CollectionOptions {
* @since 2.0
*/
public static CollectionOptions empty() {
- return new CollectionOptions(null, null, null, null, Validator.none());
+ return new CollectionOptions(null, null, null, null, ValidationOptions.none());
}
/**
@@ -101,7 +101,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions capped() {
- return new CollectionOptions(size, maxDocuments, true, collation, validator);
+ return new CollectionOptions(size, maxDocuments, true, collation, validationOptions);
}
/**
@@ -112,7 +112,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions maxDocuments(long maxDocuments) {
- return new CollectionOptions(size, maxDocuments, capped, collation, validator);
+ return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
}
/**
@@ -123,7 +123,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions size(long size) {
- return new CollectionOptions(size, maxDocuments, capped, collation, validator);
+ return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
}
/**
@@ -134,11 +134,11 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions collation(@Nullable Collation collation) {
- return new CollectionOptions(size, maxDocuments, capped, collation, validator);
+ return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
}
/**
- * Create new {@link CollectionOptions} with already given settings and {@code validator} set to given
+ * Create new {@link CollectionOptions} with already given settings and {@code validationOptions} set to given
* {@link MongoJsonSchema}.
*
* @param schema can be {@literal null}.
@@ -146,11 +146,19 @@ public class CollectionOptions {
* @since 2.1
*/
public CollectionOptions schema(@Nullable MongoJsonSchema schema) {
- return validation(new Validator(schema, null, validator.validationLevel, validator.validationAction));
+ return validator(Validator.schema(schema));
}
- public CollectionOptions validatorDefinition(@Nullable ValidatorDefinition definition) {
- return validation(new Validator(null, definition, validator.validationLevel, validator.validationAction));
+ /**
+ * /** Create new {@link CollectionOptions} with already given settings and {@code validationOptions} set to given
+ * {@link Validator}.
+ *
+ * @param validator can be {@literal null}.
+ * @return new {@link CollectionOptions}.
+ * @since 2.1
+ */
+ public CollectionOptions validator(@Nullable Validator validator) {
+ return validation(validationOptions.validator(validator));
}
/**
@@ -219,7 +227,7 @@ public class CollectionOptions {
public CollectionOptions schemaValidationLevel(ValidationLevel validationLevel) {
Assert.notNull(validationLevel, "ValidationLevel must not be null!");
- return validation(new Validator(validator.schema, validator.validatorDefinition, validationLevel, validator.validationAction));
+ return validation(validationOptions.validationLevel(validationLevel));
}
/**
@@ -233,20 +241,20 @@ public class CollectionOptions {
public CollectionOptions schemaValidationAction(ValidationAction validationAction) {
Assert.notNull(validationAction, "ValidationAction must not be null!");
- return validation(new Validator(validator.schema, validator.validatorDefinition, validator.validationLevel, validationAction));
+ return validation(validationOptions.validationAction(validationAction));
}
/**
- * Create new {@link CollectionOptions} with the given {@link Validator}.
+ * Create new {@link CollectionOptions} with the given {@link ValidationOptions}.
*
- * @param validator must not be {@literal null}. Use {@link Validator#none()} to remove validation.
+ * @param validationOptions must not be {@literal null}. Use {@link ValidationOptions#none()} to remove validation.
* @return new {@link CollectionOptions}.
* @since 2.1
*/
- public CollectionOptions validation(Validator validator) {
+ public CollectionOptions validation(ValidationOptions validationOptions) {
- Assert.notNull(validator, "Validator must not be null!");
- return new CollectionOptions(size, maxDocuments, capped, collation, validator);
+ Assert.notNull(validationOptions, "ValidationOptions must not be null!");
+ return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
}
/**
@@ -293,47 +301,72 @@ public class CollectionOptions {
* @return {@link Optional#empty()} if not set.
* @since 2.1
*/
- public Optional getValidator() {
- return validator.isEmpty() ? Optional.empty() : Optional.of(validator);
+ public Optional getValidationOptions() {
+ return validationOptions.isEmpty() ? Optional.empty() : Optional.of(validationOptions);
}
/**
- * Encapsulation of Validator options.
+ * Encapsulation of ValidationOptions options.
*
* @author Christoph Strobl
* @author Andreas Zink
* @since 2.1
*/
@RequiredArgsConstructor
- public static class Validator {
+ public static class ValidationOptions {
- private static final Validator NONE = new Validator(null, null, null, null);
+ private static final ValidationOptions NONE = new ValidationOptions(null, null, null);
- private final @Nullable MongoJsonSchema schema;
- private final @Nullable ValidatorDefinition validatorDefinition;
+ private final @Nullable Validator validator;
private final @Nullable ValidationLevel validationLevel;
private final @Nullable ValidationAction validationAction;
/**
- * Create an empty {@link Validator}.
+ * Create an empty {@link ValidationOptions}.
*
* @return never {@literal null}.
*/
- public static Validator none() {
+ public static ValidationOptions none() {
return NONE;
}
/**
- * Get the {@code $jsonSchema} used for validation.
+ * Define the {@link Validator} to be used for document validation.
*
- * @return {@link Optional#empty()} if not set.
+ * @param validator can be {@literal null}.
+ * @return new instance of {@link ValidationOptions}.
*/
- public Optional getSchema() {
- return Optional.ofNullable(schema);
+ public ValidationOptions validator(@Nullable Validator validator) {
+ return new ValidationOptions(validator, validationLevel, validationAction);
}
- public Optional getValidatorDefinition() {
- return Optional.ofNullable(validatorDefinition);
+ /**
+ * Define the validation level to apply.
+ *
+ * @param validationLevel can be {@literal null}.
+ * @return new instance of {@link ValidationOptions}.
+ */
+ public ValidationOptions validationLevel(ValidationLevel validationLevel) {
+ return new ValidationOptions(validator, validationLevel, validationAction);
+ }
+
+ /**
+ * Define the validation action to take.
+ *
+ * @param validationAction can be {@literal null}.
+ * @return new instance of {@link ValidationOptions}.
+ */
+ public ValidationOptions validationAction(ValidationAction validationAction) {
+ return new ValidationOptions(validator, validationLevel, validationAction);
+ }
+
+ /**
+ * Get the {@link Validator} to use.
+ *
+ * @return never {@literal null}.
+ */
+ public Optional getValidator() {
+ return Optional.ofNullable(validator);
}
/**
@@ -358,7 +391,7 @@ public class CollectionOptions {
* @return {@literal true} if no arguments set.
*/
boolean isEmpty() {
- return !Optionals.isAnyPresent(getSchema(), getValidatorDefinition(), getValidationAction(), getValidationLevel());
+ return !Optionals.isAnyPresent(getValidator(), getValidationAction(), getValidationLevel());
}
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index 2d2f7d5a2..b83a66878 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -63,7 +63,7 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
-import org.springframework.data.mongodb.core.CollectionOptions.Validator;
+import org.springframework.data.mongodb.core.CollectionOptions.ValidationOptions;
import org.springframework.data.mongodb.core.DefaultBulkOperations.BulkOperationContext;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
@@ -108,6 +108,8 @@ import org.springframework.data.mongodb.core.query.Meta;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.mongodb.core.validation.JsonSchemaValidator;
+import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.mongodb.util.MongoClientVersion;
import org.springframework.data.projection.ProjectionInformation;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
@@ -139,10 +141,16 @@ import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
-import com.mongodb.client.model.*;
+import com.mongodb.client.model.CountOptions;
+import com.mongodb.client.model.CreateCollectionOptions;
+import com.mongodb.client.model.DeleteOptions;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.model.FindOneAndDeleteOptions;
+import com.mongodb.client.model.FindOneAndUpdateOptions;
+import com.mongodb.client.model.ReturnDocument;
+import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.ValidationAction;
import com.mongodb.client.model.ValidationLevel;
-import com.mongodb.client.model.ValidationOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.util.JSONParseException;
@@ -2236,7 +2244,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
if (collectionOptions.containsKey("validator")) {
- ValidationOptions options = new ValidationOptions();
+ com.mongodb.client.model.ValidationOptions options = new com.mongodb.client.model.ValidationOptions();
if (collectionOptions.containsKey("validationLevel")) {
options.validationLevel(ValidationLevel.fromString(collectionOptions.getString("validationLevel")));
@@ -2377,10 +2385,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Document doc = convertToDocument(collectionOptions);
- if (collectionOptions != null && collectionOptions.getValidator().isPresent()) {
+ if (collectionOptions != null && collectionOptions.getValidationOptions().isPresent()) {
- Validator v = collectionOptions.getValidator().get();
- v.getSchema().ifPresent(val -> doc.put("validator", schemaMapper.mapSchema(val.toDocument(), targetType)));
+ ValidationOptions v = collectionOptions.getValidationOptions().get();
+ v.getValidator().ifPresent(val -> doc.put("validator", getMappedValidator(val, targetType)));
}
return doc;
}
@@ -2401,18 +2409,28 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
collectionOptions.getMaxDocuments().ifPresent(val -> document.put("max", val));
collectionOptions.getCollation().ifPresent(val -> document.append("collation", val.toDocument()));
- if (collectionOptions.getValidator().isPresent()) {
- Validator v = collectionOptions.getValidator().get();
+ if (collectionOptions.getValidationOptions().isPresent()) {
+
+ CollectionOptions.ValidationOptions v = collectionOptions.getValidationOptions().get();
v.getValidationLevel().ifPresent(val -> document.append("validationLevel", val.getValue()));
v.getValidationAction().ifPresent(val -> document.append("validationAction", val.getValue()));
- v.getSchema().ifPresent(val -> document.append("validator",
- new MongoJsonSchemaMapper(getConverter()).mapSchema(val.toDocument(), Object.class)));
- v.getValidatorDefinition().ifPresent(val -> document.put("validator", val.toDocument()));
+ v.getValidator().ifPresent(val -> document.append("validator", getMappedValidator(val, Object.class)));
}
}
return document;
}
+ Document getMappedValidator(Validator validator, Class> domainType) {
+
+ Document validationRules = validator.toDocument();
+
+ if (validator instanceof JsonSchemaValidator || validationRules.containsKey("$jsonSchema")) {
+ return schemaMapper.mapSchema(validationRules, domainType);
+ }
+
+ return queryMapper.getMappedObject(validationRules, mappingContext.getPersistentEntity(domainType));
+ }
+
/**
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter.
* The first document that matches the query is returned and also removed from the collection in the database.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
index 71fffaa92..3a70e89c0 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
@@ -24,8 +24,17 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -91,6 +100,8 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.mongodb.core.validation.JsonSchemaValidator;
+import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.mongodb.util.MongoClientVersion;
import org.springframework.data.projection.ProjectionInformation;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
@@ -2007,15 +2018,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
collectionOptions.getMaxDocuments().ifPresent(result::maxDocuments);
collectionOptions.getCollation().map(Collation::toMongoCollation).ifPresent(result::collation);
- collectionOptions.getValidator().ifPresent(it -> {
+ collectionOptions.getValidationOptions().ifPresent(it -> {
ValidationOptions validationOptions = new ValidationOptions();
it.getValidationAction().ifPresent(validationOptions::validationAction);
it.getValidationLevel().ifPresent(validationOptions::validationLevel);
- it.getSchema()
- .ifPresent(val -> validationOptions.validator(schemaMapper.mapSchema(val.toDocument(), entityType)));
+ it.getValidator().ifPresent(val -> validationOptions.validator(getMappedValidator(val, entityType)));
result.validationOptions(validationOptions);
});
@@ -2023,6 +2033,17 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return result;
}
+ Document getMappedValidator(Validator validator, Class> domainType) {
+
+ Document validationRules = validator.toDocument();
+
+ if (validator instanceof JsonSchemaValidator || validationRules.containsKey("$jsonSchema")) {
+ return schemaMapper.mapSchema(validationRules, domainType);
+ }
+
+ return queryMapper.getMappedObject(validationRules, mappingContext.getPersistentEntity(domainType));
+ }
+
/**
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter.
* The first document that matches the query is returned and also removed from the collection in the database.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/CriteriaValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/CriteriaValidator.java
index c6cc30385..c6d150a2b 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/CriteriaValidator.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/CriteriaValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 the original author or authors.
+ * Copyright 2018 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.
@@ -15,51 +15,61 @@
*/
package org.springframework.data.mongodb.core.validation;
+import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
import org.bson.Document;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
-import org.springframework.lang.NonNull;
+import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.util.Assert;
/**
- * Utility to build a MongoDB {@code validator} based on a {@link CriteriaDefinition}.
- *
+ * {@link Validator} implementation based on {@link CriteriaDefinition query expressions}.
+ *
* @author Andreas Zink
+ * @author Christoph Strobl
* @since 2.1
* @see Criteria
+ * @see Schema Validation
*/
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode
-public class CriteriaValidator implements ValidatorDefinition {
+public class CriteriaValidator implements Validator {
- private final Document document;
-
- private CriteriaValidator(Document document) {
- Assert.notNull(document, "Document must not be null!");
- this.document = document;
- }
+ private final CriteriaDefinition criteria;
/**
- * Builds a {@code validator} object, which is basically setup of query operators, based on a
+ * Creates a new {@link Validator} object, which is basically setup of query operators, based on a
* {@link CriteriaDefinition} instance.
- *
- * @param criteria the criteria to build the {@code validator} from
- * @return
+ *
+ * @param criteria the criteria to build the {@code validator} from. Must not be {@literal null}.
+ * @return new instance of {@link CriteriaValidator}.
+ * @throws IllegalArgumentException when criteria is {@literal null}.
*/
- public static CriteriaValidator fromCriteria(@NonNull CriteriaDefinition criteria) {
+ public static CriteriaValidator of(CriteriaDefinition criteria) {
+
Assert.notNull(criteria, "Criteria must not be null!");
- return new CriteriaValidator(criteria.getCriteriaObject());
+ return new CriteriaValidator(criteria);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.validation.Validator#toDocument()
+ */
@Override
public Document toDocument() {
- return this.document;
+ return criteria.getCriteriaObject();
}
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
@Override
public String toString() {
- return document.toString();
+ return SerializationUtils.serializeToJsonSafely(toDocument());
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/DocumentValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/DocumentValidator.java
new file mode 100644
index 000000000..870973c0f
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/DocumentValidator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018 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.mongodb.core.validation;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+import org.bson.Document;
+import org.springframework.data.mongodb.core.query.SerializationUtils;
+import org.springframework.util.Assert;
+
+/**
+ * Most trivial {@link Validator} implementation using plain {@link Document} to describe the desired document structure
+ * which can be either a {@code $jsonSchema} or query expression.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ * @see Schema Validation
+ */
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class DocumentValidator implements Validator {
+
+ private final Document validatorObject;
+
+ /**
+ * Create new {@link org.springframework.data.mongodb.core.validation.DocumentValidator} defining validation rules via
+ * a plain {@link Document}.
+ *
+ * @param validatorObject must not be {@literal null}.
+ * @throws IllegalArgumentException if validatorObject is {@literal null}.
+ */
+ public static DocumentValidator of(Document validatorObject) {
+
+ Assert.notNull(validatorObject, "ValidatorObject must not be null!");
+ return new DocumentValidator(new Document(validatorObject));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.validation.Validator#toDocument()
+ */
+ @Override
+ public Document toDocument() {
+ return new Document(validatorObject);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return SerializationUtils.serializeToJsonSafely(validatorObject);
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/JsonSchemaValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/JsonSchemaValidator.java
new file mode 100644
index 000000000..3c1fbbf9c
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/JsonSchemaValidator.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 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.mongodb.core.validation;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+import org.bson.Document;
+import org.springframework.data.mongodb.core.query.SerializationUtils;
+import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+import org.springframework.util.Assert;
+
+/**
+ * {@link Validator} implementation based on {@link MongoJsonSchema JSON Schema}.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ * @see Schema Validation
+ */
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class JsonSchemaValidator implements Validator {
+
+ private final MongoJsonSchema schema;
+
+ public static JsonSchemaValidator of(MongoJsonSchema schema) {
+
+ Assert.notNull(schema, "Schema must not be null!");
+ return new JsonSchemaValidator(schema);
+ }
+
+ public MongoJsonSchema getSchema() {
+ return schema;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.validation.Validator#toDocument()
+ */
+ @Override
+ public Document toDocument() {
+ return schema.toDocument();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return SerializationUtils.serializeToJsonSafely(toDocument());
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationAction.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationAction.java
deleted file mode 100644
index 199e00a7d..000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationAction.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2017 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.mongodb.core.validation;
-
-import lombok.Getter;
-
-/**
- * Determines whether to error on invalid documents or just warn about the violations but allow invalid documents to be
- * inserted.
- *
- * @author Andreas Zink
- * @since 2.1
- * @see MongoDB Collection Options
- */
-public enum ValidationAction {
-
- /**
- * Documents must pass validation before the write occurs. Otherwise, the write operation fails. (MongoDB default)
- */
- ERROR("error"),
-
- /**
- * Documents do not have to pass validation. If the document fails validation, the write operation logs the validation
- * failure.
- */
- WARN("warn");
-
- @Getter private String value;
-
- private ValidationAction(String value) {
- this.value = value;
- }
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationLevel.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationLevel.java
deleted file mode 100644
index 187c63ca1..000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationLevel.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2017 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.mongodb.core.validation;
-
-import lombok.Getter;
-
-/**
- * Determines how strictly MongoDB applies the validation rules to existing documents during an update.
- *
- * @author Andreas Zink
- * @since 2.1
- * @see MongoDB Collection Options
- */
-public enum ValidationLevel {
-
- /**
- * No validation for inserts or updates.
- */
- OFF("off"),
-
- /**
- * Apply validation rules to all inserts and all updates. (MongoDB default)
- */
- STRICT("strict"),
-
- /**
- * Apply validation rules to inserts and to updates on existing valid documents. Do not apply rules to updates on
- * existing invalid documents.
- */
- MODERATE("moderate");
-
- @Getter private String value;
-
- private ValidationLevel(String value) {
- this.value = value;
- }
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationOptions.java
deleted file mode 100644
index ebb9c0baa..000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidationOptions.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2017 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.mongodb.core.validation;
-
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.util.Optional;
-
-import org.springframework.data.mongodb.core.CollectionOptions;
-import org.springframework.lang.NonNull;
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
-
-/**
- * Wraps the collection validation options.
- *
- * @author Andreas Zink
- * @since 2.1
- * @see {@link CollectionOptions}
- * @see MongoDB Document Validation
- * @see MongoDB Collection Options
- */
-@EqualsAndHashCode
-@ToString
-public class ValidationOptions {
- private ValidatorDefinition validator;
- private ValidationLevel validationLevel;
- private ValidationAction validationAction;
-
- private ValidationOptions(ValidatorDefinition validator) {
- Assert.notNull(validator, "ValidatorDefinition must not be null!");
- this.validator = validator;
- }
-
- public static ValidationOptions validator(@NonNull ValidatorDefinition validator) {
- return new ValidationOptions(validator);
- }
-
- public ValidationOptions validationLevel(@Nullable ValidationLevel validationLevel) {
- this.validationLevel = validationLevel;
- return this;
- }
-
- public ValidationOptions validationAction(@Nullable ValidationAction validationAction) {
- this.validationAction = validationAction;
- return this;
- }
-
- public ValidatorDefinition getValidator() {
- return validator;
- }
-
- public Optional getValidationLevel() {
- return Optional.ofNullable(validationLevel);
- }
-
- public Optional getValidationAction() {
- return Optional.ofNullable(validationAction);
- }
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/Validator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/Validator.java
new file mode 100644
index 000000000..40dfd2994
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/Validator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 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.mongodb.core.validation;
+
+import org.bson.Document;
+import org.springframework.data.mongodb.core.query.CriteriaDefinition;
+import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+import org.springframework.util.Assert;
+
+/**
+ * Provides a {@code validator} object to be used for collection validation via
+ * {@link org.springframework.data.mongodb.core.CollectionOptions.ValidationOptions}.
+ *
+ * @author Andreas Zink
+ * @author Christoph Strobl
+ * @since 2.1
+ * @see MongoDB Collection Options
+ */
+public interface Validator {
+
+ /**
+ * Get the {@link Document} containing the validation specific rules. The document may contain fields that may require
+ * type and/or field name mapping.
+ *
+ * @return a MongoDB {@code validator} {@link Document}. Never {@literal null}.
+ */
+ Document toDocument();
+
+ /**
+ * Creates a basic {@link Validator} checking documents against a given set of rules.
+ *
+ * @param validationRules must not be {@literal null}.
+ * @return new instance of {@link Validator}.
+ * @throws IllegalArgumentException if validationRules is {@literal null}.
+ */
+ static Validator document(Document validationRules) {
+
+ Assert.notNull(validationRules, "ValidationRules must not be null!");
+ return DocumentValidator.of(validationRules);
+ }
+
+ /**
+ * Creates a new {@link Validator} checking documents against the structure defined in {@link MongoJsonSchema}.
+ *
+ * @param schema must not be {@literal null}.
+ * @return new instance of {@link Validator}.
+ * @throws IllegalArgumentException if schema is {@literal null}.
+ */
+ static Validator schema(MongoJsonSchema schema) {
+
+ Assert.notNull(schema, "Schema must not be null!");
+ return JsonSchemaValidator.of(schema);
+ }
+
+ /**
+ * Creates a new {@link Validator} checking documents against a given query structure expressed by
+ * {@link CriteriaDefinition}.
+ *
+ * @param criteria must not be {@literal null}.
+ * @return new instance of {@link Validator}.
+ * @throws IllegalArgumentException if criteria is {@literal null}.
+ */
+ static Validator criteria(CriteriaDefinition criteria) {
+
+ Assert.notNull(criteria, "Criteria must not be null!");
+ return CriteriaValidator.of(criteria);
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidatorDefinition.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidatorDefinition.java
deleted file mode 100644
index 50bcbb579..000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/ValidatorDefinition.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2017 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.mongodb.core.validation;
-
-import org.bson.Document;
-import org.springframework.lang.NonNull;
-
-/**
- * Provides a {@code validator} object to be used for collection validation.
- *
- * @author Andreas Zink
- * @since 2.1
- * @see MongoDB Collection Options
- */
-public interface ValidatorDefinition {
-
- /**
- * @return a MongoDB {@code validator} document
- */
- public @NonNull Document toDocument();
-
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/package-info.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/package-info.java
new file mode 100644
index 000000000..002a4ee1f
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/validation/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * MongoDB schema validation specifics.
+ */
+@org.springframework.lang.NonNullApi
+@org.springframework.lang.NonNullFields
+package org.springframework.data.mongodb.core.validation;
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateValidationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateValidationTests.java
index 10db45c82..a2449427b 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateValidationTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateValidationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 the original author or authors.
+ * Copyright 2018 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.
@@ -15,46 +15,50 @@
*/
package org.springframework.data.mongodb.core;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.mongodb.core.query.Criteria.*;
+import static org.springframework.data.mongodb.core.validation.Validator.*;
import lombok.AllArgsConstructor;
import lombok.Data;
-import lombok.NoArgsConstructor;
import java.util.List;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-
import org.bson.Document;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
+import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
+import org.springframework.data.mongodb.core.CollectionOptions.ValidationOptions;
+import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.query.Criteria;
-import org.springframework.data.mongodb.core.validation.CriteriaValidator;
-import org.springframework.data.mongodb.core.validation.ValidationAction;
-import org.springframework.data.mongodb.core.validation.ValidationLevel;
-import org.springframework.data.mongodb.core.validation.ValidationOptions;
+import org.springframework.data.mongodb.core.validation.DocumentValidator;
import org.springframework.data.mongodb.test.util.MongoVersionRule;
import org.springframework.data.util.Version;
+import org.springframework.lang.Nullable;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mongodb.MongoClient;
+import com.mongodb.client.model.ValidationAction;
+import com.mongodb.client.model.ValidationLevel;
/**
+ * Integration tests for {@link CollectionOptions#validation(ValidationOptions)} using
+ * {@link org.springframework.data.mongodb.core.validation.CriteriaValidator} and {@link DocumentValidator}.
+ *
* @author Andreas Zink
+ * @author Christoph Strobl
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class MongoTemplateValidationTests {
public static @ClassRule MongoVersionRule REQUIRES_AT_LEAST_3_2_0 = MongoVersionRule.atLeast(Version.parse("3.2.0"));
- public static final String COLLECTION_NAME = "validation-1";
+
+ static final String COLLECTION_NAME = "validation-1";
@Configuration
static class Config extends AbstractMongoConfiguration {
@@ -79,73 +83,99 @@ public class MongoTemplateValidationTests {
@Test // DATAMONGO-1322
public void testCollectionWithSimpleCriteriaBasedValidation() {
- Criteria criteria = Criteria.where("nonNullString").ne(null).type(2).and("rangedInteger").ne(null).type(16).gte(0)
- .lte(122);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
+
+ Criteria criteria = where("nonNullString").ne(null).type(2).and("rangedInteger").ne(null).type(16).gte(0).lte(122);
+
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().validator(criteria(criteria)));
Document validator = getValidatorInfo(COLLECTION_NAME);
+
assertThat(validator.get("nonNullString")).isEqualTo(new Document("$ne", null).append("$type", 2));
assertThat(validator.get("rangedInteger"))
.isEqualTo(new Document("$ne", null).append("$type", 16).append("$gte", 0).append("$lte", 122));
- template.save(new SimpleBean("hello", 101), COLLECTION_NAME);
- try {
- template.save(new SimpleBean(null, 101), COLLECTION_NAME);
- Assert.fail("The collection validation was setup to check for non-null string");
- } catch (Exception e) {
- // ignore
- }
- try {
- template.save(new SimpleBean("hello", -1), COLLECTION_NAME);
- Assert.fail("The collection validation was setup to check for non-negative int");
- } catch (Exception e) {
- // ignore
- }
+ template.save(new SimpleBean("hello", 101, null), COLLECTION_NAME);
+
+ assertThatExceptionOfType(DataIntegrityViolationException.class)
+ .isThrownBy(() -> template.save(new SimpleBean(null, 101, null), COLLECTION_NAME));
+
+ assertThatExceptionOfType(DataIntegrityViolationException.class)
+ .isThrownBy(() -> template.save(new SimpleBean("hello", -1, null), COLLECTION_NAME));
}
@Test // DATAMONGO-1322
public void testCollectionValidationActionError() {
- Criteria criteria = Criteria.where("name").type(2);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationAction(com.mongodb.client.model.ValidationAction.ERROR).validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
- String validationAction = getValidationActionInfo(COLLECTION_NAME);
- assertThat(ValidationAction.ERROR.getValue()).isEqualTo(validationAction);
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationAction(ValidationAction.ERROR)
+ .validator(criteria(where("name").type(2))));
+
+ assertThat(getValidationActionInfo(COLLECTION_NAME)).isEqualTo(ValidationAction.ERROR.getValue());
}
@Test // DATAMONGO-1322
public void testCollectionValidationActionWarn() {
- Criteria criteria = Criteria.where("name").type(2);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationAction(com.mongodb.client.model.ValidationAction.WARN).validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
- String validationAction = getValidationActionInfo(COLLECTION_NAME);
- assertThat(ValidationAction.WARN.getValue()).isEqualTo(validationAction);
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationAction(ValidationAction.WARN)
+ .validator(criteria(where("name").type(2))));
+
+ assertThat(getValidationActionInfo(COLLECTION_NAME)).isEqualTo(ValidationAction.WARN.getValue());
}
@Test // DATAMONGO-1322
public void testCollectionValidationLevelOff() {
- Criteria criteria = Criteria.where("name").type(2);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(com.mongodb.client.model.ValidationLevel.OFF).validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
- String validationAction = getValidationLevelInfo(COLLECTION_NAME);
- assertThat(ValidationLevel.OFF.getValue()).isEqualTo(validationAction);
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(ValidationLevel.OFF)
+ .validator(criteria(where("name").type(2))));
+
+ assertThat(getValidationLevelInfo(COLLECTION_NAME)).isEqualTo(ValidationLevel.OFF.getValue());
}
@Test // DATAMONGO-1322
public void testCollectionValidationLevelModerate() {
- Criteria criteria = Criteria.where("name").type(2);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(com.mongodb.client.model.ValidationLevel.MODERATE).validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
- String validationAction = getValidationLevelInfo(COLLECTION_NAME);
- assertThat(ValidationLevel.MODERATE.getValue()).isEqualTo(validationAction);
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(ValidationLevel.MODERATE)
+ .validator(criteria(where("name").type(2))));
+
+ assertThat(getValidationLevelInfo(COLLECTION_NAME)).isEqualTo(ValidationLevel.MODERATE.getValue());
}
@Test // DATAMONGO-1322
public void testCollectionValidationLevelStrict() {
- Criteria criteria = Criteria.where("name").type(2);
- template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(com.mongodb.client.model.ValidationLevel.STRICT).validatorDefinition(CriteriaValidator.fromCriteria(criteria)));
- String validationAction = getValidationLevelInfo(COLLECTION_NAME);
- assertThat(ValidationLevel.STRICT.getValue()).isEqualTo(validationAction);
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().schemaValidationLevel(ValidationLevel.STRICT)
+ .validator(criteria(where("name").type(2))));
+
+ assertThat(getValidationLevelInfo(COLLECTION_NAME)).isEqualTo(ValidationLevel.STRICT.getValue());
+ }
+
+ @Test // DATAMONGO-1322
+ public void mapsFieldNameCorrectlyWhenGivenDomainTypeInformation() {
+
+ template.createCollection(SimpleBean.class,
+ CollectionOptions.empty().validator(criteria(where("customFieldName").type(8))));
+
+ assertThat(getValidatorInfo(COLLECTION_NAME)).isEqualTo(new Document("customName", new Document("$type", 8)));
+ }
+
+ @Test // DATAMONGO-1322
+ public void usesDocumentValidatorCorrectly() {
+
+ Document rules = new Document("customFieldName", new Document("$type", "bool"));
+
+ template.createCollection(COLLECTION_NAME, CollectionOptions.empty().validator(document(rules)));
+
+ assertThat(getValidatorInfo(COLLECTION_NAME))
+ .isEqualTo(new Document("customFieldName", new Document("$type", "bool")));
+ }
+
+ @Test // DATAMONGO-1322
+ public void mapsDocumentValidatorFieldsCorrectly() {
+
+ Document rules = new Document("customFieldName", new Document("$type", "bool"));
+
+ template.createCollection(SimpleBean.class, CollectionOptions.empty().validator(document(rules)));
+
+ assertThat(getValidatorInfo(COLLECTION_NAME)).isEqualTo(new Document("customName", new Document("$type", "bool")));
}
private Document getCollectionOptions(String collectionName) {
@@ -165,6 +195,7 @@ public class MongoTemplateValidationTests {
}
private Document getCollectionInfo(String collectionName) {
+
return template.execute(db -> {
Document result = db.runCommand(
new Document().append("listCollections", 1).append("filter", new Document("name", collectionName)));
@@ -174,10 +205,12 @@ public class MongoTemplateValidationTests {
@Data
@AllArgsConstructor
- @NoArgsConstructor
+ @org.springframework.data.mongodb.core.mapping.Document(collection = COLLECTION_NAME)
static class SimpleBean {
- @NotNull private String nonNullString;
- @NotNull @Min(0) @Max(122) private Integer rangedInteger;
+
+ private @Nullable String nonNullString;
+ private @Nullable Integer rangedInteger;
+ private @Field("customName") Object customFieldName;
}
}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaTests.java
index 0ce070ae2..ff8b9ff79 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaTests.java
@@ -19,6 +19,7 @@ import static org.springframework.data.mongodb.test.util.Assertions.*;
import lombok.Data;
+import java.util.Collections;
import java.util.List;
import org.bson.Document;
@@ -33,6 +34,7 @@ import org.springframework.data.mongodb.core.CollectionOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoJsonSchemaMapper;
import org.springframework.data.mongodb.core.mapping.Field;
+import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.mongodb.test.util.MongoVersionRule;
import org.springframework.data.util.Version;
import org.springframework.test.context.ContextConfiguration;
@@ -99,6 +101,20 @@ public class MongoJsonSchemaTests {
assertThat(fromDb).isEqualTo($jsonSchema);
}
+ @Test // DATAMONGO-1835
+ public void writeSchemaInDocumentValidatorCorrectly() {
+
+ Document unmappedSchema = new Document("$jsonSchema",
+ new Document("type", "object").append("required", Collections.singletonList("firstname")));
+
+ Document mappedSchema = new Document("$jsonSchema",
+ new Document("type", "object").append("required", Collections.singletonList("first_name")));
+
+ template.createCollection(Person.class, CollectionOptions.empty().validator(Validator.document(unmappedSchema)));
+
+ assertThat(readSchemaFromDatabase("persons")).isEqualTo(mappedSchema);
+ }
+
@Test // DATAMONGO-1835
public void nonMappedSchema() {
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorUnitTests.java
similarity index 84%
rename from spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorTest.java
rename to spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorUnitTests.java
index 127968043..2a4c8dd11 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorTest.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/validation/CriteriaValidatorUnitTests.java
@@ -22,14 +22,18 @@ import org.junit.Test;
import org.springframework.data.mongodb.core.query.Criteria;
/**
+ * Unit tests for {@link CriteriaValidator}.
+ *
* @author Andreas Zink
+ * @author Christoph Strobl
*/
-public class CriteriaValidatorTest {
+public class CriteriaValidatorUnitTests {
@Test // DATAMONGO-1322
public void testSimpleCriteria() {
+
Criteria criteria = Criteria.where("nonNullString").ne(null).type(2).and("rangedInteger").type(16).gte(0).lte(122);
- Document validator = CriteriaValidator.fromCriteria(criteria).toDocument();
+ Document validator = CriteriaValidator.of(criteria).toDocument();
assertThat(validator.get("nonNullString")).isEqualTo(new Document("$ne", null).append("$type", 2));
assertThat(validator.get("rangedInteger"))
@@ -38,6 +42,6 @@ public class CriteriaValidatorTest {
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1322
public void testFailOnNull() {
- CriteriaValidator.fromCriteria(null);
+ CriteriaValidator.of(null);
}
}
diff --git a/src/main/asciidoc/reference/mongo-3.adoc b/src/main/asciidoc/reference/mongo-3.adoc
index 281a63a60..37ac56a93 100644
--- a/src/main/asciidoc/reference/mongo-3.adoc
+++ b/src/main/asciidoc/reference/mongo-3.adoc
@@ -96,6 +96,23 @@ MongoDB 3.6 allows validation and querying of documents using JSON schema draft
Spring Data MongoDB supports MongoDB's specific JSON schema implementation to define and use schemas. See <> for further details.
+[[mongo.mongo-3.validation.query-expression]]
+==== Query Expression Validation
+
+Next to the <> as of version 3.2 MongoDB supports validating documents against a given query structure. The structure can be built using `Criteria` objects just the same way as they are used for defining queries.
+
+[source,java]
+----
+Criteria queryExpression = Criteria.where("lastname").ne(null).type(2)
+ .and("age").ne(null).type(16).gt(0).lte(150);
+
+Validator validator = Validator.criteria(queryExpression);
+
+template.createCollection(Person.class, CollectionOptions.empty().validator(validator));
+----
+
+NOTE: Field names used within the query expression are mapped to the domain types property names taking potential `@Field` annotations into account.
+
[[mongo.mongo-3.misc]]
=== Other things to be aware of