diff --git a/spring-data-mongodb/src/main/java/org/baeldung/annotation/CascadeSave.java b/spring-data-mongodb/src/main/java/org/baeldung/annotation/CascadeSave.java new file mode 100644 index 0000000000..9fba40245b --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/baeldung/annotation/CascadeSave.java @@ -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 { + +} diff --git a/spring-data-mongodb/src/main/java/org/baeldung/config/MongoConfig.java b/spring-data-mongodb/src/main/java/org/baeldung/config/MongoConfig.java index d9214c182b..4b776af5b6 100644 --- a/spring-data-mongodb/src/main/java/org/baeldung/config/MongoConfig.java +++ b/spring-data-mongodb/src/main/java/org/baeldung/config/MongoConfig.java @@ -1,7 +1,15 @@ 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.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 com.mongodb.Mongo; @@ -11,6 +19,8 @@ import com.mongodb.MongoClient; @EnableMongoRepositories(basePackages = "org.baeldung.repository") public class MongoConfig extends AbstractMongoConfiguration { + private List> converters = new ArrayList>(); + @Override protected String getDatabaseName() { return "test"; @@ -25,4 +35,15 @@ public class MongoConfig extends AbstractMongoConfiguration { public String getMappingBasePackage() { return "org.baeldung"; } + + @Bean + public CascadeSaveMongoEventListener cascadingMongoEventListener() { + return new CascadeSaveMongoEventListener(); + } + + @Override + public CustomConversions customConversions() { + converters.add(new UserWriterConverter()); + return new CustomConversions(converters); + } } diff --git a/spring-data-mongodb/src/main/java/org/baeldung/converter/UserWriterConverter.java b/spring-data-mongodb/src/main/java/org/baeldung/converter/UserWriterConverter.java new file mode 100644 index 0000000000..18f2314c6b --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/baeldung/converter/UserWriterConverter.java @@ -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 { + @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; + } +} diff --git a/spring-data-mongodb/src/main/java/org/baeldung/event/CascadeSaveMongoEventListener.java b/spring-data-mongodb/src/main/java/org/baeldung/event/CascadeSaveMongoEventListener.java new file mode 100644 index 0000000000..ad09f1ac04 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/baeldung/event/CascadeSaveMongoEventListener.java @@ -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 { + @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); + } + } + } + }); + } +} diff --git a/spring-data-mongodb/src/main/java/org/baeldung/event/FieldCallback.java b/spring-data-mongodb/src/main/java/org/baeldung/event/FieldCallback.java new file mode 100644 index 0000000000..868bbc31f0 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/baeldung/event/FieldCallback.java @@ -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; + } +} diff --git a/spring-data-mongodb/src/main/java/org/baeldung/model/EmailAddress.java b/spring-data-mongodb/src/main/java/org/baeldung/model/EmailAddress.java new file mode 100644 index 0000000000..6db7d160d7 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/baeldung/model/EmailAddress.java @@ -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; + } +} diff --git a/spring-data-mongodb/src/main/java/org/baeldung/model/User.java b/spring-data-mongodb/src/main/java/org/baeldung/model/User.java index 8cf516762d..e5977c658a 100644 --- a/spring-data-mongodb/src/main/java/org/baeldung/model/User.java +++ b/spring-data-mongodb/src/main/java/org/baeldung/model/User.java @@ -1,7 +1,12 @@ package org.baeldung.model; +import org.baeldung.annotation.CascadeSave; 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.Field; import com.mysema.query.annotations.QueryEntity; @@ -11,9 +16,16 @@ public class User { @Id private String id; + @Indexed(direction = IndexDirection.ASCENDING) private String name; + private Integer age; + @DBRef + @Field("email") + @CascadeSave + private EmailAddress emailAddress; + public String getId() { return id; } @@ -37,4 +49,12 @@ public class User { public void setAge(final Integer age) { this.age = age; } + + public EmailAddress getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(EmailAddress emailAddress) { + this.emailAddress = emailAddress; + } } diff --git a/spring-data-mongodb/src/main/resources/mongoConfig.xml b/spring-data-mongodb/src/main/resources/mongoConfig.xml index 1bda9d0303..1a9d161ad6 100644 --- a/spring-data-mongodb/src/main/resources/mongoConfig.xml +++ b/spring-data-mongodb/src/main/resources/mongoConfig.xml @@ -10,21 +10,26 @@ http://www.springframework.org/schema/context/spring-context-3.2.xsd" > - + + - - + + + + + + \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/DocumentQueryIntegrationTest.java b/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/DocumentQueryIntegrationTest.java index 75077c19cb..cf46c6ed6e 100644 --- a/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/DocumentQueryIntegrationTest.java +++ b/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/DocumentQueryIntegrationTest.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.List; import org.baeldung.config.MongoConfig; +import org.baeldung.model.EmailAddress; import org.baeldung.model.User; import org.junit.After; import org.junit.Before; @@ -31,11 +32,14 @@ public class DocumentQueryIntegrationTest { @Before public void testSetup() { - mongoTemplate.createCollection(User.class); + if (!mongoTemplate.collectionExists(User.class)) { + mongoTemplate.createCollection(User.class); + } } @After public void tearDown() { + mongoTemplate.dropCollection(EmailAddress.class); mongoTemplate.dropCollection(User.class); } diff --git a/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/MongoTemplateQueryIntegrationTest.java b/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/MongoTemplateQueryIntegrationTest.java index 2a8a2fd71b..f0185e97a4 100644 --- a/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/MongoTemplateQueryIntegrationTest.java +++ b/spring-data-mongodb/src/test/java/org/baeldung/mongotemplate/MongoTemplateQueryIntegrationTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertThat; import java.util.List; import org.baeldung.config.MongoConfig; +import org.baeldung.model.EmailAddress; import org.baeldung.model.User; import org.junit.After; 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.Pageable; 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.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.Query; import org.springframework.test.context.ContextConfiguration; @@ -30,7 +34,9 @@ public class MongoTemplateQueryIntegrationTest { @Before public void testSetup() { - mongoTemplate.createCollection(User.class); + if (!mongoTemplate.collectionExists(User.class)) { + mongoTemplate.createCollection(User.class); + } } @After @@ -128,4 +134,42 @@ public class MongoTemplateQueryIntegrationTest { List users = mongoTemplate.find(query, User.class); 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 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 indexInfos = mongoTemplate.indexOps("user").getIndexInfo(); + + assertThat(indexInfos.size(), is(2)); + } } diff --git a/spring-data-mongodb/src/test/java/org/baeldung/repository/BaseQueryIntegrationTest.java b/spring-data-mongodb/src/test/java/org/baeldung/repository/BaseQueryIntegrationTest.java index 459716c7ca..8572cc858e 100644 --- a/spring-data-mongodb/src/test/java/org/baeldung/repository/BaseQueryIntegrationTest.java +++ b/spring-data-mongodb/src/test/java/org/baeldung/repository/BaseQueryIntegrationTest.java @@ -17,7 +17,9 @@ public class BaseQueryIntegrationTest { @Before public void testSetup() { - mongoOps.createCollection(User.class); + if (!mongoOps.collectionExists(User.class)) { + mongoOps.createCollection(User.class); + } } @After diff --git a/spring-data-mongodb/src/test/java/org/baeldung/repository/UserRepositoryIntegrationTest.java b/spring-data-mongodb/src/test/java/org/baeldung/repository/UserRepositoryIntegrationTest.java index 009191f03e..53cadc09bc 100644 --- a/spring-data-mongodb/src/test/java/org/baeldung/repository/UserRepositoryIntegrationTest.java +++ b/spring-data-mongodb/src/test/java/org/baeldung/repository/UserRepositoryIntegrationTest.java @@ -34,7 +34,9 @@ public class UserRepositoryIntegrationTest { @Before public void testSetup() { - mongoOps.createCollection(User.class); + if (!mongoOps.collectionExists(User.class)) { + mongoOps.createCollection(User.class); + } } @After @@ -67,12 +69,11 @@ public class UserRepositoryIntegrationTest { mongoOps.insert(user); user = mongoOps.findOne(Query.query(Criteria.where("name").is("Jack")), User.class); - final String id = user.getId(); user.setName("Jim"); 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 @@ -145,4 +146,5 @@ public class UserRepositoryIntegrationTest { assertThat(users.size(), is(1)); assertThat(page.getTotalPages(), is(2)); } + }