Merge pull request #236 from alex-semenyuk/master

Introduction to Spring Data MongoDB (continue)
This commit is contained in:
Eugen 2015-08-15 14:58:41 -07:00
commit 393c1eac14
12 changed files with 230 additions and 9 deletions

View File

@ -0,0 +1,12 @@
package org.baeldung.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CascadeSave {
}

View File

@ -1,7 +1,15 @@
package org.baeldung.config; package org.baeldung.config;
import java.util.ArrayList;
import java.util.List;
import org.baeldung.converter.UserWriterConverter;
import org.baeldung.event.CascadeSaveMongoEventListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration; import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.Mongo; import com.mongodb.Mongo;
@ -11,6 +19,8 @@ import com.mongodb.MongoClient;
@EnableMongoRepositories(basePackages = "org.baeldung.repository") @EnableMongoRepositories(basePackages = "org.baeldung.repository")
public class MongoConfig extends AbstractMongoConfiguration { public class MongoConfig extends AbstractMongoConfiguration {
private List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
@Override @Override
protected String getDatabaseName() { protected String getDatabaseName() {
return "test"; return "test";
@ -25,4 +35,15 @@ public class MongoConfig extends AbstractMongoConfiguration {
public String getMappingBasePackage() { public String getMappingBasePackage() {
return "org.baeldung"; return "org.baeldung";
} }
@Bean
public CascadeSaveMongoEventListener cascadingMongoEventListener() {
return new CascadeSaveMongoEventListener();
}
@Override
public CustomConversions customConversions() {
converters.add(new UserWriterConverter());
return new CustomConversions(converters);
}
} }

View File

@ -0,0 +1,25 @@
package org.baeldung.converter;
import org.springframework.stereotype.Component;
import org.baeldung.model.User;
import org.springframework.core.convert.converter.Converter;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@Component
public class UserWriterConverter implements Converter<User, DBObject> {
@Override
public DBObject convert(User user) {
DBObject dbObject = new BasicDBObject();
dbObject.put("name", user.getName());
dbObject.put("age", user.getAge());
if (user.getEmailAddress() != null) {
DBObject emailDbObject = new BasicDBObject();
emailDbObject.put("value", user.getEmailAddress().getValue());
dbObject.put("email", emailDbObject);
}
dbObject.removeField("_class");
return dbObject;
}
}

View File

@ -0,0 +1,37 @@
package org.baeldung.event;
import org.baeldung.annotation.CascadeSave;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
public class CascadeSaveMongoEventListener extends AbstractMongoEventListener<Object> {
@Autowired
private MongoOperations mongoOperations;
@Override
public void onBeforeConvert(final Object source) {
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)) {
final Object fieldValue = field.get(source);
if (fieldValue != null) {
FieldCallback callback = new FieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
mongoOperations.save(fieldValue);
}
}
}
});
}
}

View File

@ -0,0 +1,22 @@
package org.baeldung.event;
import java.lang.reflect.Field;
import org.springframework.data.annotation.Id;
import org.springframework.util.ReflectionUtils;
public class FieldCallback implements ReflectionUtils.FieldCallback {
private boolean idFound;
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(Id.class)) {
idFound = true;
}
}
public boolean isIdFound() {
return idFound;
}
}

View File

@ -0,0 +1,27 @@
package org.baeldung.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class EmailAddress {
@Id
private String id;
private String value;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}

View File

@ -1,7 +1,12 @@
package org.baeldung.model; package org.baeldung.model;
import org.baeldung.annotation.CascadeSave;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.IndexDirection;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import com.mysema.query.annotations.QueryEntity; import com.mysema.query.annotations.QueryEntity;
@ -11,9 +16,16 @@ public class User {
@Id @Id
private String id; private String id;
@Indexed(direction = IndexDirection.ASCENDING)
private String name; private String name;
private Integer age; private Integer age;
@DBRef
@Field("email")
@CascadeSave
private EmailAddress emailAddress;
public String getId() { public String getId() {
return id; return id;
} }
@ -37,4 +49,12 @@ public class User {
public void setAge(final Integer age) { public void setAge(final Integer age) {
this.age = age; this.age = age;
} }
public EmailAddress getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(EmailAddress emailAddress) {
this.emailAddress = emailAddress;
}
} }

View File

@ -17,6 +17,7 @@
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/> <constructor-arg name="mongo" ref="mongo"/>
<constructor-arg ref="mongoConverter" />
<constructor-arg name="databaseName" value="test"/> <constructor-arg name="databaseName" value="test"/>
</bean> </bean>
@ -24,7 +25,11 @@
<mongo:repositories base-package="org.baeldung.repository" mongo-template-ref="mongoTemplate"/> <mongo:repositories base-package="org.baeldung.repository" mongo-template-ref="mongoTemplate"/>
<bean class="org.baeldung.event.BeforeConvertListener"> <bean class="org.baeldung.event.CascadeSaveMongoEventListener">
</bean> </bean>
<mongo:mapping-converter id="mongoConverter" base-package="org.baeldung.converter">
<mongo:custom-converters base-package="org.baeldung.converter"/>
</mongo:mapping-converter>
</beans> </beans>

