From 073a07f4caaac7993ab9ccfaf24fde4510539d45 Mon Sep 17 00:00:00 2001 From: HARDEMAN Sebastien Date: Mon, 27 Jun 2022 15:32:38 +0200 Subject: [PATCH] BAEL-5404 - UUID as Entity ID in MongoDB Commit to spring-data-mongodb-2 --- .../UuidIdentifiedEntityEventListener.java | 23 +++++++ .../java/com/baeldung/uuid/model/Book.java | 26 ++++++++ .../uuid/model/UuidIdentifiedEntity.java | 25 ++++++++ .../uuid/repository/BookRepository.java | 11 ++++ .../repository/CustomMongoRepository.java | 14 ++++ .../impl/CustomMongoRepositoryImpl.java | 52 +++++++++++++++ .../uuid/CustomRepositoryLiveTest.java | 59 +++++++++++++++++ .../baeldung/uuid/EntityCallbackLiveTest.java | 64 +++++++++++++++++++ .../java/com/baeldung/uuid/EventLiveTest.java | 64 +++++++++++++++++++ .../config/CustomRepositoryMongoConfig.java | 32 ++++++++++ .../config/EntityCallbackMongoConfig.java | 48 ++++++++++++++ .../uuid/config/EventMongoConfig.java | 38 +++++++++++ 12 files changed, 456 insertions(+) create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/event/UuidIdentifiedEntityEventListener.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/Book.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/UuidIdentifiedEntity.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/BookRepository.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/CustomMongoRepository.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/impl/CustomMongoRepositoryImpl.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/CustomRepositoryLiveTest.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EntityCallbackLiveTest.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EventLiveTest.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/CustomRepositoryMongoConfig.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EntityCallbackMongoConfig.java create mode 100644 persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EventMongoConfig.java diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/event/UuidIdentifiedEntityEventListener.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/event/UuidIdentifiedEntityEventListener.java new file mode 100644 index 0000000000..ce45d1e7bb --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/event/UuidIdentifiedEntityEventListener.java @@ -0,0 +1,23 @@ +package com.baeldung.uuid.event; + +import java.util.UUID; + +import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; +import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent; + +import com.baeldung.uuid.model.UuidIdentifiedEntity; + + +public class UuidIdentifiedEntityEventListener extends AbstractMongoEventListener { + + @Override + public void onBeforeConvert(BeforeConvertEvent event) { + + super.onBeforeConvert(event); + UuidIdentifiedEntity entity = event.getSource(); + + if(entity.getId() == null) { + entity.setId(UUID.randomUUID()); + } + } +} diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/Book.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/Book.java new file mode 100644 index 0000000000..f6aa1c615e --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/Book.java @@ -0,0 +1,26 @@ +package com.baeldung.uuid.model; + +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Book extends UuidIdentifiedEntity { + + private String title; + private String author; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } +} diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/UuidIdentifiedEntity.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/UuidIdentifiedEntity.java new file mode 100644 index 0000000000..aee0368b46 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/model/UuidIdentifiedEntity.java @@ -0,0 +1,25 @@ +package com.baeldung.uuid.model; + +import java.util.UUID; + +import org.springframework.data.annotation.Id; + +public abstract class UuidIdentifiedEntity { + + @Id + protected UUID id; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + + if(this.id != null) { + + throw new UnsupportedOperationException("ID is already defined"); + } + + this.id = id; + } +} diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/BookRepository.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/BookRepository.java new file mode 100644 index 0000000000..0d6eb790aa --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/BookRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.uuid.repository; + +import java.util.UUID; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.uuid.model.Book; + +public interface BookRepository extends MongoRepository { + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/CustomMongoRepository.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/CustomMongoRepository.java new file mode 100644 index 0000000000..599bc9ef61 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/CustomMongoRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.uuid.repository; + +import java.util.UUID; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.repository.NoRepositoryBean; + +import com.baeldung.uuid.model.UuidIdentifiedEntity; + + +@NoRepositoryBean +public interface CustomMongoRepository extends MongoRepository { + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/impl/CustomMongoRepositoryImpl.java b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/impl/CustomMongoRepositoryImpl.java new file mode 100644 index 0000000000..9764d0b06e --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/main/java/com/baeldung/uuid/repository/impl/CustomMongoRepositoryImpl.java @@ -0,0 +1,52 @@ +package com.baeldung.uuid.repository.impl; + +import java.util.List; +import java.util.UUID; + +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.repository.query.MongoEntityInformation; +import org.springframework.data.mongodb.repository.support.SimpleMongoRepository; + +import com.baeldung.uuid.model.UuidIdentifiedEntity; +import com.baeldung.uuid.repository.CustomMongoRepository; + + +public class CustomMongoRepositoryImpl extends SimpleMongoRepository implements CustomMongoRepository { + + public CustomMongoRepositoryImpl(MongoEntityInformation metadata, MongoOperations mongoOperations) { + + super(metadata, mongoOperations); + } + + @Override + public S save(S entity) { + generateId(entity); + return super.save(entity); + } + + @Override + public List saveAll(Iterable entities) { + entities.forEach(entity -> generateId(entity)); + return super.saveAll(entities); + } + + @Override + public S insert(S entity) { + generateId(entity); + return super.insert(entity); + } + + @Override + public List insert(Iterable entities) { + entities.forEach(entity -> generateId(entity)); + return super.insert(entities); + } + + protected void generateId(S entity) { + + if(entity != null && entity.getId() == null) { + entity.setId(UUID.randomUUID()); + } + } + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/CustomRepositoryLiveTest.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/CustomRepositoryLiveTest.java new file mode 100644 index 0000000000..0fc3fddfd7 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/CustomRepositoryLiveTest.java @@ -0,0 +1,59 @@ +package com.baeldung.uuid; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.uuid.config.CustomRepositoryMongoConfig; +import com.baeldung.uuid.model.Book; +import com.baeldung.uuid.repository.BookRepository; + +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = CustomRepositoryMongoConfig.class) +public class CustomRepositoryLiveTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private MongoOperations mongoOps; + + @Before + public void testSetup() { + if (!mongoOps.collectionExists(Book.class)) { + mongoOps.createCollection(Book.class); + } + } + + @After + public void tearDown() { + mongoOps.dropCollection(Book.class); + } + + @Test + public void whenInsertingBook_thenBookIsInserted() { + final Book book = new Book(); + book.setTitle("The Lord of the Rings"); + book.setAuthor("JRR Tolkien"); + Book savedBook = bookRepository.save(book); + + Book result = mongoOps.findOne(Query.query(Criteria.where("_id").is(savedBook.getId())), Book.class); + + assertEquals(result.getTitle(), "The Lord of the Rings"); + } +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EntityCallbackLiveTest.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EntityCallbackLiveTest.java new file mode 100644 index 0000000000..737c2d8adb --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EntityCallbackLiveTest.java @@ -0,0 +1,64 @@ +package com.baeldung.uuid; + +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.uuid.config.EntityCallbackMongoConfig; +import com.baeldung.uuid.model.Book; +import com.baeldung.uuid.repository.BookRepository; + +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = EntityCallbackMongoConfig.class) +public class EntityCallbackLiveTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private MongoOperations mongoOps; + + @Before + public void testSetup() { + if (!mongoOps.collectionExists(Book.class)) { + mongoOps.createCollection(Book.class); + } + } + + @After + public void tearDown() { + mongoOps.dropCollection(Book.class); + } + + @Test + public void whenSavingArticle_thenArticleIsInserted() { + final Book book = new Book(); + book.setTitle("The Lord of the Rings"); + book.setAuthor("JRR Tolkien"); + + Book savedArticle = bookRepository.save(book); + + Book result = mongoOps.findOne(Query.query(Criteria.where("_id").is(savedArticle.getId())), Book.class); + + assertNotNull(result); + assertEquals(result.getTitle(), "The Lord of the Rings"); + } + + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EventLiveTest.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EventLiveTest.java new file mode 100644 index 0000000000..2c6bc72da6 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/EventLiveTest.java @@ -0,0 +1,64 @@ +package com.baeldung.uuid; + +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.uuid.config.EventMongoConfig; +import com.baeldung.uuid.model.Book; +import com.baeldung.uuid.repository.BookRepository; + +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = EventMongoConfig.class) +public class EventLiveTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private MongoOperations mongoOps; + + @Before + public void testSetup() { + if (!mongoOps.collectionExists(Book.class)) { + mongoOps.createCollection(Book.class); + } + } + + @After + public void tearDown() { + mongoOps.dropCollection(Book.class); + } + + @Test + public void whenSavingArticle_thenArticleIsInserted() { + final Book book = new Book(); + book.setTitle("The Lord of the Rings"); + book.setAuthor("JRR Tolkien"); + + Book savedArticle = bookRepository.save(book); + + Book result = mongoOps.findOne(Query.query(Criteria.where("_id").is(savedArticle.getId())), Book.class); + + assertNotNull(result); + assertEquals(result.getTitle(), "The Lord of the Rings"); + } + + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/CustomRepositoryMongoConfig.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/CustomRepositoryMongoConfig.java new file mode 100644 index 0000000000..833a407ae2 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/CustomRepositoryMongoConfig.java @@ -0,0 +1,32 @@ +package com.baeldung.uuid.config; + +import org.bson.UuidRepresentation; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +import com.baeldung.uuid.repository.impl.CustomMongoRepositoryImpl; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +@Configuration +@EnableMongoRepositories(basePackages = "com.baeldung.uuid.repository", repositoryBaseClass = CustomMongoRepositoryImpl.class) +public class CustomRepositoryMongoConfig { + + @Bean + public MongoClient mongo() throws Exception { + final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test"); + final MongoClientSettings mongoClientSettings = MongoClientSettings.builder() + .uuidRepresentation(UuidRepresentation.STANDARD) + .applyConnectionString(connectionString).build(); + return MongoClients.create(mongoClientSettings); + } + + @Bean + public MongoTemplate mongoTemplate() throws Exception { + return new MongoTemplate(mongo(), "test"); + } +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EntityCallbackMongoConfig.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EntityCallbackMongoConfig.java new file mode 100644 index 0000000000..baf69dd5e8 --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EntityCallbackMongoConfig.java @@ -0,0 +1,48 @@ +package com.baeldung.uuid.config; + +import java.util.UUID; + +import org.bson.UuidRepresentation; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +import com.baeldung.uuid.model.UuidIdentifiedEntity; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +@Configuration +@EnableMongoRepositories(basePackages = "com.baeldung.uuid.repository") +public class EntityCallbackMongoConfig { + + @Bean + public MongoClient mongo() throws Exception { + final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test"); + final MongoClientSettings mongoClientSettings = MongoClientSettings.builder() + .uuidRepresentation(UuidRepresentation.STANDARD) + .applyConnectionString(connectionString).build(); + return MongoClients.create(mongoClientSettings); + } + + @Bean + public MongoTemplate mongoTemplate() throws Exception { + return new MongoTemplate(mongo(), "test"); + } + + @Bean + public BeforeConvertCallback beforeSaveCallback() { + + return (entity, collection) -> { + + if(entity.getId() == null) { + entity.setId(UUID.randomUUID()); + } + return entity; + }; + } + +} diff --git a/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EventMongoConfig.java b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EventMongoConfig.java new file mode 100644 index 0000000000..d26281dd4a --- /dev/null +++ b/persistence-modules/spring-data-mongodb-2/src/test/java/com/baeldung/uuid/config/EventMongoConfig.java @@ -0,0 +1,38 @@ +package com.baeldung.uuid.config; + +import org.bson.UuidRepresentation; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +import com.baeldung.uuid.event.UuidIdentifiedEntityEventListener; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +@Configuration +@EnableMongoRepositories(basePackages = "com.baeldung.uuid.repository") +public class EventMongoConfig { + + @Bean + public MongoClient mongo() throws Exception { + final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test"); + final MongoClientSettings mongoClientSettings = MongoClientSettings.builder() + .uuidRepresentation(UuidRepresentation.STANDARD) + .applyConnectionString(connectionString).build(); + return MongoClients.create(mongoClientSettings); + } + + @Bean + public MongoTemplate mongoTemplate() throws Exception { + return new MongoTemplate(mongo(), "test"); + } + + @Bean + public UuidIdentifiedEntityEventListener uuidIdentifiedEntityEventListener() { + + return new UuidIdentifiedEntityEventListener(); + } +}