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 4dd8e96dd7..1b08555132 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,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * Copyright 2012-2016 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. @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.data.mongodb.core.convert.LazyLoadingProxy; import org.springframework.util.Assert; import com.mongodb.DBObject; @@ -31,6 +32,7 @@ * before entities are saved in database. * * @author Maciej Walkowiak + * @author Paul Sterl */ public class ValidatingMongoEventListener extends AbstractMongoEventListener { @@ -54,14 +56,15 @@ public ValidatingMongoEventListener(Validator validator) { */ @Override @SuppressWarnings({ "rawtypes", "unchecked" }) - public void onBeforeSave(Object source, DBObject dbo) { + public void onBeforeSave(Object obj, DBObject dbo) { - LOG.debug("Validating object: {}", source); - Set violations = validator.validate(source); + LOG.debug("Validating object: {}", obj); + final Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj; + final Set violations = validator.validate(target); if (!violations.isEmpty()) { - LOG.info("During object: {} validation violations found: {}", source, violations); + LOG.info("During object: {} validation violations found: {}", target, violations); throw new ConstraintViolationException(violations); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/Address.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/Address.java new file mode 100644 index 0000000000..e7eae8eab0 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/Address.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016 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 javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @see DATAMONGO-1393 + * @author Paul Sterl + */ +@Document(collection = "ADDRESS") +public class Address { + + @Id + private ObjectId id; + + @NotNull @Size(min = 2) + private String name; + + public Address() { + super(); + } + public Address(String name) { + this(); + this.name = name; + } + public ObjectId getId() { + return id; + } + public void setId(ObjectId id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} 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 c638aeadc6..2652a51255 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * Copyright 2012-2016 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,28 +15,93 @@ */ package org.springframework.data.mongodb.core.mapping.event; +import java.util.ArrayList; +import java.util.List; + import javax.validation.constraints.Min; import javax.validation.constraints.Size; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.event.User.AddressRelation.Type; + /** * Class used to test JSR-303 validation * {@link org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener} * * @see DATAMONGO-36 * @author Maciej Walkowiak + * @author Paul Sterl */ +@Document(collection = "USER") public class User { + + public static class AddressRelation { + public enum Type { + PRIVATE, + WORK + } + private Type type = Type.PRIVATE; + @DBRef(lazy = true) + private Address address; + // needed otherwise spring doesn't create the proxy for some reason ... + public AddressRelation() { + super(); + } + public AddressRelation(Type type, Address address) { + this(); + this.type = type; + this.address = address; + } + public Type getType() { + return type; + } + public void setType(Type type) { + this.type = type; + } + public Address getAddress() { + return address; + } + public void setAddress(Address address) { + this.address = address; + } + } + + @Id + private ObjectId id; @Size(min = 10) private String name; @Min(18) private Integer age; + + private List addresses = new ArrayList(); + public User() { + super(); + } public User(String name, Integer age) { + this(); this.name = name; this.age = age; } + public User(String name, Integer age, Address...addresses) { + this(name, age); + for (Address address : addresses) { + this.addresses.add(new AddressRelation(Type.WORK, address)); + } + } + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } public String getName() { return name; @@ -45,4 +110,10 @@ public String getName() { public Integer getAge() { return age; } + public List getAddresses() { + return addresses; + } + public void setAddresses(List addresses) { + this.addresses = addresses; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests.java index 8a8d06cd3e..567619168e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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,8 +15,12 @@ */ package org.springframework.data.mongodb.core.mapping.event; -import static org.hamcrest.core.IsEqual.*; -import static org.junit.Assert.*; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.UUID; import javax.validation.ConstraintViolationException; @@ -24,7 +28,10 @@ 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.data.mongodb.core.convert.LazyLoadingProxy; +import org.springframework.data.mongodb.core.mapping.event.User.AddressRelation; +import org.springframework.data.mongodb.core.mapping.event.repo.AddressRepository; +import org.springframework.data.mongodb.core.mapping.event.repo.UserRepository; import org.springframework.data.mongodb.test.util.MongoVersionRule; import org.springframework.data.util.Version; import org.springframework.test.context.ContextConfiguration; @@ -37,6 +44,7 @@ * @author Maciej Walkowiak * @author Oliver Gierke * @author Christoph Strobl + * @author Paul Sterl */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @@ -44,7 +52,8 @@ public class ValidatingMongoEventListenerTests { public static @ClassRule MongoVersionRule version = MongoVersionRule.atLeast(new Version(2, 6)); - @Autowired MongoTemplate mongoTemplate; + @Autowired AddressRepository addressRepo; + @Autowired UserRepository userRepo; @Test public void shouldThrowConstraintViolationException() { @@ -52,7 +61,7 @@ public void shouldThrowConstraintViolationException() { User user = new User("john", 17); try { - mongoTemplate.save(user); + userRepo.save(user); fail(); } catch (ConstraintViolationException e) { assertThat(e.getConstraintViolations().size(), equalTo(2)); @@ -61,6 +70,34 @@ public void shouldThrowConstraintViolationException() { @Test public void shouldNotThrowAnyExceptions() { - mongoTemplate.save(new User("john smith", 18)); + userRepo.save(new User("john smith", 18)); + } + + /** + * @see DATAMONGO-1393 + */ + @Test + public void validationOfLazyProxy() { + Address address = addressRepo.insert(new Address(UUID.randomUUID().toString())); + User user = userRepo.insert(new User("Foo Bar Name 123456", 18, address)); + + user = userRepo.findOne(user.getId()); + assertTrue("Spring should use now a LazyLoadingProxy.", user.getAddresses().get(0).getAddress() instanceof LazyLoadingProxy); + address = user.getAddresses().get(0).getAddress(); + address.setName("New Fancy Address Name"); + addressRepo.save(address); + } + /** + * @see DATAMONGO-1393 + */ + @Test(expected = ConstraintViolationException.class) + public void validationErrorTest() { + Address address = addressRepo.insert(new Address(UUID.randomUUID().toString())); + User user = userRepo.insert(new User("Foo Bar Name 123456", 18, address)); + + user = userRepo.findOne(user.getId()); + address = user.getAddresses().get(0).getAddress(); + address.setName(null); + addressRepo.save(address); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/AddressRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/AddressRepository.java new file mode 100644 index 0000000000..294eaa1086 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/AddressRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 by the original author(s). + * + * 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.repo; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.core.mapping.event.Address; +import org.springframework.data.mongodb.repository.MongoRepository; + +/** + * @author Paul Sterl + */ +public interface AddressRepository extends MongoRepository { +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/UserRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/UserRepository.java new file mode 100644 index 0000000000..5d04c0b442 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/repo/UserRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 by the original author(s). + * + * 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.repo; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.core.mapping.event.User; +import org.springframework.data.mongodb.repository.MongoRepository; + +/** + * @author Paul Sterl + */ +public interface UserRepository extends MongoRepository { +} diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests-context.xml index 97797b9847..9c7e41e2b9 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListenerTests-context.xml @@ -10,6 +10,7 @@ +