View File

@ -7,6 +7,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import org.baeldung.config.MongoConfig; import org.baeldung.config.MongoConfig;
import org.baeldung.model.EmailAddress;
import org.baeldung.model.User; import org.baeldung.model.User;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -31,11 +32,14 @@ public class DocumentQueryIntegrationTest {
@Before @Before
public void testSetup() { public void testSetup() {
if (!mongoTemplate.collectionExists(User.class)) {
mongoTemplate.createCollection(User.class); mongoTemplate.createCollection(User.class);
} }
}
@After @After
public void tearDown() { public void tearDown() {
mongoTemplate.dropCollection(EmailAddress.class);
mongoTemplate.dropCollection(User.class); mongoTemplate.dropCollection(User.class);
} }

View File

@ -6,6 +6,7 @@ import static org.junit.Assert.assertThat;
import java.util.List; import java.util.List;
import org.baeldung.config.MongoConfig; import org.baeldung.config.MongoConfig;
import org.baeldung.model.EmailAddress;
import org.baeldung.model.User; import org.baeldung.model.User;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -15,7 +16,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
@ -30,8 +34,10 @@ public class MongoTemplateQueryIntegrationTest {
@Before @Before
public void testSetup() { public void testSetup() {
if (!mongoTemplate.collectionExists(User.class)) {
mongoTemplate.createCollection(User.class); mongoTemplate.createCollection(User.class);
} }
}
@After @After
public void tearDown() { public void tearDown() {
@ -128,4 +134,42 @@ public class MongoTemplateQueryIntegrationTest {
List<User> users = mongoTemplate.find(query, User.class); List<User> users = mongoTemplate.find(query, User.class);
assertThat(users.size(), is(3)); assertThat(users.size(), is(3));
} }
@Test
public void givenUserExistsWithIndexAddedFromMapping_whenCheckingIndex_thenIndexIsExisted() {
final User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("a@gmail.com");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
List<IndexInfo> indexInfos = mongoTemplate.indexOps("user").getIndexInfo();
assertThat(indexInfos.size(), is(1));
}
@Test
public void whenSavingUserWithEmailAddress_thenUserandEmailAddressSaved() {
final User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("b@gmail.com");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
assertThat(mongoTemplate.findOne(Query.query(Criteria.where("name").is("Brendan")), User.class).getEmailAddress().getValue(), is("b@gmail.com"));
}
@Test
public void givenUserExistsWithIndexAddedFromCode_whenCheckingIndex_thenIndexIsExisted() {
final User user = new User();
user.setName("Brendan");
mongoTemplate.indexOps(User.class).ensureIndex(new Index().on("name", Direction.ASC));
mongoTemplate.insert(user);
List<IndexInfo> indexInfos = mongoTemplate.indexOps("user").getIndexInfo();
assertThat(indexInfos.size(), is(2));
}
} }

View File

@ -17,8 +17,10 @@ public class BaseQueryIntegrationTest {
@Before @Before
public void testSetup() { public void testSetup() {
if (!mongoOps.collectionExists(User.class)) {
mongoOps.createCollection(User.class); mongoOps.createCollection(User.class);
} }
}
@After @After
public void tearDown() { public void tearDown() {

View File

@ -34,8 +34,10 @@ public class UserRepositoryIntegrationTest {
@Before @Before
public void testSetup() { public void testSetup() {
if (!mongoOps.collectionExists(User.class)) {
mongoOps.createCollection(User.class); mongoOps.createCollection(User.class);
} }
}
@After @After
public void tearDown() { public void tearDown() {
@ -67,12 +69,11 @@ public class UserRepositoryIntegrationTest {
mongoOps.insert(user); mongoOps.insert(user);
user = mongoOps.findOne(Query.query(Criteria.where("name").is("Jack")), User.class); user = mongoOps.findOne(Query.query(Criteria.where("name").is("Jack")), User.class);
final String id = user.getId();
user.setName("Jim"); user.setName("Jim");
userRepository.save(user); userRepository.save(user);
assertThat(mongoOps.findOne(Query.query(Criteria.where("id").is(id)), User.class).getName(), is("Jim")); assertThat(mongoOps.findAll(User.class).size(), is(2));
} }
@Test @Test
@ -145,4 +146,5 @@ public class UserRepositoryIntegrationTest {
assertThat(users.size(), is(1)); assertThat(users.size(), is(1));
assertThat(page.getTotalPages(), is(2)); assertThat(page.getTotalPages(), is(2));
} }
} }