Skip to content

Commit 5b13307

Browse files
Maciej Walkowiakodrotbohm
Maciej Walkowiak
authored andcommitted
DATAMONGO-36 - Added support for JSR-303 validation
Added event listener that uses a java.validation.Validator to trigger validation on an entity before persisting it. This validation is enabled by default if the javx.validation API is present on the classpath. Added namespace attribute 'disable-validation' to allow disabling that auto enabling behavior.
1 parent d317bcf commit 5b13307

File tree

15 files changed

+851
-7
lines changed

15 files changed

+851
-7
lines changed

Diff for: spring-data-mongodb/pom.xml

+16
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<mongo.version>2.7.1</mongo.version>
1616
<querydsl.version>2.3.2</querydsl.version>
1717
<cdi.version>1.0</cdi.version>
18+
<validation.version>1.0.0.GA</validation.version>
1819
<webbeans.version>1.1.3</webbeans.version>
1920
</properties>
2021

@@ -130,6 +131,21 @@
130131
<scope>test</scope>
131132
</dependency>
132133

134+
<!-- JSR 303 Validation -->
135+
<dependency>
136+
<groupId>javax.validation</groupId>
137+
<artifactId>validation-api</artifactId>
138+
<version>${validation.version}</version>
139+
<optional>true</optional>
140+
</dependency>
141+
142+
<dependency>
143+
<groupId>org.hibernate</groupId>
144+
<artifactId>hibernate-validator</artifactId>
145+
<version>4.2.0.Final</version>
146+
<scope>test</scope>
147+
</dependency>
148+
133149
</dependencies>
134150

135151
<build>

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java

+1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ public abstract class BeanNames {
2525
static final String INDEX_HELPER = "indexCreationHelper";
2626
static final String MONGO = "mongo";
2727
static final String DB_FACTORY = "mongoDbFactory";
28+
static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener";
2829
}

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java

+56-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
/*
2-
* Copyright (c) 2011 by the original author(s).
2+
* Copyright 2011-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.springframework.data.mongodb.config;
1817

1918
import static org.springframework.data.mongodb.config.BeanNames.*;
@@ -30,12 +29,14 @@
3029
import org.springframework.beans.factory.config.BeanDefinition;
3130
import org.springframework.beans.factory.config.BeanDefinitionHolder;
3231
import org.springframework.beans.factory.config.RuntimeBeanReference;
32+
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
3333
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3434
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3535
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3636
import org.springframework.beans.factory.support.GenericBeanDefinition;
3737
import org.springframework.beans.factory.support.ManagedList;
3838
import org.springframework.beans.factory.support.ManagedSet;
39+
import org.springframework.beans.factory.support.RootBeanDefinition;
3940
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
4041
import org.springframework.beans.factory.xml.ParserContext;
4142
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
@@ -52,18 +53,25 @@
5253
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
5354
import org.springframework.data.mongodb.core.mapping.Document;
5455
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
56+
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
5557
import org.springframework.util.Assert;
58+
import org.springframework.util.ClassUtils;
5659
import org.springframework.util.StringUtils;
5760
import org.springframework.util.xml.DomUtils;
5861
import org.w3c.dom.Element;
5962

6063
/**
61-
* @author Jon Brisbin <[email protected]>
64+
* Bean definition parser for the {@code mapping-converter} element.
65+
*
66+
* @author Jon Brisbin
6267
* @author Oliver Gierke
68+
* @author Maciej Walkowiak
6369
*/
6470
public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
6571

6672
private static final String BASE_PACKAGE = "base-package";
73+
private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator",
74+
MappingMongoConverterParser.class.getClassLoader());
6775

6876
@Override
6977
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
@@ -107,9 +115,53 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
107115
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
108116
}
109117

118+
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
119+
120+
if (validatingMongoEventListener != null) {
121+
registry.registerBeanDefinition(VALIDATING_EVENT_LISTENER, validatingMongoEventListener);
122+
}
123+
110124
return converterBuilder.getBeanDefinition();
111125
}
112126

127+
private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) {
128+
129+
String disableValidation = element.getAttribute("disable-validation");
130+
boolean validationDisabled = StringUtils.hasText(disableValidation) && Boolean.valueOf(disableValidation);
131+
132+
if (!validationDisabled) {
133+
134+
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
135+
RuntimeBeanReference validator = getValidator(builder, parserContext);
136+
137+
if (validator != null) {
138+
139+
builder.getRawBeanDefinition().setBeanClass(ValidatingMongoEventListener.class);
140+
builder.addConstructorArgValue(validator);
141+
142+
return builder.getBeanDefinition();
143+
}
144+
}
145+
146+
return null;
147+
}
148+
149+
private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) {
150+
151+
if (!jsr303Present) {
152+
return null;
153+
}
154+
155+
RootBeanDefinition validatorDef = new RootBeanDefinition(
156+
"org.springframework.validation.beanvalidation.LocalValidatorFactoryBean");
157+
validatorDef.setSource(source);
158+
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
159+
String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
160+
parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
161+
162+
return new RuntimeBeanReference(validatorName);
163+
}
164+
113165
private String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
114166
BeanDefinition conversionsDefinition) {
115167

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2012 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 org.springframework.data.mongodb.core.mapping.event;
17+
18+
import java.util.Set;
19+
20+
import javax.validation.ConstraintViolationException;
21+
import javax.validation.Validator;
22+
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
import org.springframework.util.Assert;
26+
27+
import com.mongodb.DBObject;
28+
29+
/**
30+
* javax.validation dependant entities validator. When it is registered as Spring component its automatically invoked
31+
* before entities are saved in database.
32+
*
33+
* @author Maciej Walkowiak
34+
*/
35+
public class ValidatingMongoEventListener extends AbstractMongoEventListener<Object> {
36+
37+
private static final Logger LOG = LoggerFactory.getLogger(ValidatingMongoEventListener.class);
38+
39+
private final Validator validator;
40+
41+
/**
42+
* Creates a new {@link ValidatingMongoEventListener} using the given {@link Validator}.
43+
*
44+
* @param validator must not be {@literal null}.
45+
*/
46+
public ValidatingMongoEventListener(Validator validator) {
47+
Assert.notNull(validator);
48+
this.validator = validator;
49+
}
50+
51+
/*
52+
* (non-Javadoc)
53+
* @see org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener#onBeforeSave(java.lang.Object, com.mongodb.DBObject)
54+
*/
55+
@Override
56+
@SuppressWarnings({ "rawtypes", "unchecked" })
57+
public void onBeforeSave(Object source, DBObject dbo) {
58+
59+
LOG.debug("Validating object: {}", source);
60+
Set violations = validator.validate(source);
61+
62+
if (!violations.isEmpty()) {
63+
64+
LOG.info("During object: {} validation violations found: {}", source, violations);
65+
throw new ConstraintViolationException(violations);
66+
}
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
http\://www.springframework.org/schema/data/mongo/spring-mongo-1.1.xsd=org/springframework/data/mongodb/config/spring-mongo-1.1.xsd
12
http\://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd=org/springframework/data/mongodb/config/spring-mongo-1.0.xsd
2-
http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.0.xsd
3+
http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.1.xsd

0 commit comments

Comments
 (0)