Skip to content

DATAMONGO-1393 fixed validation for Lazy Proxies #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand All @@ -31,6 +32,7 @@
* before entities are saved in database.
*
* @author Maciej Walkowiak
* @author Paul Sterl
*/
public class ValidatingMongoEventListener extends AbstractMongoEventListener<Object> {

Expand All @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<AddressRelation> addresses = new ArrayList<AddressRelation>();

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;
Expand All @@ -45,4 +110,10 @@ public String getName() {
public Integer getAge() {
return age;
}
public List<AddressRelation> getAddresses() {
return addresses;
}
public void setAddresses(List<AddressRelation> addresses) {
this.addresses = addresses;
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -15,16 +15,23 @@
*/
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;

import org.junit.ClassRule;
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;
Expand All @@ -37,22 +44,24 @@
* @author Maciej Walkowiak
* @author Oliver Gierke
* @author Christoph Strobl
* @author Paul Sterl
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
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() {

User user = new User("john", 17);

try {
mongoTemplate.save(user);
userRepo.save(user);
fail();
} catch (ConstraintViolationException e) {
assertThat(e.getConstraintViolations().size(), equalTo(2));
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<Address, ObjectId> {
}
Original file line number Diff line number Diff line change
@@ -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<User, ObjectId> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<mongo:db-factory dbname="validation" />

<mongo:mapping-converter base-package="org.springframework.data.mongodb.core" />
<mongo:repositories base-package="org.springframework.data.mongodb.core.mapping.event.repo" />

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
Expand Down