Skip to content

Commit 9520ac6

Browse files
christophstroblmp911de
authored andcommitted
#405 - Add Example for MongoDB Schema & Validation.
1 parent 04be1b9 commit 9520ac6

File tree

8 files changed

+394
-0
lines changed

8 files changed

+394
-0
lines changed

mongodb/pom.xml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<module>security</module>
3030
<module>text-search</module>
3131
<module>transactions</module>
32+
<module>schema-validation</module>
3233
<module>util</module>
3334
</modules>
3435

@@ -59,6 +60,7 @@
5960
<groupId>de.flapdoodle.embed</groupId>
6061
<artifactId>de.flapdoodle.embed.mongo</artifactId>
6162
<scope>provided</scope>
63+
<version>2.1.1</version>
6264
</dependency>
6365

6466
</dependencies>

mongodb/schema-validation/README.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Spring Data MongoDB 2.1 - Schema & Validation Example
2+
3+
MongoDB (as of version 3.2) supports validating documents against a given structure described by a query.
4+
5+
```json
6+
{
7+
"name" : {
8+
"$exists" : true,
9+
"$ne" : null,
10+
"$type" : 2
11+
},
12+
"age" : {
13+
"$exists" : true,
14+
"$ne" : null,
15+
"$type" : 16,
16+
"$gte" : 0,
17+
"$lte" : 125
18+
}
19+
}
20+
```
21+
The structure can be built from `Criteria` objects in the same way as they are used for defining queries.
22+
23+
```java
24+
Validator.criteria(where("name").exists(true).ne(null).type(2)
25+
.and("age").exists(true).ne(null).type(16).gte(0).lte(125));
26+
```
27+
28+
MongoDB 3.6 supports collections that validate documents against a provided [JSON Schema](https://docs.mongodb.com/manual/core/schema-validation/#json-schema) that
29+
complies to the JSON schema specification (draft 4).
30+
31+
```json
32+
{
33+
"type": "object",
34+
"required": [ "name", "age" ],
35+
"properties": {
36+
"name": {
37+
"type": "string",
38+
"minLength": 1
39+
},
40+
"age": {
41+
"type": "int",
42+
"minimum" : 0,
43+
"exclusiveMinimum" : false,
44+
"maximum" : 125,
45+
"exclusiveMaximum" : false
46+
}
47+
}
48+
}
49+
```
50+
The `MongoJsonSchema` and its builder allow fluent schema definition via the Java API.
51+
52+
```java
53+
MongoJsonSchema schema = MongoJsonSchema.builder() //
54+
.required("name", "age") //
55+
.properties( //
56+
string("name").minLength(1), //
57+
int32("age").gte(0).lte(125) //
58+
).build();
59+
```
60+
61+
The schema can not only be used to set up `Document` validation for a collection
62+
63+
```java
64+
template.createCollection(Jedi.class, CollectionOptions.empty().validator(Validator.schema(schema)));
65+
```
66+
67+
but also to query the store for documents matching a given blueprint.
68+
69+
```java
70+
template.find(query(matchingDocumentStructure(schema)), Jedi.class);
71+
```

mongodb/schema-validation/pom.xml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<artifactId>spring-data-mongodb-schema-validation</artifactId>
6+
7+
<name>Spring Data MongoDB 2.1 - Schema &amp; Validation Example</name>
8+
9+
<parent>
10+
<groupId>org.springframework.data.examples</groupId>
11+
<artifactId>spring-data-mongodb-examples</artifactId>
12+
<version>2.0.0.BUILD-SNAPSHOT</version>
13+
</parent>
14+
15+
<properties>
16+
<mongodb.version>3.8.0</mongodb.version>
17+
<mongo-driver-reactivestreams.version>1.9.0</mongo-driver-reactivestreams.version>
18+
<spring-data-releasetrain.version>Lovelace-RC2</spring-data-releasetrain.version>
19+
</properties>
20+
21+
<profiles>
22+
23+
<!-- Override property as the module always needs Lovelace -->
24+
25+
<profile>
26+
<id>spring-data-next</id>
27+
<properties>
28+
<spring-data-releasetrain.version>Lovelace-RC2</spring-data-releasetrain.version>
29+
</properties>
30+
</profile>
31+
32+
</profiles>
33+
34+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.mongodb.schema;
17+
18+
import org.springframework.boot.autoconfigure.SpringBootApplication;
19+
20+
@SpringBootApplication
21+
public class Application {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.mongodb.schema;
17+
18+
import lombok.AllArgsConstructor;
19+
import lombok.Data;
20+
import lombok.NoArgsConstructor;
21+
22+
import org.springframework.data.annotation.Id;
23+
import org.springframework.data.mongodb.core.mapping.Document;
24+
import org.springframework.lang.Nullable;
25+
26+
/**
27+
* @author Christoph Strobl
28+
*/
29+
@Data
30+
@AllArgsConstructor
31+
@NoArgsConstructor
32+
@Document("star-wars")
33+
class Jedi {
34+
35+
@Id String id;
36+
@Nullable String name;
37+
@Nullable String lastname;
38+
@Nullable Integer age;
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.mongodb.schema;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.springframework.data.mongodb.core.query.Criteria.*;
20+
import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.*;
21+
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.dao.DataIntegrityViolationException;
28+
import org.springframework.data.mongodb.core.CollectionOptions;
29+
import org.springframework.data.mongodb.core.MongoOperations;
30+
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
31+
import org.springframework.data.mongodb.core.validation.Validator;
32+
import org.springframework.test.context.junit4.SpringRunner;
33+
34+
/**
35+
* @author Christoph Strobl
36+
*/
37+
@RunWith(SpringRunner.class)
38+
@SpringBootTest
39+
public class DocumentValidation {
40+
41+
static final String COLLECTION = "star-wars";
42+
43+
@Autowired MongoOperations mongoOps;
44+
45+
@Before
46+
public void setUp() {
47+
mongoOps.dropCollection(COLLECTION);
48+
}
49+
50+
/**
51+
* MongoDB (as of version 3.2) supports validating documents against a given structure described by a query. The
52+
* structure can be built from {@link org.springframework.data.mongodb.core.query.Criteria} objects in the same way as
53+
* they are used for defining queries.
54+
*
55+
* <pre>
56+
* <code>
57+
* {
58+
* name : {
59+
* $exists : true,
60+
* $ne : null,
61+
* $type : 2
62+
* },
63+
* age : {
64+
* $exists : true,
65+
* $ne : null,
66+
* $type : 16,
67+
* $gte : 0,
68+
* $lte : 125
69+
* }
70+
* }
71+
* </code>
72+
* </pre>
73+
*/
74+
@Test
75+
public void criteriaValidator() {
76+
77+
Validator validator = Validator.criteria( //
78+
where("name").exists(true).ne(null).type(2) // non null String
79+
.and("age").exists(true).ne(null).type(16).gte(0).lte(125)) // non null int between 0 and 125
80+
;
81+
82+
mongoOps.createCollection(Jedi.class, CollectionOptions.empty().validator(validator));
83+
84+
assertThat(mongoOps.save(new Jedi("luke", "luke", "skywalker", 25))).isNotNull();
85+
86+
assertThatExceptionOfType(DataIntegrityViolationException.class)
87+
.isThrownBy(() -> mongoOps.save(new Jedi("yoda", "yoda", null, 900)));
88+
}
89+
90+
/**
91+
* As of version 3.6, MongoDB supports collections that validate documents against a provided JSON Schema that
92+
* complies to the JSON schema specification (draft 4).
93+
*
94+
* <pre>
95+
* <code>
96+
* {
97+
* "type": "object",
98+
* "required": [ "name", "age" ],
99+
* "properties": {
100+
* "name": {
101+
* "type": "string",
102+
* "minLength": 1
103+
* },
104+
* "age": {
105+
* "type": "int",
106+
* "minimum" : 0,
107+
* "exclusiveMinimum" : false,
108+
* "maximum" : 125,
109+
* "exclusiveMaximum" : false
110+
* }
111+
* }
112+
* }
113+
* </code>
114+
* </pre>
115+
*/
116+
@Test
117+
public void schemaValidator() {
118+
119+
Validator validator = Validator.schema(MongoJsonSchema.builder() //
120+
.required("name", "age") //
121+
.properties( //
122+
string("name").minLength(1), //
123+
int32("age").gte(0).lte(125) //
124+
).build());
125+
mongoOps.createCollection(Jedi.class, CollectionOptions.empty().validator(validator));
126+
127+
assertThat(mongoOps.save(new Jedi("luke", "luke", "skywalker", 25))).isNotNull();
128+
129+
assertThatExceptionOfType(DataIntegrityViolationException.class)
130+
.isThrownBy(() -> mongoOps.save(new Jedi("yoda", "yoda", null, 900)));
131+
}
132+
}

0 commit comments

Comments
 (0)