From cd120d9adeeb2b9c505ae236a34a3b31ce129df4 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 23 Apr 2012 18:09:18 +0200 Subject: [PATCH 1/6] DATAMONGO-36 - added support for JSR-303 validation --- spring-data-mongodb/pom.xml | 40 +++++++++++----- .../mapping/event/BeforeSaveValidator.java | 39 ++++++++++++++++ .../event/BeforeSaveValidatorTest.java | 46 +++++++++++++++++++ .../data/mongodb/core/mapping/event/User.java | 30 ++++++++++++ .../event/BeforeSaveValidatorTest-context.xml | 30 ++++++++++++ spring-data-mongodb/template.mf | 1 + 6 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java create mode 100644 spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index ad546153e5..2ac53d9c70 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 org.springframework.data @@ -42,9 +42,9 @@ ${org.springframework.version.range} - commons-logging - commons-logging - + commons-logging + commons-logging + @@ -99,7 +99,7 @@ 1.0 true - + javax.enterprise @@ -108,21 +108,21 @@ provided true - + javax.el el-api ${cdi.version} test - + org.apache.openwebbeans.test cditest-owb ${webbeans.version} test - + javax.servlet servlet-api @@ -130,8 +130,23 @@ test + + + javax.validation + validation-api + 1.0.0.GA + compile + + + + org.hibernate + hibernate-validator + 4.2.0.Final + test + + - + @@ -151,12 +166,13 @@ target/generated-test-sources - org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor + org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor + - + diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java new file mode 100644 index 0000000000..8d1c46962f --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java @@ -0,0 +1,39 @@ +package org.springframework.data.mongodb.core.mapping.event; + +import com.mongodb.DBObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * javax.validation dependant entities validator. + * When it is registered as Spring component its automatically invoked before entities are saved in database. + * + * @author Maciej Walkowiak + */ +public class BeforeSaveValidator extends AbstractMongoEventListener { + private static final Logger LOG = LoggerFactory.getLogger(BeforeSaveValidator.class); + + private Validator validator; + + @Override + public void onBeforeSave(Object source, DBObject dbo) { + LOG.debug("Validating object: {}", source); + + Set violations = validator.validate(source); + + if (violations.size() > 0) { + LOG.info("During object: {} validation violations found: {}", source, violations); + + throw new ConstraintViolationException((Set>) violations); + } + } + + public void setValidator(Validator validator) { + this.validator = validator; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java new file mode 100644 index 0000000000..3f39c5edc4 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java @@ -0,0 +1,46 @@ +package org.springframework.data.mongodb.core.mapping.event; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.validation.ConstraintViolationException; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class BeforeSaveValidatorTest { + @Autowired + private MongoTemplate mongoTemplate; + + @Test + public void shouldThrowConstraintViolationException() { + //given + User user = new User("john", 17); + + try { + //when + mongoTemplate.save(user); + + //then + fail(); + } catch (ConstraintViolationException e) { + assertThat(e.getConstraintViolations().size(), equalTo(2)); + } + } + + @Test + public void shouldNotThrowAnyExceptions() { + //given + User user = new User("john smith", 18); + + //when & then + mongoTemplate.save(user); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java new file mode 100644 index 0000000000..17d1207a44 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java @@ -0,0 +1,30 @@ +package org.springframework.data.mongodb.core.mapping.event; + +import javax.validation.constraints.Min; +import javax.validation.constraints.Size; + +/** + * Class used to test JSR-303 validation @{link org.springframework.data.mongodb.core.mapping.event.BeforeSaveValidator} + * + * @author Maciej Walkowiak + */ +public class User { + @Size(min = 10) + private String name; + + @Min(18) + private Integer age; + + public User(String name, Integer age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public Integer getAge() { + return age; + } +} diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml new file mode 100644 index 0000000000..7471b7eba3 --- /dev/null +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-mongodb/template.mf b/spring-data-mongodb/template.mf index ae1431b311..c0ead7cc56 100644 --- a/spring-data-mongodb/template.mf +++ b/spring-data-mongodb/template.mf @@ -10,6 +10,7 @@ Import-Template: com.mongodb.*;version="0", com.mysema.query.*;version="[2.1.1, 3.0.0)";resolution:=optional, javax.annotation.processing.*;version="0", + javax.validation.*;version="1.0.0.GA", javax.enterprise.*;version="${cdi.version:[=.=.=,+1.0.0)}";resolution:=optional, javax.tools.*;version="0", org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional, From e95add7248577871d4bbea03a5a44bd170876e0f Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 23 Apr 2012 18:24:55 +0200 Subject: [PATCH 2/6] DATAMONGO-36 - added check to make sure that bean has all required properties set --- .../mongodb/core/mapping/event/BeforeSaveValidator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java index 8d1c46962f..a4f3948710 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java @@ -3,6 +3,8 @@ import com.mongodb.DBObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; @@ -15,11 +17,15 @@ * * @author Maciej Walkowiak */ -public class BeforeSaveValidator extends AbstractMongoEventListener { +public class BeforeSaveValidator extends AbstractMongoEventListener implements InitializingBean { private static final Logger LOG = LoggerFactory.getLogger(BeforeSaveValidator.class); private Validator validator; + public void afterPropertiesSet() throws Exception { + Assert.notNull(validator, "Validator is not set"); + } + @Override public void onBeforeSave(Object source, DBObject dbo) { LOG.debug("Validating object: {}", source); From 5f3c1dba6e260953ad034577311065e83ece8037 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 23 Apr 2012 18:37:37 +0200 Subject: [PATCH 3/6] DATAMONGO-36 - fixed formatting --- spring-data-mongodb/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 2ac53d9c70..094d9a9a71 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -166,8 +166,7 @@ target/generated-test-sources - org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor - + org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor From 85ba6d51decff554c749f66ef06099cd4cc2a4cc Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 23 Apr 2012 21:36:33 +0200 Subject: [PATCH 4/6] DATAMONGO-36 - added option in Mongo XML namespace for enabling validation --- .../mongodb/config/MongoNamespaceHandler.java | 1 + .../mongodb/config/MongoValidationParser.java | 55 +++++++++++++++++++ .../data/mongodb/config/spring-mongo-1.0.xsd | 11 ++++ 3 files changed, 67 insertions(+) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java index 4eb27dee57..15369d30cf 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java @@ -37,5 +37,6 @@ public void init() { registerBeanDefinitionParser("mongo", new MongoParser()); registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser()); registerBeanDefinitionParser("jmx", new MongoJmxParser()); + registerBeanDefinitionParser("validation-enabled", new MongoValidationParser()); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java new file mode 100644 index 0000000000..28cd46ff31 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java @@ -0,0 +1,55 @@ +package org.springframework.data.mongodb.config; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.mongodb.core.mapping.event.BeforeSaveValidator; +import org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser; +import org.springframework.util.ClassUtils; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.w3c.dom.Element; + +public class MongoValidationParser extends AbstractBeanDefinitionParser { + private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { + return "beforeSaveValidator"; + } + + @Override + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); + + RuntimeBeanReference validator = getValidator(builder, parserContext); + + if (validator == null) { + return null; + } else { + builder.getRawBeanDefinition().setBeanClass(BeforeSaveValidator.class); + builder.addPropertyValue("validator", validator); + + return builder.getBeanDefinition(); + } + } + + private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) { + if (!jsr303Present) { + return null; + } + + RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); + validatorDef.setSource(source); + validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); + parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); + + return new RuntimeBeanReference(validatorName); + } +} diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd index 702c855b03..c3be263790 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd @@ -16,6 +16,17 @@ + + + + + + + + + Date: Mon, 23 Apr 2012 21:36:33 +0200 Subject: [PATCH 5/6] DATAMONGO-36 - added option in Mongo XML namespace for enabling validation --- .../mongodb/config/MongoValidationParser.java | 55 ------------------- ...java => ValidatingMongoEventListener.java} | 4 +- ...erterParserValidationIntegrationTests.java | 4 ++ ... => ValidatingMongoEventListenerTest.java} | 2 +- .../resources/namespace/converter-default.xml | 0 .../converter-validation-disabled.xml | 0 .../converter-validation-enabled.xml | 0 ...idatingMongoEventListenerTest-context.xml} | 2 +- 8 files changed, 8 insertions(+), 59 deletions(-) delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java rename spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/{BeforeSaveValidator.java => ValidatingMongoEventListener.java} (85%) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java rename spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/{BeforeSaveValidatorTest.java => ValidatingMongoEventListenerTest.java} (95%) create mode 100644 spring-data-mongodb/src/test/resources/namespace/converter-default.xml create mode 100644 spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml create mode 100644 spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml rename spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/{BeforeSaveValidatorTest-context.xml => ValidatingMongoEventListenerTest-context.xml} (92%) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java deleted file mode 100644 index 28cd46ff31..0000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoValidationParser.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.springframework.data.mongodb.config; - -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.mongodb.core.mapping.event.BeforeSaveValidator; -import org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser; -import org.springframework.util.ClassUtils; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.w3c.dom.Element; - -public class MongoValidationParser extends AbstractBeanDefinitionParser { - private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); - - @Override - protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { - return "beforeSaveValidator"; - } - - @Override - protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); - - RuntimeBeanReference validator = getValidator(builder, parserContext); - - if (validator == null) { - return null; - } else { - builder.getRawBeanDefinition().setBeanClass(BeforeSaveValidator.class); - builder.addPropertyValue("validator", validator); - - return builder.getBeanDefinition(); - } - } - - private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) { - if (!jsr303Present) { - return null; - } - - RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); - validatorDef.setSource(source); - validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); - parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); - - return new RuntimeBeanReference(validatorName); - } -} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java similarity index 85% rename from spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java rename to spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java index a4f3948710..5243b030a3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java @@ -17,8 +17,8 @@ * * @author Maciej Walkowiak */ -public class BeforeSaveValidator extends AbstractMongoEventListener implements InitializingBean { - private static final Logger LOG = LoggerFactory.getLogger(BeforeSaveValidator.class); +public class ValidatingMongoEventListener extends AbstractMongoEventListener implements InitializingBean { + private static final Logger LOG = LoggerFactory.getLogger(ValidatingMongoEventListener.class); private Validator validator; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java new file mode 100644 index 0000000000..d75d2c8394 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java @@ -0,0 +1,4 @@ +package org.springframework.data.mongodb.config; + +public class MappingMongoConverterParserValidationIntegrationTests { +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest.java similarity index 95% rename from spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java rename to spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest.java index 3f39c5edc4..f35ccb8b9d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest.java @@ -15,7 +15,7 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration -public class BeforeSaveValidatorTest { +public class ValidatingMongoEventListenerTest { @Autowired private MongoTemplate mongoTemplate; diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-default.xml b/spring-data-mongodb/src/test/resources/namespace/converter-default.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml b/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml b/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml similarity index 92% rename from spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml rename to spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml index 7471b7eba3..4571cbc904 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/BeforeSaveValidatorTest-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml @@ -17,7 +17,7 @@ - + From 65cc7c4dc2c5ba06864f2738e74051239ade57c2 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 27 Apr 2012 12:14:20 +0200 Subject: [PATCH 6/6] DATAMONGO-36 - changed class name to ValidatingMongoEventListener - replaced namespace validation-enabled to flag disable-validation in mongo:mapping-converter - added integration tests - minor fixes --- .../data/mongodb/config/BeanNames.java | 1 + .../config/MappingMongoConverterParser.java | 60 +++++++++++++++--- .../mongodb/config/MongoNamespaceHandler.java | 1 - .../event/ValidatingMongoEventListener.java | 29 ++++++--- .../data/mongodb/config/spring-mongo-1.0.xsd | 18 +++--- ...gMongoConverterParserIntegrationTests.java | 2 +- ...erterParserValidationIntegrationTests.java | 61 +++++++++++++++++++ .../data/mongodb/core/mapping/event/User.java | 2 +- .../resources/namespace/converter-default.xml | 10 +++ .../converter-validation-disabled.xml | 10 +++ .../converter-validation-enabled.xml | 10 +++ ...lidatingMongoEventListenerTest-context.xml | 5 +- 12 files changed, 172 insertions(+), 37 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java index c1d21bf094..2c4ef69d53 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java @@ -25,4 +25,5 @@ public abstract class BeanNames { static final String INDEX_HELPER = "indexCreationHelper"; static final String MONGO = "mongo"; static final String DB_FACTORY = "mongoDbFactory"; + static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener"; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java index 5e007e34ce..6fe7c1af0b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java @@ -30,12 +30,8 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.ManagedSet; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.*; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; @@ -52,18 +48,23 @@ import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener; +import org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.w3c.dom.Element; /** * @author Jon Brisbin * @author Oliver Gierke + * @author Maciej Walkowiak */ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { - private static final String BASE_PACKAGE = "base-package"; + private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) @@ -107,9 +108,50 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition()); } + BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext); + + if (validatingMongoEventListener != null) { + registry.registerBeanDefinition(VALIDATING_EVENT_LISTENER, validatingMongoEventListener); + } + return converterBuilder.getBeanDefinition(); } + private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) { + String disableValidation = element.getAttribute("disable-validation"); + + BeanDefinition result = null; + + if (disableValidation == null || Boolean.valueOf(disableValidation) == Boolean.FALSE) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); + + RuntimeBeanReference validator = getValidator(builder, parserContext); + + if (validator != null) { + builder.getRawBeanDefinition().setBeanClass(ValidatingMongoEventListener.class); + builder.addConstructorArgValue(validator); + + result = builder.getBeanDefinition(); + } + } + + return result; + } + + private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) { + if (!jsr303Present) { + return null; + } + + RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); + validatorDef.setSource(source); + validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); + parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); + + return new RuntimeBeanReference(validatorName); + } + private String potentiallyCreateMappingContext(Element element, ParserContext parserContext, BeanDefinition conversionsDefinition) { @@ -221,7 +263,7 @@ public BeanMetadataElement parseConverter(Element element, ParserContext parserC /** * {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches. - * + * * @author Oliver Gierke */ private static class NegatingFilter implements TypeFilter { @@ -230,7 +272,7 @@ private static class NegatingFilter implements TypeFilter { /** * Creates a new {@link NegatingFilter} with the given delegates. - * + * * @param filters */ public NegatingFilter(TypeFilter... filters) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java index 15369d30cf..4eb27dee57 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java @@ -37,6 +37,5 @@ public void init() { registerBeanDefinitionParser("mongo", new MongoParser()); registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser()); registerBeanDefinitionParser("jmx", new MongoJmxParser()); - registerBeanDefinitionParser("validation-enabled", new MongoValidationParser()); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java index 5243b030a3..5f9f8d817b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.java @@ -1,10 +1,23 @@ +/* + * Copyright 2010 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.mapping.event; import com.mongodb.DBObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; @@ -17,13 +30,13 @@ * * @author Maciej Walkowiak */ -public class ValidatingMongoEventListener extends AbstractMongoEventListener implements InitializingBean { +public class ValidatingMongoEventListener extends AbstractMongoEventListener { private static final Logger LOG = LoggerFactory.getLogger(ValidatingMongoEventListener.class); - private Validator validator; + private final Validator validator; - public void afterPropertiesSet() throws Exception { - Assert.notNull(validator, "Validator is not set"); + public ValidatingMongoEventListener(Validator validator) { + this.validator = validator; } @Override @@ -38,8 +51,4 @@ public void onBeforeSave(Object source, DBObject dbo) { throw new ConstraintViolationException((Set>) violations); } } - - public void setValidator(Validator validator) { - this.validator = validator; - } } diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd index c3be263790..c706ba8b9c 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd @@ -16,17 +16,6 @@ - - - - - - - - - + + + + Disables JSR-303 validation on MongoDB documents before they are saved. By default it is set to false. + + + diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserIntegrationTests.java index 533b6ce973..65b078d59c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserIntegrationTests.java @@ -37,7 +37,7 @@ import com.mongodb.DBObject; /** - * Integration tests for {@link MongoParser}. + * Integration tests for {@link MappingMongoConverterParser}. * * @author Oliver Gierke */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java index d75d2c8394..13eaddc6dc 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MappingMongoConverterParserValidationIntegrationTests.java @@ -1,4 +1,65 @@ +/* + * Copyright 2010 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.config; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * Integration test for creation of instance of {@link org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener} + * by defining <mongo:mapping-converter /> in context XML + * + * @author Maciej Walkowiak + */ public class MappingMongoConverterParserValidationIntegrationTests { + private DefaultListableBeanFactory factory; + private BeanDefinitionReader reader; + + @Before + public void setUp() { + factory = new DefaultListableBeanFactory(); + reader = new XmlBeanDefinitionReader(factory); + } + + @Test + public void validatingEventListenerCreatedWithDefaultConfig() { + reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-default.xml")); + + assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue()))); + } + + @Test + public void validatingEventListenerCreatedWhenValidationEnabled() { + reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-validation-enabled.xml")); + + assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue()))); + } + + @Test(expected = NoSuchBeanDefinitionException.class) + public void validatingEventListenersIsNotCreatedWhenDisabled() { + reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-validation-disabled.xml")); + + factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java index 17d1207a44..099d5001cc 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/User.java @@ -4,7 +4,7 @@ import javax.validation.constraints.Size; /** - * Class used to test JSR-303 validation @{link org.springframework.data.mongodb.core.mapping.event.BeforeSaveValidator} + * Class used to test JSR-303 validation @{link org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener} * * @author Maciej Walkowiak */ diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-default.xml b/spring-data-mongodb/src/test/resources/namespace/converter-default.xml index e69de29bb2..76a4cb1b1e 100644 --- a/spring-data-mongodb/src/test/resources/namespace/converter-default.xml +++ b/spring-data-mongodb/src/test/resources/namespace/converter-default.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml b/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml index e69de29bb2..a8035d5719 100644 --- a/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml +++ b/spring-data-mongodb/src/test/resources/namespace/converter-validation-disabled.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml b/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml index e69de29bb2..0c97b7f7d3 100644 --- a/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml +++ b/spring-data-mongodb/src/test/resources/namespace/converter-validation-enabled.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml index 4571cbc904..1e54713b16 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTest-context.xml @@ -17,14 +17,11 @@ - + - - -