diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index 907a68f2..a2daf322 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -29,6 +29,7 @@
security
text-search
transactions
+ schema-validation
util
@@ -59,6 +60,7 @@
de.flapdoodle.embed
de.flapdoodle.embed.mongo
provided
+ 2.1.1
diff --git a/mongodb/schema-validation/README.md b/mongodb/schema-validation/README.md
new file mode 100644
index 00000000..03be93f5
--- /dev/null
+++ b/mongodb/schema-validation/README.md
@@ -0,0 +1,71 @@
+# Spring Data MongoDB 2.1 - Schema & Validation Example
+
+MongoDB (as of version 3.2) supports validating documents against a given structure described by a query.
+
+```json
+{
+ "name" : {
+ "$exists" : true,
+ "$ne" : null,
+ "$type" : 2
+ },
+ "age" : {
+ "$exists" : true,
+ "$ne" : null,
+ "$type" : 16,
+ "$gte" : 0,
+ "$lte" : 125
+ }
+}
+```
+The structure can be built from `Criteria` objects in the same way as they are used for defining queries.
+
+```java
+Validator.criteria(where("name").exists(true).ne(null).type(2)
+ .and("age").exists(true).ne(null).type(16).gte(0).lte(125));
+```
+
+MongoDB 3.6 supports collections that validate documents against a provided [JSON Schema](https://docs.mongodb.com/manual/core/schema-validation/#json-schema) that
+complies to the JSON schema specification (draft 4).
+
+```json
+{
+ "type": "object",
+ "required": [ "name", "age" ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "age": {
+ "type": "int",
+ "minimum" : 0,
+ "exclusiveMinimum" : false,
+ "maximum" : 125,
+ "exclusiveMaximum" : false
+ }
+ }
+}
+```
+The `MongoJsonSchema` and its builder allow fluent schema definition via the Java API.
+
+```java
+MongoJsonSchema schema = MongoJsonSchema.builder() //
+ .required("name", "age") //
+ .properties( //
+ string("name").minLength(1), //
+ int32("age").gte(0).lte(125) //
+ ).build();
+```
+
+The schema can not only be used to set up `Document` validation for a collection
+
+```java
+template.createCollection(Jedi.class, CollectionOptions.empty().validator(Validator.schema(schema)));
+```
+
+but also to query the store for documents matching a given blueprint.
+
+```java
+template.find(query(matchingDocumentStructure(schema)), Jedi.class);
+```
diff --git a/mongodb/schema-validation/pom.xml b/mongodb/schema-validation/pom.xml
new file mode 100644
index 00000000..6dacaddd
--- /dev/null
+++ b/mongodb/schema-validation/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+
+ spring-data-mongodb-schema-validation
+
+ Spring Data MongoDB 2.1 - Schema & Validation Example
+
+
+ org.springframework.data.examples
+ spring-data-mongodb-examples
+ 2.0.0.BUILD-SNAPSHOT
+
+
+
+ 3.8.0
+ 1.9.0
+ Lovelace-RC2
+
+
+
+
+
+
+
+ spring-data-next
+
+ Lovelace-RC2
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Application.java b/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Application.java
new file mode 100644
index 00000000..9f257760
--- /dev/null
+++ b/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Application.java
@@ -0,0 +1,21 @@
+/*
+ * 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 example.springdata.mongodb.schema;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {}
diff --git a/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Jedi.java b/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Jedi.java
new file mode 100644
index 00000000..dffcfb95
--- /dev/null
+++ b/mongodb/schema-validation/src/main/java/example/springdata/mongodb/schema/Jedi.java
@@ -0,0 +1,39 @@
+/*
+ * 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 example.springdata.mongodb.schema;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.lang.Nullable;
+
+/**
+ * @author Christoph Strobl
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Document("star-wars")
+class Jedi {
+
+ @Id String id;
+ @Nullable String name;
+ @Nullable String lastname;
+ @Nullable Integer age;
+}
diff --git a/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/DocumentValidation.java b/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/DocumentValidation.java
new file mode 100644
index 00000000..3882aa46
--- /dev/null
+++ b/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/DocumentValidation.java
@@ -0,0 +1,132 @@
+/*
+ * 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 example.springdata.mongodb.schema;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.mongodb.core.query.Criteria.*;
+import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.data.mongodb.core.CollectionOptions;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+import org.springframework.data.mongodb.core.validation.Validator;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Christoph Strobl
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class DocumentValidation {
+
+ static final String COLLECTION = "star-wars";
+
+ @Autowired MongoOperations mongoOps;
+
+ @Before
+ public void setUp() {
+ mongoOps.dropCollection(COLLECTION);
+ }
+
+ /**
+ * MongoDB (as of version 3.2) supports validating documents against a given structure described by a query. The
+ * structure can be built from {@link org.springframework.data.mongodb.core.query.Criteria} objects in the same way as
+ * they are used for defining queries.
+ *
+ *
+ *
+ * {
+ * name : {
+ * $exists : true,
+ * $ne : null,
+ * $type : 2
+ * },
+ * age : {
+ * $exists : true,
+ * $ne : null,
+ * $type : 16,
+ * $gte : 0,
+ * $lte : 125
+ * }
+ * }
+ *
+ *
+ */
+ @Test
+ public void criteriaValidator() {
+
+ Validator validator = Validator.criteria( //
+ where("name").exists(true).ne(null).type(2) // non null String
+ .and("age").exists(true).ne(null).type(16).gte(0).lte(125)) // non null int between 0 and 125
+ ;
+
+ mongoOps.createCollection(Jedi.class, CollectionOptions.empty().validator(validator));
+
+ assertThat(mongoOps.save(new Jedi("luke", "luke", "skywalker", 25))).isNotNull();
+
+ assertThatExceptionOfType(DataIntegrityViolationException.class)
+ .isThrownBy(() -> mongoOps.save(new Jedi("yoda", "yoda", null, 900)));
+ }
+
+ /**
+ * As of version 3.6, MongoDB supports collections that validate documents against a provided JSON Schema that
+ * complies to the JSON schema specification (draft 4).
+ *
+ *
+ *
+ * {
+ * "type": "object",
+ * "required": [ "name", "age" ],
+ * "properties": {
+ * "name": {
+ * "type": "string",
+ * "minLength": 1
+ * },
+ * "age": {
+ * "type": "int",
+ * "minimum" : 0,
+ * "exclusiveMinimum" : false,
+ * "maximum" : 125,
+ * "exclusiveMaximum" : false
+ * }
+ * }
+ * }
+ *
+ *
+ */
+ @Test
+ public void schemaValidator() {
+
+ Validator validator = Validator.schema(MongoJsonSchema.builder() //
+ .required("name", "age") //
+ .properties( //
+ string("name").minLength(1), //
+ int32("age").gte(0).lte(125) //
+ ).build());
+ mongoOps.createCollection(Jedi.class, CollectionOptions.empty().validator(validator));
+
+ assertThat(mongoOps.save(new Jedi("luke", "luke", "skywalker", 25))).isNotNull();
+
+ assertThatExceptionOfType(DataIntegrityViolationException.class)
+ .isThrownBy(() -> mongoOps.save(new Jedi("yoda", "yoda", null, 900)));
+ }
+}
diff --git a/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/SchemaQuery.java b/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/SchemaQuery.java
new file mode 100644
index 00000000..d155c0f3
--- /dev/null
+++ b/mongodb/schema-validation/src/test/java/example/springdata/mongodb/schema/SchemaQuery.java
@@ -0,0 +1,93 @@
+/*
+ * 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 example.springdata.mongodb.schema;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.mongodb.core.query.Criteria.*;
+import static org.springframework.data.mongodb.core.query.Query.*;
+import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Christoph Strobl
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class SchemaQuery {
+
+ static final String COLLECTION = "star-wars";
+
+ @Autowired MongoOperations mongoOps;
+
+ @Before
+ public void setUp() {
+
+ mongoOps.dropCollection(COLLECTION);
+ }
+
+ /**
+ * As of version 3.6, MongoDB supports querying documents against a provided JSON Schema that complies to the JSON
+ * schema specification (draft 4).
+ *
+ *
+ *
+ * {
+ * "type": "object",
+ * "required": [ "name", "age" ],
+ * "properties": {
+ * "name": {
+ * "type": "string",
+ * "minLength": 1
+ * },
+ * "age": {
+ * "type": "int",
+ * "minimum" : 0,
+ * "exclusiveMinimum" : false,
+ * "maximum" : 125,
+ * "exclusiveMaximum" : false
+ * }
+ * }
+ * }
+ *
+ *
+ */
+ @Test
+ public void criteriaValidator() {
+
+ Jedi luke = new Jedi("luke", "luke", "skywalker", 25);
+ Jedi yoda = new Jedi("yoda", "yoda", null, 900);
+
+ mongoOps.save(luke);
+ mongoOps.save(yoda);
+
+ MongoJsonSchema schema = MongoJsonSchema.builder() //
+ .required("name", "age") //
+ .properties( //
+ string("name").minLength(1), //
+ int32("age").gte(0).lte(125) //
+ ).build();
+
+ assertThat(mongoOps.find(query(matchingDocumentStructure(schema)), Jedi.class)).containsExactly(luke);
+ }
+}
diff --git a/mongodb/schema-validation/src/test/resources/application.properties b/mongodb/schema-validation/src/test/resources/application.properties
new file mode 100644
index 00000000..8ddb707b
--- /dev/null
+++ b/mongodb/schema-validation/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+spring.mongodb.embedded.features=ONLY_64BIT,NO_HTTP_INTERFACE_ARG,NO_CHUNKSIZE_ARG,SYNC_DELAY,ONLY_WITH_SSL
+spring.mongodb.embedded.version=4.0.1
\ No newline at end of file