From 28cdc0ddc0f259ae00b1657b9251a0f029d33087 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Fri, 27 May 2022 23:55:58 -0300 Subject: [PATCH 01/34] BAEL-5370 - MongoDB Composite Key First Draft. --- .../SpringBootCompositeKeyApplication.java | 15 ++ .../composite/key/dao/CustomerRepository.java | 12 ++ .../composite/key/dao/SaleRepository.java | 12 ++ .../composite/key/dao/TicketRepository.java | 10 ++ .../boot/composite/key/data/Customer.java | 49 ++++++ .../boot/composite/key/data/Sale.java | 38 +++++ .../boot/composite/key/data/Ticket.java | 31 ++++ .../boot/composite/key/data/TicketId.java | 56 +++++++ .../key/service/CustomerService.java | 66 +++++++++ .../composite/key/web/CustomerController.java | 88 +++++++++++ .../boot.composite.key/app.properties | 1 + .../key/CustomerServiceIntegrationTest.java | 140 ++++++++++++++++++ 12 files changed, 518 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java new file mode 100644 index 0000000000..e9f8eab1dd --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.boot.composite.key; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +@PropertySource("classpath:boot.composite.key/app.properties") +@EnableMongoRepositories(basePackages = { "com.baeldung.boot.composite.key" }) +public class SpringBootCompositeKeyApplication { + public static void main(String... args) { + SpringApplication.run(SpringBootCompositeKeyApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java new file mode 100644 index 0000000000..6953a21ddd --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.composite.key.dao; + +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.composite.key.data.Customer; + +public interface CustomerRepository extends MongoRepository { + + Optional findByStoreIdAndNumber(Long storeId, Long number); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java new file mode 100644 index 0000000000..3caa33d465 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.composite.key.dao; + +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.composite.key.data.Sale; +import com.baeldung.boot.composite.key.data.TicketId; + +public interface SaleRepository extends MongoRepository { + Optional findByTicketId(TicketId ticketId); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java new file mode 100644 index 0000000000..b02ea461d2 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.boot.composite.key.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; + +public interface TicketRepository extends MongoRepository { + +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java new file mode 100644 index 0000000000..d4bb1ef40c --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java @@ -0,0 +1,49 @@ +package com.baeldung.boot.composite.key.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@CompoundIndex(name = "customer_idx", def = "{ 'storeId': 1, 'number': 1 }", unique = true) +public class Customer { + @Id + private String id; + + private Long storeId; + private Long number; + + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java new file mode 100644 index 0000000000..a81c91674c --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java @@ -0,0 +1,38 @@ +package com.baeldung.boot.composite.key.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@CompoundIndex(name = "sale_idx", def = "{ 'ticketId': 1 }", unique = true) +public class Sale { + @Id + private String id; + + private TicketId ticketId; + private Double value; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public TicketId getTicketId() { + return ticketId; + } + + public void setTicketId(TicketId ticketId) { + this.ticketId = ticketId; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java new file mode 100644 index 0000000000..7a8ebe1ab3 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java @@ -0,0 +1,31 @@ +package com.baeldung.boot.composite.key.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Ticket { + @Id + private TicketId id; + + private String event; + + public Ticket() { + } + + public TicketId getId() { + return id; + } + + public void setId(TicketId id) { + this.id = id; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java new file mode 100644 index 0000000000..76fbf81391 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java @@ -0,0 +1,56 @@ +package com.baeldung.boot.composite.key.data; + +public class TicketId { + private String venue; + private String date; + + public TicketId() { + } + + public String getVenue() { + return venue; + } + + public void setVenue(String venue) { + this.venue = venue; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((date == null) ? 0 : date.hashCode()); + result = prime * result + ((venue == null) ? 0 : venue.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TicketId other = (TicketId) obj; + if (date == null) { + if (other.date != null) + return false; + } else if (!date.equals(other.date)) + return false; + if (venue == null) { + if (other.venue != null) + return false; + } else if (!venue.equals(other.venue)) + return false; + return true; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java new file mode 100644 index 0000000000..476209bce9 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java @@ -0,0 +1,66 @@ +package com.baeldung.boot.composite.key.service; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.composite.key.dao.CustomerRepository; +import com.baeldung.boot.composite.key.dao.SaleRepository; +import com.baeldung.boot.composite.key.dao.TicketRepository; +import com.baeldung.boot.composite.key.data.Customer; +import com.baeldung.boot.composite.key.data.Sale; +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; + +@Service +public class CustomerService { + @Autowired + private CustomerRepository customerRepository; + + @Autowired + private TicketRepository ticketRepository; + + @Autowired + private SaleRepository saleRepository; + + public Optional find(TicketId id) { + return ticketRepository.findById(id); + } + + public Ticket insert(Ticket ticket) { + return ticketRepository.insert(ticket); + } + + public Ticket save(Ticket ticket) { + return ticketRepository.save(ticket); + } + + public Optional findCustomerById(String id) { + return customerRepository.findById(id); + } + + public Optional findCustomerByIndex(Long storeId, Long number) { + return customerRepository.findByStoreIdAndNumber(storeId, number); + } + + public Customer insert(Customer customer) { + return customerRepository.insert(customer); + } + + public Customer save(Customer customer) { + return customerRepository.save(customer); + } + + public Sale insert(Sale sale) { + return saleRepository.insert(sale); + } + + public Optional findSaleByTicketId(TicketId ticketId) { + return saleRepository.findByTicketId(ticketId); + } + + public Optional findSaleById(String id) { + return saleRepository.findById(id); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java new file mode 100644 index 0000000000..83afe0ae42 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java @@ -0,0 +1,88 @@ +package com.baeldung.boot.composite.key.web; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.composite.key.data.Customer; +import com.baeldung.boot.composite.key.data.Sale; +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; +import com.baeldung.boot.composite.key.service.CustomerService; + +@RestController +@RequestMapping("/customer") +public class CustomerController { + @Autowired + private CustomerService customerService; + + // @Autowired + // private TicketRepository ticketRepository; + // + // @GetMapping("/ticket") + // public Optional getTicket(TicketId id) { + // return ticketRepository.findById(id); + // } + // + // @PostMapping("/ticket") + // public Ticket postTicket(@RequestBody Ticket ticket) { + // return ticketRepository.insert(ticket); + // } + + @GetMapping("/ticket") + public Optional getTicket(TicketId id) { + return customerService.find(id); + } + + @PostMapping("/ticket") + public Ticket postTicket(@RequestBody Ticket ticket) { + return customerService.insert(ticket); + } + + @PutMapping("/ticket") + public Ticket putTicket(@RequestBody Ticket ticket) { + return customerService.save(ticket); + } + + @GetMapping("/{id}") + public Optional getCustomer(@PathVariable String id) { + return customerService.findCustomerById(id); + } + + @GetMapping("/{storeId}/{number}") + public Optional getCustomerByIndex(@PathVariable Long storeId, @PathVariable Long number) { + return customerService.findCustomerByIndex(storeId, number); + } + + @PostMapping + public Customer postCustomer(@RequestBody Customer customer) { + return customerService.insert(customer); + } + + @PutMapping + public Customer putCustomer(@RequestBody Customer customer) { + return customerService.save(customer); + } + + @PostMapping("/sale") + public Sale postSale(@RequestBody Sale sale) { + return customerService.insert(sale); + } + + @GetMapping("/sale/{id}") + public Optional getSale(@PathVariable String id) { + return customerService.findSaleById(id); + } + + @GetMapping("/sale") + public Optional getSale(TicketId ticketId) { + return customerService.findSaleByTicketId(ticketId); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties new file mode 100644 index 0000000000..a73a94d850 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties @@ -0,0 +1 @@ +spring.data.mongodb.auto-index-creation=true diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java new file mode 100644 index 0000000000..4f779ebf02 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java @@ -0,0 +1,140 @@ +package com.baeldung.boot.composite.key; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.util.Optional; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.composite.key.data.Customer; +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; +import com.baeldung.boot.composite.key.service.CustomerService; + +@SpringBootTest +@DirtiesContext +@RunWith(SpringRunner.class) +public class CustomerServiceIntegrationTest { + @Autowired + private CustomerService service; + + private static Ticket ticket; + private static TicketId ticketId; + + @BeforeClass + public static void setup() { + ticket = new Ticket(); + ticket.setEvent("Event A"); + + ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue A"); + ticket.setId(ticketId); + } + + @Test + public void givenCompositeId_whenObjectSaved_thenIdMatches() { + Ticket savedTicket = service.insert(ticket); + assertEquals(savedTicket.getId(), ticket.getId()); + } + + @Test + public void givenCompositeId_whenSearchingByIdObject_thenFound() { + Optional optionalTicket = service.find(ticketId); + + assertThat(optionalTicket.isPresent()); + Ticket savedTicket = optionalTicket.get(); + + assertEquals(savedTicket.getId(), ticketId); + } + + @Test + public void givenCompoundUniqueIndex_whenSearchingByGeneratedId_thenFound() { + Customer customer = new Customer(); + customer.setName("Name"); + customer.setNumber(0l); + customer.setStoreId(0l); + + Customer savedCustomer = service.insert(customer); + + Optional optional = service.findCustomerById(savedCustomer.getId()); + + assertThat(optional.isPresent()); + } + + @Test + public void givenCompositeId_whenDupeInsert_thenExceptionIsThrown() { + Ticket ticket = new Ticket(); + ticket.setEvent("C"); + + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("V"); + ticket.setId(ticketId); + + assertThrows(DuplicateKeyException.class, () -> { + service.insert(ticket); + service.insert(ticket); + }); + } + + @Test + public void givenCompositeId_whenDupeSave_thenObjectUpdated() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue"); + + Ticket ticketA = new Ticket(); + ticketA.setEvent("A"); + ticketA.setId(ticketId); + + service.save(ticketA); + + Ticket ticketB = new Ticket(); + ticketB.setEvent("B"); + ticketB.setId(ticketId); + + Ticket savedTicket = service.save(ticketB); + assertEquals(savedTicket.getEvent(), ticketB.getEvent()); + } + + @Test + public void givenCompoundUniqueIndex_whenDupeInsert_thenExceptionIsThrown() { + Customer customer = new Customer(); + customer.setName("Name"); + customer.setNumber(1l); + customer.setStoreId(2l); + + assertThrows(DuplicateKeyException.class, () -> { + service.insert(customer); + service.insert(customer); + }); + } + + @Test + public void givenCompoundUniqueIndex_whenDupeSave_thenExceptionIsThrown() { + Customer customerA = new Customer(); + customerA.setName("Name A"); + customerA.setNumber(1l); + customerA.setStoreId(2l); + + Customer customerB = new Customer(); + customerB.setName("Name B"); + customerB.setNumber(1l); + customerB.setStoreId(2l); + + assertThrows(DuplicateKeyException.class, () -> { + service.save(customerA); + service.save(customerB); + }); + } +} From 0260f6373e8e148ab32a5ac93239b4258f092ce7 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Fri, 27 May 2022 23:57:12 -0300 Subject: [PATCH 02/34] removing comments --- .../boot/composite/key/web/CustomerController.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java index 83afe0ae42..9e41d13e14 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java @@ -23,19 +23,6 @@ public class CustomerController { @Autowired private CustomerService customerService; - // @Autowired - // private TicketRepository ticketRepository; - // - // @GetMapping("/ticket") - // public Optional getTicket(TicketId id) { - // return ticketRepository.findById(id); - // } - // - // @PostMapping("/ticket") - // public Ticket postTicket(@RequestBody Ticket ticket) { - // return ticketRepository.insert(ticket); - // } - @GetMapping("/ticket") public Optional getTicket(TicketId id) { return customerService.find(id); From 8a75af488ba08fa1e7a4e2fc663ac3d7309c7f3a Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Fri, 3 Jun 2022 10:06:51 -0300 Subject: [PATCH 03/34] BAEL-5370 Test could fail if ran in a different order: givenCompositeId_whenSearchingByIdObject_thenFound --- .../boot/composite/key/data/Ticket.java | 6 +++ .../key/CustomerServiceIntegrationTest.java | 44 +++++++------------ 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java index 7a8ebe1ab3..d77b54c513 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java @@ -13,6 +13,12 @@ public class Ticket { public Ticket() { } + public Ticket(TicketId id, String event) { + super(); + this.id = id; + this.event = event; + } + public TicketId getId() { return id; } diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java index 4f779ebf02..658be343f1 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertThrows; import java.util.Optional; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,28 +26,26 @@ public class CustomerServiceIntegrationTest { @Autowired private CustomerService service; - private static Ticket ticket; - private static TicketId ticketId; - - @BeforeClass - public static void setup() { - ticket = new Ticket(); - ticket.setEvent("Event A"); - - ticketId = new TicketId(); - ticketId.setDate("2020-01-01"); - ticketId.setVenue("Venue A"); - ticket.setId(ticketId); - } - @Test public void givenCompositeId_whenObjectSaved_thenIdMatches() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue A"); + + Ticket ticket = new Ticket(ticketId, "Event A"); Ticket savedTicket = service.insert(ticket); + assertEquals(savedTicket.getId(), ticket.getId()); } @Test public void givenCompositeId_whenSearchingByIdObject_thenFound() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue B"); + + service.insert(new Ticket(ticketId, "Event B")); + Optional optionalTicket = service.find(ticketId); assertThat(optionalTicket.isPresent()); @@ -73,13 +70,11 @@ public class CustomerServiceIntegrationTest { @Test public void givenCompositeId_whenDupeInsert_thenExceptionIsThrown() { - Ticket ticket = new Ticket(); - ticket.setEvent("C"); - TicketId ticketId = new TicketId(); ticketId.setDate("2020-01-01"); ticketId.setVenue("V"); - ticket.setId(ticketId); + + Ticket ticket = new Ticket(ticketId, "Event C"); assertThrows(DuplicateKeyException.class, () -> { service.insert(ticket); @@ -93,17 +88,12 @@ public class CustomerServiceIntegrationTest { ticketId.setDate("2020-01-01"); ticketId.setVenue("Venue"); - Ticket ticketA = new Ticket(); - ticketA.setEvent("A"); - ticketA.setId(ticketId); - + Ticket ticketA = new Ticket(ticketId, "A"); service.save(ticketA); - Ticket ticketB = new Ticket(); - ticketB.setEvent("B"); - ticketB.setId(ticketId); - + Ticket ticketB = new Ticket(ticketId, "B"); Ticket savedTicket = service.save(ticketB); + assertEquals(savedTicket.getEvent(), ticketB.getEvent()); } From 793ada0100c3974cba0eca0e3674cdb36de51ace Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Mon, 13 Jun 2022 23:37:28 -0300 Subject: [PATCH 04/34] BAEL-5370 removing compound index related stuff --- .../SpringBootCompositeKeyApplication.java | 2 - .../composite/key/dao/CustomerRepository.java | 12 ----- .../composite/key/dao/SaleRepository.java | 12 ----- .../boot/composite/key/data/Customer.java | 49 ------------------- .../boot/composite/key/data/Sale.java | 38 -------------- .../key/service/CustomerService.java | 38 -------------- .../composite/key/web/CustomerController.java | 38 -------------- .../boot.composite.key/app.properties | 1 - .../key/CustomerServiceIntegrationTest.java | 46 ----------------- 9 files changed, 236 deletions(-) delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java index e9f8eab1dd..1322adbf77 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java @@ -2,11 +2,9 @@ package com.baeldung.boot.composite.key; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.PropertySource; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @SpringBootApplication -@PropertySource("classpath:boot.composite.key/app.properties") @EnableMongoRepositories(basePackages = { "com.baeldung.boot.composite.key" }) public class SpringBootCompositeKeyApplication { public static void main(String... args) { diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java deleted file mode 100644 index 6953a21ddd..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/CustomerRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.boot.composite.key.dao; - -import java.util.Optional; - -import org.springframework.data.mongodb.repository.MongoRepository; - -import com.baeldung.boot.composite.key.data.Customer; - -public interface CustomerRepository extends MongoRepository { - - Optional findByStoreIdAndNumber(Long storeId, Long number); -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java deleted file mode 100644 index 3caa33d465..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/SaleRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.boot.composite.key.dao; - -import java.util.Optional; - -import org.springframework.data.mongodb.repository.MongoRepository; - -import com.baeldung.boot.composite.key.data.Sale; -import com.baeldung.boot.composite.key.data.TicketId; - -public interface SaleRepository extends MongoRepository { - Optional findByTicketId(TicketId ticketId); -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java deleted file mode 100644 index d4bb1ef40c..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Customer.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.boot.composite.key.data; - -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.CompoundIndex; -import org.springframework.data.mongodb.core.mapping.Document; - -@Document -@CompoundIndex(name = "customer_idx", def = "{ 'storeId': 1, 'number': 1 }", unique = true) -public class Customer { - @Id - private String id; - - private Long storeId; - private Long number; - - private String name; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Long getStoreId() { - return storeId; - } - - public void setStoreId(Long storeId) { - this.storeId = storeId; - } - - public Long getNumber() { - return number; - } - - public void setNumber(Long number) { - this.number = number; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java deleted file mode 100644 index a81c91674c..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Sale.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.baeldung.boot.composite.key.data; - -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.CompoundIndex; -import org.springframework.data.mongodb.core.mapping.Document; - -@Document -@CompoundIndex(name = "sale_idx", def = "{ 'ticketId': 1 }", unique = true) -public class Sale { - @Id - private String id; - - private TicketId ticketId; - private Double value; - - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } - - public TicketId getTicketId() { - return ticketId; - } - - public void setTicketId(TicketId ticketId) { - this.ticketId = ticketId; - } - - public Double getValue() { - return value; - } - - public void setValue(Double value) { - this.value = value; - } -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java index 476209bce9..90ca1b758d 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java @@ -5,25 +5,15 @@ import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import com.baeldung.boot.composite.key.dao.CustomerRepository; -import com.baeldung.boot.composite.key.dao.SaleRepository; import com.baeldung.boot.composite.key.dao.TicketRepository; -import com.baeldung.boot.composite.key.data.Customer; -import com.baeldung.boot.composite.key.data.Sale; import com.baeldung.boot.composite.key.data.Ticket; import com.baeldung.boot.composite.key.data.TicketId; @Service public class CustomerService { - @Autowired - private CustomerRepository customerRepository; - @Autowired private TicketRepository ticketRepository; - @Autowired - private SaleRepository saleRepository; - public Optional find(TicketId id) { return ticketRepository.findById(id); } @@ -35,32 +25,4 @@ public class CustomerService { public Ticket save(Ticket ticket) { return ticketRepository.save(ticket); } - - public Optional findCustomerById(String id) { - return customerRepository.findById(id); - } - - public Optional findCustomerByIndex(Long storeId, Long number) { - return customerRepository.findByStoreIdAndNumber(storeId, number); - } - - public Customer insert(Customer customer) { - return customerRepository.insert(customer); - } - - public Customer save(Customer customer) { - return customerRepository.save(customer); - } - - public Sale insert(Sale sale) { - return saleRepository.insert(sale); - } - - public Optional findSaleByTicketId(TicketId ticketId) { - return saleRepository.findByTicketId(ticketId); - } - - public Optional findSaleById(String id) { - return saleRepository.findById(id); - } } diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java index 9e41d13e14..4379a46d05 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java @@ -4,15 +4,12 @@ import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.baeldung.boot.composite.key.data.Customer; -import com.baeldung.boot.composite.key.data.Sale; import com.baeldung.boot.composite.key.data.Ticket; import com.baeldung.boot.composite.key.data.TicketId; import com.baeldung.boot.composite.key.service.CustomerService; @@ -37,39 +34,4 @@ public class CustomerController { public Ticket putTicket(@RequestBody Ticket ticket) { return customerService.save(ticket); } - - @GetMapping("/{id}") - public Optional getCustomer(@PathVariable String id) { - return customerService.findCustomerById(id); - } - - @GetMapping("/{storeId}/{number}") - public Optional getCustomerByIndex(@PathVariable Long storeId, @PathVariable Long number) { - return customerService.findCustomerByIndex(storeId, number); - } - - @PostMapping - public Customer postCustomer(@RequestBody Customer customer) { - return customerService.insert(customer); - } - - @PutMapping - public Customer putCustomer(@RequestBody Customer customer) { - return customerService.save(customer); - } - - @PostMapping("/sale") - public Sale postSale(@RequestBody Sale sale) { - return customerService.insert(sale); - } - - @GetMapping("/sale/{id}") - public Optional getSale(@PathVariable String id) { - return customerService.findSaleById(id); - } - - @GetMapping("/sale") - public Optional getSale(TicketId ticketId) { - return customerService.findSaleByTicketId(ticketId); - } } diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties deleted file mode 100644 index a73a94d850..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.composite.key/app.properties +++ /dev/null @@ -1 +0,0 @@ -spring.data.mongodb.auto-index-creation=true diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java index 658be343f1..1aee478ad0 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java @@ -14,7 +14,6 @@ import org.springframework.dao.DuplicateKeyException; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.boot.composite.key.data.Customer; import com.baeldung.boot.composite.key.data.Ticket; import com.baeldung.boot.composite.key.data.TicketId; import com.baeldung.boot.composite.key.service.CustomerService; @@ -54,20 +53,6 @@ public class CustomerServiceIntegrationTest { assertEquals(savedTicket.getId(), ticketId); } - @Test - public void givenCompoundUniqueIndex_whenSearchingByGeneratedId_thenFound() { - Customer customer = new Customer(); - customer.setName("Name"); - customer.setNumber(0l); - customer.setStoreId(0l); - - Customer savedCustomer = service.insert(customer); - - Optional optional = service.findCustomerById(savedCustomer.getId()); - - assertThat(optional.isPresent()); - } - @Test public void givenCompositeId_whenDupeInsert_thenExceptionIsThrown() { TicketId ticketId = new TicketId(); @@ -96,35 +81,4 @@ public class CustomerServiceIntegrationTest { assertEquals(savedTicket.getEvent(), ticketB.getEvent()); } - - @Test - public void givenCompoundUniqueIndex_whenDupeInsert_thenExceptionIsThrown() { - Customer customer = new Customer(); - customer.setName("Name"); - customer.setNumber(1l); - customer.setStoreId(2l); - - assertThrows(DuplicateKeyException.class, () -> { - service.insert(customer); - service.insert(customer); - }); - } - - @Test - public void givenCompoundUniqueIndex_whenDupeSave_thenExceptionIsThrown() { - Customer customerA = new Customer(); - customerA.setName("Name A"); - customerA.setNumber(1l); - customerA.setStoreId(2l); - - Customer customerB = new Customer(); - customerB.setName("Name B"); - customerB.setNumber(1l); - customerB.setStoreId(2l); - - assertThrows(DuplicateKeyException.class, () -> { - service.save(customerA); - service.save(customerB); - }); - } } From f1259c2a4d717dc2e3c16f26eb6cae1c065d70b0 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Fri, 17 Jun 2022 12:01:44 -0300 Subject: [PATCH 05/34] removing first insert from assertThrows --- .../boot/composite/key/CustomerServiceIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java index 1aee478ad0..af310ab29e 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java @@ -60,10 +60,10 @@ public class CustomerServiceIntegrationTest { ticketId.setVenue("V"); Ticket ticket = new Ticket(ticketId, "Event C"); + service.insert(ticket); assertThrows(DuplicateKeyException.class, () -> { service.insert(ticket); - service.insert(ticket); }); } From e0a7591f9defa207018816003a8b99e192a9b5fe Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Sun, 19 Jun 2022 16:32:10 -0300 Subject: [PATCH 06/34] first draft --- .../SpringBootUniqueFieldApplication.java | 15 +++ .../unique/field/dao/AssetRepository.java | 8 ++ .../unique/field/dao/CompanyRepository.java | 11 ++ .../unique/field/dao/Customer2Repository.java | 8 ++ .../unique/field/dao/CustomerRepository.java | 11 ++ .../boot/unique/field/dao/SaleRepository.java | 12 ++ .../boot/unique/field/data/Asset.java | 29 +++++ .../boot/unique/field/data/Company.java | 40 +++++++ .../boot/unique/field/data/Customer.java | 57 +++++++++ .../boot/unique/field/data/Customer2.java | 47 ++++++++ .../baeldung/boot/unique/field/data/Sale.java | 36 ++++++ .../boot/unique/field/data/SaleId.java | 22 ++++ .../field/web/UniqueFieldController.java | 93 +++++++++++++++ .../boot.unique.field/app.properties | 1 + .../field/UniqueFieldIntegrationTest.java | 112 ++++++++++++++++++ 15 files changed, 502 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/SpringBootUniqueFieldApplication.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/AssetRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CompanyRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CustomerRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/SaleRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Asset.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Company.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Sale.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/SaleId.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.unique.field/app.properties create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/unique/field/UniqueFieldIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/SpringBootUniqueFieldApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/SpringBootUniqueFieldApplication.java new file mode 100644 index 0000000000..648ecd4dfb --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/SpringBootUniqueFieldApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.boot.unique.field; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +@PropertySource("classpath:boot.unique.field/app.properties") +@EnableMongoRepositories(basePackages = { "com.baeldung.boot.unique.field" }) +public class SpringBootUniqueFieldApplication { + public static void main(String... args) { + SpringApplication.run(SpringBootUniqueFieldApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/AssetRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/AssetRepository.java new file mode 100644 index 0000000000..9adca8b4bd --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/AssetRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.boot.unique.field.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.unique.field.data.Asset; + +public interface AssetRepository extends MongoRepository { +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CompanyRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CompanyRepository.java new file mode 100644 index 0000000000..718e284efe --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CompanyRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.boot.unique.field.dao; + +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.unique.field.data.Company; + +public interface CompanyRepository extends MongoRepository { + Optional findByEmail(String email); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java new file mode 100644 index 0000000000..6afe004609 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java @@ -0,0 +1,8 @@ +package com.baeldung.boot.unique.field.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.unique.field.data.Customer2; + +public interface Customer2Repository extends MongoRepository { +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CustomerRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CustomerRepository.java new file mode 100644 index 0000000000..f6e5b54470 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/CustomerRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.boot.unique.field.dao; + +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.unique.field.data.Customer; + +public interface CustomerRepository extends MongoRepository { + Optional findByStoreIdAndNumber(Long storeId, Long number); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/SaleRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/SaleRepository.java new file mode 100644 index 0000000000..8547a5ab76 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/SaleRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.unique.field.dao; + +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.unique.field.data.Sale; +import com.baeldung.boot.unique.field.data.SaleId; + +public interface SaleRepository extends MongoRepository { + Optional findBySaleId(SaleId id); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Asset.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Asset.java new file mode 100644 index 0000000000..9652691a8b --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Asset.java @@ -0,0 +1,29 @@ +package com.baeldung.boot.unique.field.data; + +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Asset { + @Indexed(unique = true) + private String name; + + @Indexed(unique = true) + private Integer number; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Company.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Company.java new file mode 100644 index 0000000000..31b4cf0588 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Company.java @@ -0,0 +1,40 @@ +package com.baeldung.boot.unique.field.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Company { + @Id + private String id; + + private String name; + + @Indexed(unique = true) + private String email; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer.java new file mode 100644 index 0000000000..d1459dc663 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer.java @@ -0,0 +1,57 @@ +package com.baeldung.boot.unique.field.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@CompoundIndex(name = "customer_idx", def = "{ 'storeId': 1, 'number': 1 }", unique = true) +public class Customer { + @Id + private String id; + + private Long storeId; + + private Long number; + + private String name; + + public Customer() { + } + + public Customer(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java new file mode 100644 index 0000000000..523a0a9841 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java @@ -0,0 +1,47 @@ +package com.baeldung.boot.unique.field.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@CompoundIndex(def = "{ 'storeId': 1, 'number': 1 }", unique = true) +public class Customer2 { + @Id + private Long storeId; + + private Long number; + + private String name; + + public Customer2() { + } + + public Customer2(String name) { + this.name = name; + } + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Sale.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Sale.java new file mode 100644 index 0000000000..3d0a549575 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Sale.java @@ -0,0 +1,36 @@ +package com.baeldung.boot.unique.field.data; + +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Sale { + @Indexed(unique = true) + private SaleId saleId; + + private Double value; + + public Sale() { + } + + public Sale(SaleId saleId) { + super(); + this.saleId = saleId; + } + + public SaleId getSaleId() { + return saleId; + } + + public void setSaleId(SaleId saleId) { + this.saleId = saleId; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/SaleId.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/SaleId.java new file mode 100644 index 0000000000..69a5c5a561 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/SaleId.java @@ -0,0 +1,22 @@ +package com.baeldung.boot.unique.field.data; + +public class SaleId { + private Long item; + private String date; + + public Long getItem() { + return item; + } + + public void setItem(Long item) { + this.item = item; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java new file mode 100644 index 0000000000..8ac00c497f --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java @@ -0,0 +1,93 @@ +package com.baeldung.boot.unique.field.web; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.unique.field.dao.AssetRepository; +import com.baeldung.boot.unique.field.dao.CompanyRepository; +import com.baeldung.boot.unique.field.dao.Customer2Repository; +import com.baeldung.boot.unique.field.dao.CustomerRepository; +import com.baeldung.boot.unique.field.dao.SaleRepository; +import com.baeldung.boot.unique.field.data.Asset; +import com.baeldung.boot.unique.field.data.Company; +import com.baeldung.boot.unique.field.data.Customer; +import com.baeldung.boot.unique.field.data.Customer2; +import com.baeldung.boot.unique.field.data.Sale; +import com.baeldung.boot.unique.field.data.SaleId; + +@RestController +@RequestMapping("/unique-field") +public class UniqueFieldController { + @Autowired + private SaleRepository saleRepo; + + @Autowired + private CompanyRepository companyRepo; + + @Autowired + private CustomerRepository customerRepo; + + @Autowired + private Customer2Repository customer2Repo; + + @Autowired + private AssetRepository assetRepo; + + @PostMapping("/sale") + public Sale post(@RequestBody Sale sale) { + return saleRepo.insert(sale); + } + + @GetMapping("/sale") + public Optional getSale(SaleId id) { + return saleRepo.findBySaleId(id); + } + + @PostMapping("/company") + public Company post(@RequestBody Company company) { + return companyRepo.insert(company); + } + + @PutMapping("/company") + public Company put(@RequestBody Company company) { + return companyRepo.save(company); + } + + @GetMapping("/company/{id}") + public Optional getCompany(@PathVariable String id) { + return companyRepo.findById(id); + } + + @PostMapping("/customer") + public Customer post(@RequestBody Customer customer) { + return customerRepo.insert(customer); + } + + @PostMapping("/customer2") + public Customer2 post(@RequestBody Customer2 customer) { + return customer2Repo.insert(customer); + } + + @GetMapping("/customer/{id}") + public Optional getCustomer(@PathVariable String id) { + return customerRepo.findById(id); + } + + @PostMapping("/asset") + public Asset post(@RequestBody Asset asset) { + return assetRepo.insert(asset); + } + + @GetMapping("/asset/{id}") + public Optional getAsset(@PathVariable String id) { + return assetRepo.findById(id); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.unique.field/app.properties b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.unique.field/app.properties new file mode 100644 index 0000000000..a73a94d850 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/resources/boot.unique.field/app.properties @@ -0,0 +1 @@ +spring.data.mongodb.auto-index-creation=true diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/unique/field/UniqueFieldIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/unique/field/UniqueFieldIntegrationTest.java new file mode 100644 index 0000000000..c18a877b79 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/unique/field/UniqueFieldIntegrationTest.java @@ -0,0 +1,112 @@ +package com.baeldung.boot.unique.field; + +import static org.junit.Assert.assertThrows; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.unique.field.dao.AssetRepository; +import com.baeldung.boot.unique.field.dao.CompanyRepository; +import com.baeldung.boot.unique.field.dao.CustomerRepository; +import com.baeldung.boot.unique.field.dao.SaleRepository; +import com.baeldung.boot.unique.field.data.Asset; +import com.baeldung.boot.unique.field.data.Company; +import com.baeldung.boot.unique.field.data.Customer; +import com.baeldung.boot.unique.field.data.Sale; +import com.baeldung.boot.unique.field.data.SaleId; + +@SpringBootTest +@DirtiesContext +@RunWith(SpringRunner.class) +public class UniqueFieldIntegrationTest { + @Autowired + private SaleRepository saleRepo; + + @Autowired + private CompanyRepository companyRepo; + + @Autowired + private CustomerRepository customerRepo; + + @Autowired + private AssetRepository assetRepo; + + @Test + public void givenMultipleIndexes_whenAnyFieldDupe_thenExceptionIsThrown() { + Asset a = new Asset(); + a.setName("Name"); + a.setNumber(1); + + assetRepo.insert(a); + + Asset b = new Asset(); + b.setName("Name"); + b.setNumber(2); + assertThrows(DuplicateKeyException.class, () -> { + assetRepo.insert(b); + }); + + Asset c = new Asset(); + c.setName("Other"); + c.setNumber(1); + assertThrows(DuplicateKeyException.class, () -> { + assetRepo.insert(c); + }); + } + + @Test + public void givenUniqueIndex_whenInsertingDupe_thenExceptionIsThrown() { + Company a = new Company(); + a.setName("Name"); + a.setEmail("a@mail.com"); + + companyRepo.insert(a); + + Company b = new Company(); + b.setName("Other"); + b.setEmail("a@mail.com"); + assertThrows(DuplicateKeyException.class, () -> { + companyRepo.insert(b); + }); + } + + @Test + public void givenCompoundIndex_whenDupeInsert_thenExceptionIsThrown() { + Customer customerA = new Customer("Name A"); + customerA.setNumber(1l); + customerA.setStoreId(2l); + + Customer customerB = new Customer("Name B"); + customerB.setNumber(1l); + customerB.setStoreId(2l); + + customerRepo.insert(customerA); + + assertThrows(DuplicateKeyException.class, () -> { + customerRepo.insert(customerB); + }); + } + + @Test + public void givenCustomTypeIndex_whenInsertingDupe_thenExceptionIsThrown() { + SaleId id = new SaleId(); + id.setDate("2022-06-15"); + id.setItem(1L); + + Sale a = new Sale(id); + a.setValue(53.94); + + saleRepo.insert(a); + + Sale b = new Sale(id); + b.setValue(100.00); + assertThrows(DuplicateKeyException.class, () -> { + saleRepo.insert(b); + }); + } +} From 3ae97db187f253b5773d120b89601e34b57e9630 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Sun, 19 Jun 2022 16:35:36 -0300 Subject: [PATCH 07/34] removing Customer2 --- .../unique/field/dao/Customer2Repository.java | 8 ---- .../boot/unique/field/data/Customer2.java | 47 ------------------- .../field/web/UniqueFieldController.java | 10 ---- 3 files changed, 65 deletions(-) delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java deleted file mode 100644 index 6afe004609..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/dao/Customer2Repository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.baeldung.boot.unique.field.dao; - -import org.springframework.data.mongodb.repository.MongoRepository; - -import com.baeldung.boot.unique.field.data.Customer2; - -public interface Customer2Repository extends MongoRepository { -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java deleted file mode 100644 index 523a0a9841..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/data/Customer2.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.boot.unique.field.data; - -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.CompoundIndex; -import org.springframework.data.mongodb.core.mapping.Document; - -@Document -@CompoundIndex(def = "{ 'storeId': 1, 'number': 1 }", unique = true) -public class Customer2 { - @Id - private Long storeId; - - private Long number; - - private String name; - - public Customer2() { - } - - public Customer2(String name) { - this.name = name; - } - - public Long getStoreId() { - return storeId; - } - - public void setStoreId(Long storeId) { - this.storeId = storeId; - } - - public Long getNumber() { - return number; - } - - public void setNumber(Long number) { - this.number = number; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java index 8ac00c497f..716977edd4 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/unique/field/web/UniqueFieldController.java @@ -13,13 +13,11 @@ import org.springframework.web.bind.annotation.RestController; import com.baeldung.boot.unique.field.dao.AssetRepository; import com.baeldung.boot.unique.field.dao.CompanyRepository; -import com.baeldung.boot.unique.field.dao.Customer2Repository; import com.baeldung.boot.unique.field.dao.CustomerRepository; import com.baeldung.boot.unique.field.dao.SaleRepository; import com.baeldung.boot.unique.field.data.Asset; import com.baeldung.boot.unique.field.data.Company; import com.baeldung.boot.unique.field.data.Customer; -import com.baeldung.boot.unique.field.data.Customer2; import com.baeldung.boot.unique.field.data.Sale; import com.baeldung.boot.unique.field.data.SaleId; @@ -35,9 +33,6 @@ public class UniqueFieldController { @Autowired private CustomerRepository customerRepo; - @Autowired - private Customer2Repository customer2Repo; - @Autowired private AssetRepository assetRepo; @@ -71,11 +66,6 @@ public class UniqueFieldController { return customerRepo.insert(customer); } - @PostMapping("/customer2") - public Customer2 post(@RequestBody Customer2 customer) { - return customer2Repo.insert(customer); - } - @GetMapping("/customer/{id}") public Optional getCustomer(@PathVariable String id) { return customerRepo.findById(id); From e5ad2b045b0cc081285e58913e3b0f8bead7cf6e Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Mon, 11 Jul 2022 16:39:59 -0300 Subject: [PATCH 08/34] first draft --- .../count/SpringBootCountApplication.java | 13 ++ .../boot/count/dao/CarRepository.java | 16 +++ .../com/baeldung/boot/count/data/Car.java | 32 +++++ .../boot/count/service/CountCarService.java | 69 ++++++++++ .../boot/count/web/CarController.java | 79 ++++++++++++ .../CountCarServiceIntegrationTest.java | 118 ++++++++++++++++++ 6 files changed, 327 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java new file mode 100644 index 0000000000..bb7351383c --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.boot.count; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +@EnableMongoRepositories(basePackages = { "com.baeldung.boot.count" }) +public class SpringBootCountApplication { + public static void main(String... args) { + SpringApplication.run(SpringBootCountApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java new file mode 100644 index 0000000000..b03298852e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.boot.count.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; + +import com.baeldung.boot.count.data.Car; + +public interface CarRepository extends MongoRepository { + @Query(value = "{brand: ?0}", count = true) + public long countBrand(String brand); + + Long countByBrand(String brand); + + @Query(value = "{}", count = true) + Long countWithAnnotation(); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java new file mode 100644 index 0000000000..55c26c1de4 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java @@ -0,0 +1,32 @@ +package com.baeldung.boot.count.data; + +import org.springframework.data.mongodb.core.mapping.Document; +@Document +public class Car { + private String name; + + private String brand; + + public Car() { + } + + public Car(String brand) { + this.brand = brand; + } + + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java new file mode 100644 index 0000000000..d4685847fb --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java @@ -0,0 +1,69 @@ +package com.baeldung.boot.count.service; + +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.count.dao.CarRepository; +import com.baeldung.boot.count.data.Car; + +@Service +public class CountCarService { + + @Autowired + private CarRepository repo; + + @Autowired + private MongoTemplate mongo; + + public List findCars() { + return repo.findAll(); + } + + public Optional findCar(String id) { + return repo.findById(id); + } + + public Car insertCar(Car item) { + return repo.insert(item); + } + + public long getCountWithQueryAnnotation() { + return repo.countWithAnnotation(); + } + + public long getCountWithCrudRepository() { + return repo.count(); + } + + public long getCountBrandWithQueryMethod(String brand) { + return repo.countByBrand(brand); + } + + public long getCountWithExample(Car item) { + return repo.count(Example.of(item)); + } + + public long getCountWithExampleCriteria(Car item) { + Query query = new Query(); + query.addCriteria(Criteria.byExample(item)); + return mongo.count(query, Car.class); + } + + public long getCountBrandWithQueryAnnotation(String brand) { + return repo.countBrand(brand); + } + + public long getCountBrandWithCriteria(String brand) { + Query query = new Query(); + query.addCriteria(Criteria.where("brand") + .is(brand)); + return mongo.count(query, Car.class); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java new file mode 100644 index 0000000000..bc5d6dff9d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java @@ -0,0 +1,79 @@ +package com.baeldung.boot.count.web; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.count.dao.CarRepository; +import com.baeldung.boot.count.data.Car; + +@RestController +@RequestMapping("/car") +public class CarController { + @Autowired + private CarRepository carRepo; + + @Autowired + private MongoTemplate mongo; + + @GetMapping("/{id}") + public Optional getCar(@PathVariable String id) { + return carRepo.findById(id); + } + + @PostMapping + public Car postCar(@RequestBody Car item) { + return carRepo.insert(item); + } + + @GetMapping("/count/{brand}") + public Long getCountCarBrand(@PathVariable String brand) { + return carRepo.countByBrand(brand); + } + + @GetMapping("/count2/{brand}") + public Long getCountCarBrand2(@PathVariable String brand) { + return carRepo.countBrand(brand); + } + + @GetMapping("/count") + public Long getCountCar() { + return carRepo.countWithAnnotation(); + } + + @GetMapping("/count2") + public Long getCountCar2() { + // default do repo + return carRepo.count(); + } + + @PostMapping("/count") + public Long postCount(@RequestBody Car item) { + return carRepo.count(Example.of(item)); + } + + @PostMapping("/count/criteria") + public Long postCountCriteria(@RequestBody Car item) { + Query query = new Query(); + query.addCriteria(Criteria.byExample(item)); + return mongo.count(query, Car.class); + } + + @GetMapping("/count/criteria/{brand}") + public Long getCountCarCriteria(@PathVariable String brand) { + Query query = new Query(); + query.addCriteria(Criteria.where("brand") + .is(brand)); + return mongo.count(query, Car.class); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java new file mode 100644 index 0000000000..421ecd3a34 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java @@ -0,0 +1,118 @@ +package com.baeldung.boot.count.service; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.count.data.Car; + +@SpringBootTest +@DirtiesContext +@RunWith(SpringRunner.class) +public class CountCarServiceIntegrationTest { + @Autowired + private CountCarService service; + + Car car1 = new Car("B-A"); + + @Before + public void init() { + service.insertCar(car1); + service.insertCar(new Car("B-B")); + service.insertCar(new Car("B-C")); + } + + @Test + public void givenAllDocs_whenQueryAnnotationCount_thenCountEqualsSize() { + List all = service.findCars(); + + long count = service.getCountWithQueryAnnotation(); + + assertEquals(count, all.size()); + } + + @Test + public void givenAllDocs_whenCrudRepositoryCount_thenCountEqualsSize() { + List all = service.findCars(); + + long count = service.getCountWithCrudRepository(); + + assertEquals(count, all.size()); + } + + @Test + public void givenFilteredDocs_whenCriteriaCountByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithCriteria(filter); + + assertEquals(count, all); + } + + @Test + public void givenQueryAnnotation_whenCountingByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithQueryAnnotation(filter); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenQueryMethodCountByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithQueryMethod(filter); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenExampleCount_thenCountEqualsSize() { + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(car1.getBrand())) + .count(); + + long count = service.getCountWithExample(car1); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenExampleCriteriaCount_thenCountEqualsSize() { + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(car1.getBrand())) + .count(); + + long count = service.getCountWithExampleCriteria(car1); + + assertEquals(count, all); + } +} From 8982fdcf737c3e973202ac4474a1c3002f42262d Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Fri, 15 Jul 2022 13:17:12 -0300 Subject: [PATCH 09/34] adjustments * removed controlled * fixed formatting on Car --- .../com/baeldung/boot/count/data/Car.java | 1 + .../boot/count/web/CarController.java | 79 ------------------- 2 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java index 55c26c1de4..42b80d70b0 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java @@ -1,6 +1,7 @@ package com.baeldung.boot.count.data; import org.springframework.data.mongodb.core.mapping.Document; + @Document public class Car { private String name; diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java deleted file mode 100644 index bc5d6dff9d..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/web/CarController.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.baeldung.boot.count.web; - -import java.util.Optional; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.boot.count.dao.CarRepository; -import com.baeldung.boot.count.data.Car; - -@RestController -@RequestMapping("/car") -public class CarController { - @Autowired - private CarRepository carRepo; - - @Autowired - private MongoTemplate mongo; - - @GetMapping("/{id}") - public Optional getCar(@PathVariable String id) { - return carRepo.findById(id); - } - - @PostMapping - public Car postCar(@RequestBody Car item) { - return carRepo.insert(item); - } - - @GetMapping("/count/{brand}") - public Long getCountCarBrand(@PathVariable String brand) { - return carRepo.countByBrand(brand); - } - - @GetMapping("/count2/{brand}") - public Long getCountCarBrand2(@PathVariable String brand) { - return carRepo.countBrand(brand); - } - - @GetMapping("/count") - public Long getCountCar() { - return carRepo.countWithAnnotation(); - } - - @GetMapping("/count2") - public Long getCountCar2() { - // default do repo - return carRepo.count(); - } - - @PostMapping("/count") - public Long postCount(@RequestBody Car item) { - return carRepo.count(Example.of(item)); - } - - @PostMapping("/count/criteria") - public Long postCountCriteria(@RequestBody Car item) { - Query query = new Query(); - query.addCriteria(Criteria.byExample(item)); - return mongo.count(query, Car.class); - } - - @GetMapping("/count/criteria/{brand}") - public Long getCountCarCriteria(@PathVariable String brand) { - Query query = new Query(); - query.addCriteria(Criteria.where("brand") - .is(brand)); - return mongo.count(query, Car.class); - } -} From 012c924afb48d588274ee9aedce37bd7724e7629 Mon Sep 17 00:00:00 2001 From: apeterlic Date: Sat, 16 Jul 2022 07:46:52 +0200 Subject: [PATCH 10/34] Add Maven Snapshot Repository vs Release Repository --- .../maven-download-artifacts/pom.xml | 52 +++++++++++++++++++ .../maven-release-repository/pom.xml | 38 ++++++++++++++ .../maven-snapshot-repository/pom.xml | 38 ++++++++++++++ maven-modules/maven-repositories/pom.xml | 23 ++++++++ maven-modules/pom.xml | 1 + 5 files changed, 152 insertions(+) create mode 100644 maven-modules/maven-repositories/maven-download-artifacts/pom.xml create mode 100644 maven-modules/maven-repositories/maven-release-repository/pom.xml create mode 100644 maven-modules/maven-repositories/maven-snapshot-repository/pom.xml create mode 100644 maven-modules/maven-repositories/pom.xml diff --git a/maven-modules/maven-repositories/maven-download-artifacts/pom.xml b/maven-modules/maven-repositories/maven-download-artifacts/pom.xml new file mode 100644 index 0000000000..678fc32bec --- /dev/null +++ b/maven-modules/maven-repositories/maven-download-artifacts/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + maven-repository-download + Maven Release Repository + 1.0.0-SNAPSHOT + + + com.baeldung + maven-repositories + 1.0.0-SNAPSHOT + + + + + nexus-snapshot + nexus-snapshot + http://localhost:8081/repository/maven-snapshots/ + + true + + + false + + + + nexus-release + nexus-release + http://localhost:8081/repository/maven-releases/ + + false + + + + + + + com.baeldung + maven-release-repository + 1.0.0 + + + + com.baeldung + maven-snapshot-repository + 1.0.0-SNAPSHOT + + + + \ No newline at end of file diff --git a/maven-modules/maven-repositories/maven-release-repository/pom.xml b/maven-modules/maven-repositories/maven-release-repository/pom.xml new file mode 100644 index 0000000000..bd7adcbcce --- /dev/null +++ b/maven-modules/maven-repositories/maven-release-repository/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + maven-release-repository + Maven Release Repository + 1.0.0 + + + com.baeldung + maven-repositories + 1.0.0-SNAPSHOT + + + + + nexus + nexus-release + http://localhost:8081/repository/maven-releases/ + + false + + + true + + + + + + + nexus + nexus-release + http://localhost:8081/repository/maven-releases/ + + + + \ No newline at end of file diff --git a/maven-modules/maven-repositories/maven-snapshot-repository/pom.xml b/maven-modules/maven-repositories/maven-snapshot-repository/pom.xml new file mode 100644 index 0000000000..5409e47b8e --- /dev/null +++ b/maven-modules/maven-repositories/maven-snapshot-repository/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + maven-snapshot-repository + Maven Snapshot Repository + 1.0.0-SNAPSHOT + + + com.baeldung + maven-repositories + 1.0.0-SNAPSHOT + + + + + nexus + nexus-snapshot + http://localhost:8081/repository/maven-snapshots/ + + true + + + false + + + + + + + nexus + nexus-snapshot + http://localhost:8081/repository/maven-snapshots/ + + + + \ No newline at end of file diff --git a/maven-modules/maven-repositories/pom.xml b/maven-modules/maven-repositories/pom.xml new file mode 100644 index 0000000000..ba39d00d65 --- /dev/null +++ b/maven-modules/maven-repositories/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + maven-repositories + 1.0.0-SNAPSHOT + Maven Repositories + pom + + + com.baeldung + maven-modules + 0.0.1-SNAPSHOT + + + + maven-release-repository + maven-snapshot-repository + maven-download-artifacts + + + \ No newline at end of file diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml index 253f5d9fa0..412e26f041 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -41,6 +41,7 @@ maven-parent-pom-resolution maven-simple maven-classifier + maven-repositories From 9d59e267ac7841e08331eeb1bd6a99800f2f5cb0 Mon Sep 17 00:00:00 2001 From: "thibault.faure" Date: Wed, 29 Jun 2022 11:11:36 +0200 Subject: [PATCH 11/34] BAEL-842 improvement to the spring controller return image or file in controller example: add a dynamic example --- spring-boot-modules/spring-boot-mvc-3/pom.xml | 12 +++++ .../controller/DataProducerController.java | 15 ++++++ .../com/baeldung/produceimage/data.txt | 1 + .../com/baeldung/produceimage/image.jpg | Bin 0 -> 8310 bytes .../com/baeldung/produceimage/image.png | Bin 0 -> 4567 bytes ...DataProducerControllerIntegrationTest.java | 46 ++++++++++++++++++ 6 files changed, 74 insertions(+) create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/data.txt create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/image.jpg create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/image.png create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java diff --git a/spring-boot-modules/spring-boot-mvc-3/pom.xml b/spring-boot-modules/spring-boot-mvc-3/pom.xml index 43a492786e..f2b6c129f8 100644 --- a/spring-boot-modules/spring-boot-mvc-3/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-3/pom.xml @@ -40,6 +40,18 @@ commons-io ${commons-io.version} + + org.springframework.boot + spring-boot-starter-test + test + + + + + /src/main/resources + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java index ab233a8b60..218be68a45 100644 --- a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java @@ -1,9 +1,12 @@ package com.baeldung.produceimage.controller; import org.apache.commons.io.IOUtils; +import org.springframework.core.io.InputStreamResource; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.io.IOException; @@ -29,6 +32,18 @@ public class DataProducerController { return IOUtils.toByteArray(in); } + @GetMapping("/get-image-dynamic-type") + @ResponseBody + public ResponseEntity getImageDynamicType(@RequestParam("jpg") boolean jpg) { + final MediaType contentType = jpg ? MediaType.IMAGE_JPEG : MediaType.IMAGE_PNG; + final InputStream in = jpg ? + getClass().getResourceAsStream("/com/baeldung/produceimage/image.jpg") : + getClass().getResourceAsStream("/com/baeldung/produceimage/image.png"); + return ResponseEntity.ok() + .contentType(contentType) + .body(new InputStreamResource(in)); + } + @GetMapping(value = "/get-file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public @ResponseBody byte[] getFile() throws IOException { final InputStream in = getClass().getResourceAsStream("/com/baeldung/produceimage/data.txt"); diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/data.txt b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/data.txt new file mode 100644 index 0000000000..5a8297fc5e --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/data.txt @@ -0,0 +1 @@ +Hello Baeldung! \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/image.jpg b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/com/baeldung/produceimage/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db3abce0d6ac5d8088ae6ddc9d17037e7465198e GIT binary patch literal 8310 zcmbVxWmFu^)^)?+?hI}Nfgr&pxI+l;9vp%@1PKx#xC{*L5ZqltaF^ijmY{)2&;(xc z+~>RN{{Bu|ov!X)yUwXyYggCf(&H9@_exGt4nRNv0EDLvczgh8q@5jI+^pQ)tt@HH zeQDpiSlO_P*9LjP|#4H3=IqYuVE2l;b1-Og!n{wxOhbP)TG43 zq}23O6jb!j85y7Ra`Vc_7$N-keWd@t4?Ok)_-H^Xf(i(M9zeuL0O2D%_5)N;EkHyB z{cX(uGgLHW6a*x65aQzsfcBq?FWtaR;6u>gCs-eFCjVYRACnTVMOpX$7U4v)D`JVC z;6sHSE>Aw%CG-e*hf5dq6rgyxAJ(b!N*vKo`@dC)GzFb1qBo>_4uMd&Cm%^(_H<1a zJ8UNB$pJjg^|-Nq!zUjBTkE_hKYY6~EP2_5tNA$N`+=WPLf|T0+UTyW1b|HX&71FB z8mv0$IyI%XChid@TmJ`()ZpWt%wcf3V>sbOwi}VD=PIjdp|*MLHH2zmU>Yah?N+;u z(5J}MxC2{ozj9xFMDh!jhGJKfd3``j8RB*rI2@|n3@`jDdKKYdFjr_-fn}VMa9j+n z`(=QV>INIlwcP69ErpFr{SV_=Xy;}o-MMTEE`nEYj1?n!m}eRLWFiaB?d-5YYnM#98znxAepDe? zwT^M2kOZT7T}XHm)ATjRr*%0juluXDx9B>>LWD&pK?0NJEt z{8E|pa~~%Nbs}q3bS|^~tKFCZW>Z^-@L~J84LK%fv)f%;dQFPCvvX}g6Dl{GJSxEu ze~yEQttkLlxYsQKfcO&(ihp7J4~{1oD2NEC|KI@qgCjQ&Kp+VW#QjFy4UFyu$isi4 z2LXG#`N$i40NJHt#DQZ;8LK|vM)T5Nc*bTaBTRXfx9n&-+F&;J`n=@etx4tg+eg44 z&6q~iYid1$;aaLBvdcI;%j->3TZDmV)f)geYcVeADNcVQ!-oeTAR!_kf>4l zl#EwQcIegitMV3G#8z?8;n3-61cty*;#M~4=J?mHj`Mo_1`{D|&-U(;-V2S=m6!G^ zZ~7sn*f59ziYZG1c8x6QtXyL@;9l35XW&7hEDOO&o>BC%#G-jDgWoCvAajS-C_IJh zGB~$a#eB}egHcwJLE7!F7e5v~Rr8cbV^IkiIZWJxPk2g}KdELx-Jd^O!ebgCSW@rl zREHclb>l4S`cBi;`>Lf~)L|1{8eZ9m)@27zaJaGaV0`g*L&z z;iLSplpH%kes67jOz{TVw}s+{^IYRmv*!thXUY0FUGmL^CT{bV5y4VC$#g7I1j)N# z)${8-j+Cl>V>=-oIdCZ28%eP1CErz1R0--$^+_{P;MB^Y(dIiQ#(`LqTaTR9z*@{^ zvS#kJFJBqW!_y;^qIsx>=G%)5q*;?w#$;8_L^CQB$Eth3Ol_{CpteMCuPFKxgQ}hG@JjU}&k!Cz znt1#wLUPl6*IFDFvq{Ddn8@-MyKjWMF8uoA1QQtlcGsi?Q8T& zbN#=4gg!QFADUcqk$`uN4tQdIuWtS#dhob63ym-zWvgrr?r8Or)j!HgdB^nH4)jfJ zK-H+CZm011)P9`fX_q}ys#aMFOz?w<=AVQJYTD8^pYg`q=?G-#)j)<0tUQ0ev*pes zS*U`y@j04q!cxl*W|wrnIWsuh!pN~}+si;n=ff@c9Mg#%0{JnWQ=WN-B!8rkL3iU5 zz}dw|2=-^>v&6gGE|2Bk3{^&}hN8SdD{;}Us4|nF329s-WEMGWO})wxXZ}4%ICAh3 zluLWLJYS{NNR(kA1;>+u^L=h`uq390sDN_Lor6n%Qj64~`YZwSOB7_JD!^l#!>@0- zfSS>s&|G;Yr0h%a>n5 zQqwk5{R0bW23S~5!)(9@Bw;p!uj;anl%d4(T;`+FT*2oga$9!p{P?DFKC6~#(hiL& zT{>NhE%WZRfzB}1!?)^_|d=0aqzRaL3m#WRz9zmJ`C_`0{YQ-_i0 zMYk#Oj;MOeFNkrb0S3|3m8!IOOlI$cF|KPwsfh0RhC@tm2e;zsHM`7g<)M@q2Ab4{GH=<-6sEdW zh{wfoI*#E?qv7e22~QXbRvoipVh{PH7@_qeFqXQL&la~!EvRp`YoNoXvQeROfOWNe zg!)9Y60E~*{u7Is_fAvH$5tzj$__SU@&XLOO;we*@2S}|MD5fL)mtaoemp-^_B~~E zx$-36A+`&V-8(8CPSP>uCWF#(rJO-w#u31)n7o;m1RzndvlzcMt!U4 zk+X5WJQrR0Jg{+wB7>FP6KK!>d1ZJiAlv_X^oZ(Z~6d4}|Pqp2i_N06}bG{-{k`#M!y-MpkCzPvCZUxJhEYdMr=>vA}SY2qAgHp$J z2gW}4%ra(4yfMwhu?{`K&d(Wg-Go^`3G&o0HA}Ff0Rgwt_E80=5n@=?>Ol=k4Ljn{ z;Anv{;%8mMOfX|qSDvW<=1a#%fXx12xazY`+v}k!vhF)?N01Rdu^~^nE%JIfc6`#J zO;jI6gk7}DH76dKI~P&BftJu*vf<~W28AK7CgbTS<+8%~-Y)WveZJa2`U(*n*wRA3 zF?+-WXBe$YRzbEoK@azC0Q8^0$?B;z)*PnqA1=Tq)hi|pJbY?Z_64`4$-ws8$q^_5 zCTAaok!*YP;;qH3`x?qpx?%b}(ggcmUjqjHmv?7ByeK(0`3!fevbRaEt23_|V!INb znTUJ@hBJG9F%2<}^GB7TO@O2hc()HYkZPr~R>{3dO0w%0F2jq9Do6yqVIoE7yF&OX zjgw-DJN83j4e#D(VHA8neF-Ae)bnCFX&MT262to+#YJ1U0Glcs15CrH&CvBa;Bb@=#-#vn1hEQ$l(8gV}<-3n*Dx+3W2- znoQ%%UYuRcxE9@*kiEH4}+wsEbZot)&Z%O{qN|x$qB^1 z5E1bjf-RLc$~&s}`F~nce2SC^qOVZ>5b}&=M5ODeqqhofCEwHTk_;xWC;A4azl`T; zZ2Zx}SnY(q5S|4q)8E?EoB0Kg(9(W2#Vc(gvp5ytUG7KZ^=1d19ZBWqH&Bhifu&1~ zRqpqv(IdO=^65+?;NadYw)w&#pbnm~`;90CV}k@vL48NrejrXj75e5~Y^;kVpLJ+J zl68Ajur1#MO$1vgW3gq)K4uCuK!&Q6#c8&@3Ubg%kSp8yy?nlBG2UJ%4kj*PDr=aA zIZV0KPGg=>J%xmqmS?B%HXmzj^h>0WX~|!)D2)doB7hJ;sOZSZsK|fC^^_1pW>d&J2V!$__#uk9-ktBW|~6!m83W8K@d zd@X;{1!KhpDrqqLoS0MbKS-_>xJFP=VLJT% z_&uUug+k^wA?vLayw#t5ycESfe3{(4=^ZI$wXPNvzkw@tf16o^4U(^{210u_{rphQRt&vq`sly&F*OlX&xNq} zSe!eayqz>sq^C-Cf9C9OcXXRYYFGFOsQY6#NBG4dG=@+i2`)|7uihI|#W)%lBzOni^^^`1O43e?uz91Je)Fbb{CZH_rnN{f z6Tq3qfYoR1$0F=x^QP^F{%d2V_CzwEpyH@Dp%Cy}F1zO#=zV&@G zjD9h2S2;y(um-xhtbyvd(O?7@G^l5`Ef~&LRov=nyeC&&D?DMk&e&*;`1?eaWhR}? zWpn)?jtj$e2GM4zvQ~ABP!i#WdTT zoGc>aM?U6%WU1YAy&z;`3uoCZAyH6-~;`ym}V0$XJEHZj@yvLf~A^9No z)P2^DY3knQHD_=*bHMLbgmpFaZ7!{%@S|4dyEI&$s+6&7P}v)w8R z-F6tGpuXjcV$X}&s0Ks*s_79Y+p$Vc6$}qw>iM(cNOVM9_TZY21`Xem3>gSyr3&59N2%S8at8HOE7gxM{I@n15zZs(K2JR*k>FH(R5`fXOOF z+dw{QW!Dd!C3eORrXivUA(02A)j02pJDWPF<%~O7m!;Kd>A>{Cr_Vr)v2Sq+Rk0HI zi-nLegWLq8!u8+DcDq5^KLim7DQw2JU6&i8J0T(M6IgnXL&K#hZ`W}azZVWhfOMUZ z){5~g+`%UcIPT;>4C02H8p=k~nR;dXdaQ|EnPrgvlrbjOqNv&vYRG-&{u$Hp#a1c+ zJoKhat0-|aczW&}iRyzc^Wf}Ci2Fo+mLlm|8gp$rFp?Sic(Vqdcm43sx`|IVkMzjr&SLAv9#TiBs6G+#tgaAa)s?He zE57v9zhKSSJ3r?0Y&wj3d*@paqJhBGg9#osA+r)HE2Ps4E*JP^se)DFX{Zb#KOxVe_Drk=by;PjVOo5=q=_PE`l@OF4|+{S$>Uj^2} zg~D+~Ftfnoo$n)XEA8cI<2HF;Q9Ldq^ z9G22E3!5{PU$6)ksSauWi#<-gURnsGh`jwa!Ks zlRmIK$K)MmP;t9Rghd4Pt|rjaZlu?9yI5(SAnWku+GSZBjhE4uDJ-sv;1fE+XS43b zzk{9btCl-#Wgg>|W=?YSrP`rhw?;;rhK?S~2>p>b$+NvZ^4SVgrD*S6HRZ_(VZ>}E z*`<8R6$XRj4qPf*k7yyo&@M>)_qXjISJsosxXNfNgRt)u@-lv5CO@MZ#c`J;SeX;- zbLVn;wgbuN?1)2)CvG+_^0peTZtlEL4xE1k8lFL`&P6nJb-WcRIENKw`x>2pS0YsC zX9$rpnh044F8QG`n3X0#I&bkMg{V6n0yBEJR`rLW6Leeoss}F59Uy9DqkS0fxI&FJ z-FM^bB|%X*fGg7gYa`&72pVv8SUzbZqlhe3;t2J zjs!*(t4z+k9rK=%Cw9T8Jx9p|>2i+XO?_tACOxoyo#dfl`1Bu|u25=eo{@sb28o-P z<8IwJ7efV@)`+h?4rX)1o{{q-d(vMAqdW||H#bQTQEL9!Xix-$8Mf}V5^YeewL&65KAMEUROKm}JyVmX z^3#cVy&$-EZB=fzd$%@1!Zimw^tB5Kg+Arstt^F|Y;m5;)D-tNwY5=D-suc0^t`Y= z!`o*WS3bZ@Q<1SLQ4`S60y;IS=RKz|P*04P24@*K{=ANcsr>%BQGm*RW8QGJ-!28M z-KJD-5k1wZL)(?SN%Co+D!R(}+?jNMzT+_+8CS_=&YM!xcYS^z0tYa2Dg58EcH&|-&npb^p6$l zrbp2m8e#yVgh$GDVP}s(24o1yL8_1ZVy!=;d9MLogxXiDCOjZ2p+hdhU62CVJt8|w zmmNiNC7k3Qz@Rv&>#q|JOr?W;q0auI|$Ux@p=RaB)5dlFQxIg%g zJlyhqsOCk1FGGyg+Kcp0D#y1{b44Ut%*4aT+^l#+d= z#x(p>v)-Q-*ZS|i>ho7I`2AYO!a~p%0-+T3*2Dr zZlC$i9iRRn3t#Z5?d$7$ISMk1uHq0wQbp~a^s*YC?$XxJXii*H$-$LF2NF>MzWden0bnwa=IFt=jw$(Iw$2o&TD z1*;0l!F;=&MQ;`+Zq07v9YS_k+ZYu_&MBQB&Yuj&2Gzbv#ib$Eu#F9neY7exvPdiH zYSYF~^Aude!FdaI5JHJlH`Vg(k6XI$8C~;(%{<`Mi>v3d+c{h@TNT zniw*tf)nK=_=xxWF;8;n71p?M>Sh4Hq5>uR16nKZ5j0!#SRTe!Th4T>)7=!nZ%bTwP#rE2(p8}joSWh7T~2NRQ{O{@DL{QQSLLjTYQ5d=a*M*{s1eUP6f zmXd@|1R|!FaCHk#Bw~14gOJk5ucPI0?+Hz+|Iez)Uj{uil*+vb%Y6qwb2`_6`IwQx zwAFX)eq}=TPBxC_CtLMjt;%WTj?Y0{X;WP{JG}hg3T%=K{vO4hn&VS~+mRQ&Uk@|^ zb>+w>Mi1|&{bEWYvqVk_z@Lamfb&YAlA$i|wIE3XBK`Ki--S1WH)wly!2|3?IqmS z(C)d~!O4cS>k+WWU(*Sr~B8&sNjBjA%&-ceedbBJ=zZRuBB%V4ad2 zR@?FVW+E+(qUoZ#tO~5qy^J$VUxp~%KB4WtlYX_air3IxGw(^2=LgJhz63jDifH{1 z>X~?&&e)OKvs@vJXTVPeS}@ftuCnF~`ZZOtSjhT*iDH|+b=A)q=eYH2$90siRsefl zEosi#{8^}>S1PGYY}U?J;IrWMy0hdSUDDS4J-ukf{!6Dj?;Mi5QhiQvc`zx1gr~(R zinA@PE*oiVsD>>f$cJxko zX^eSgtOr*8DYPWXx7OH8s{yO^};+qbi1o@QHiG?x|gsc74 zcrk6!$~&z@l_V6TElQnYuJ)W^YP5?&KY<)RO7#Kq!Hi99V2+I&l9HVDPmz91D=M+X;@`P!Lu` zBKMeUdL|3wF2&VeDQIHn%Rze$dVvu(r16~H;1`~h$sjdP!vc#OHWP zUDzVOuJz@-HytDa#Wm;6^t^LPznY<=`y8UZden}x5K;B5q{gZ&-v{V-ukS5{a+rYs zJ1z2*(*jKI7B=0GJv>sA~-8sG5{2iaKr?(%zcYH$_+D*o^B*`mPU5g|6kMuDwo1$ARC!Q1L&fk;U@`=jM+h`<) W&N(9HN76>pOMWXIs(2aPx#1ZP1_K>z@;j|==^1poj5oKQ?uMgRZ*DSI*|dM_JxCLwq$9(O3p+{_bnAbhHT zjIfXA@aPwHBRqve&f(A>cPjMw^ayep)#287qwXru)oy7khYZQ@#)*=+@8Flg|CUc(!Kz02~3VtU6f)the4;qs+zo=j<%9Vj83%7 zwo#E+Sd(3(#HTZVJ7u0~ccOY*l3;0?ZLoD z5Qj-bK~#8N?VSsEqP!M{C4f<51=}iCt<>9SwYL3E|NnnGx$GShE*8-_XXb03wPvkB zQZ~G~?d&AbayT3ghr{7;I2`|0hO?K>>EW=MzU)>J{N`vzx(q2}VL(VQV2sj--3ZP& zE+(A@KJiQl{aE(ktm87?NeC($5avC*I)6D)C$UQ=Lg-@~(m3i8Z5YT`gsk_F%2AVv z589OyFCm$u7JCZ92}mF?t3C-*Na(0R8iQ^e-`||J+wD`I8r?iSLP|#sP65c~1@sj< zo<(~fFcj2(RX;jvaMXp9o)++%WEVmQ70=-p$G1cqES&Tne$p(da7Nk2`JT0DW8w7w zfnN;LDNESY4UOuvg~Cb3R!v9Jq3hN!p!WeC4m6PIzI*?Rvzh*jq)`DXlA5E zdM|6deCWsPY4Ns93p235?}e77)ucym%;1vj6+FX$h;h@a(DLV5n0ttQOnpWt1(n}@ z{(HQIBgv@iYd=fE{5P}J=uk@ICwZkEp=Qc}S_!$>fk=C@tVSK*9u^PSuUu?FTG%QJ zo@HT>w*aKG2QOg!&rHUb1u4g1$RF_=ums?OQmYqA6ZtF6k2zBnK8cO7eY;-_0tDeZ zoaJ>w<{Ry_T6d?sRWBe}LY^@yTP&+-NsNK`9aC|`!c)P*fb1YyMtj1uHJ{M)!V{dY z2Mj04xHT;agZK|d9qp=uOb)r?3BL!K;rCFF3=Bxph4Za9d7gYk^RkqL8QSesjUoNa z>K!S&yvLr5%m)koXzqV!K@ctD0i4URzNmPDE%Ip%+%*Bs>cvE*C6Bg&=ma^^$EVp9 ziUW|mKnf2MyjH{oMX3T_AeV{G*o9ZBrYLlop7=DC7N(F;5^YMKUck(%@*O>lC4E!` zmB?D_`2e!z<%IS^%bD7(rUCIF3CdX#vQ{Lz<>){fAKS)gQ&En1=4VA1t6HT6vu%nV zE0cM?u2MC)E2tyn#b}K!XPJdS_W|>gUPE(@ob1$=S}o?A>_iORU`;u* z02RBJ4aI1eHFiv0%aoI_x4EnUQMxzkCViGEi*i1xi?RMbRW~wfPX_vW11NK*Lc)T) zH(|k$9xSwQBqQOj5@ReYPR->ciQ#Cz#At-{)os_4v$vK<99>dcJzf7p)yEie5^A*d zqlvD`WUO+hAm?$-|JaZBx|!s($EcDVj&KY)1JgpZ)s=^QC<{1};cyrCZMK?o-tdBr z%|xGO9u%GrvdoS2*u-YmGknVc+dp{p(Q<*`o6jLu%SSxx0E28p!>OrEMGXN0#A zU=JoqQ9xCAw44+@QB8EfbD(bfHYf`yC;25$S`6{I=!_qsCz7k3 z*aS3`({RHy7#~qNUQ5m%Jd~H%b!>^M$h$*1p`*7sK)FyETwBgP+^oubl=G~G;Ef;b zA*nG)7F;JM3E&r#A=ZiuR%n6p11vMaf7D6fIyuAA*-Gr*Vo}sCk~6U4b-W6roU*?MISG;Ha`fPW zDibX^qc@0~Nw|NQfe*rS!H~18H4&qJ!-6iIx0I8KW~2aKQ#LXe$vMc);|-xjwB*dy zF9b7D>SD?Hp1FwCB;x)+qmmv$fDQbbTR_k5rj=cUkBjKwvgm*>l2gf+fpV(n134=u z@Uh#Hx>$1J!C4Y*OH;Vd#2>X**eFF3GW)Zfu|zLr(? zzTIbEA!qO@&*iCZJG0VBRKyJ-MpV#jJ8joogBC>FnYn{Jd&RNhx>1qx*7AJ9HRYl& z$kJRJ(~3Z-26C47yAeisiaon7oqqo*$5@LZa{=UpabzB}AYHL6py1I%CtV0eJ4n$` z&a%;iQBH(Xs4Wu@mVslZ26B2#p3Bh&J0)`BV1VrwSvgYlp5YuB8*+Msd^*7#pIZ2x z+=R{vkA!h7+^!h^zM-6|isWcxVUQ1o&qD3VXAC|xkyAQgd9+_Gn*vKtJQbISlw$ps zvuY>@E1N0D%a8|o7>zLlOK2!(S#8(RA?a@8P2}1m^xK-qS>|}^NP+72EjjPtDrFuP zCRDu-${8HwNgM3T(X$x!wG0Is%1HvDhJ}sKSR#WOonY^Z8G10;DJPqY62+)c!QUIZ{Bi^EVPN0X|T27ox$j~7xv!9whRus^tau&7}EI}FWY0Bdf9$OWt zi#Og#PS4Mc0*Bys@iXdnY&rG3-T(_0@QNqEao2Ks;iuiu-f81t0oZ||9F65P7Yp#R zImH{)p-b&h7;7lzP}Q5t=`rhRkJ*xZ*x+Ex*}@eOWNqpBiuXnWRTwila~5XWg1v>} zy`np6E~m#1`W{zfomm6yFYw8P@KA%^vzgY0a(aVoK$cFj^&>ds%gG6AY&dbY!?FFQ z)x+sYLr!l%$}O0M^VMiP2_F@}f3K30yIq^tHs|?Z$P{8G>Odqn@-dyuWN^%BDyK)- zV~1a?y*nB6!g{JHC#P;B#XUUj#LezEf&MMPh3BT66&B2y#vQh&UKo?jcJrZCzeY}O z#HVp=?t<~+Y$S_uEe;t_Y9(tfC;!t>7-i-n4V>IB$l1<}l7PkH?~J=*IHzFAS!%(Y z1<(3Z(n-@%H0rf+;M7pgil)P3#uVBtE1pG~$XR97WBSkYa<*o=AQj0ZLOH7~m|FpG zTtvpYwYzfaZIV?36ZQlt1?8));LhvGseT7J$-7?TVB=?23v#x06@SDBZ&^ixn+o<7 z;`^|?K@wrW&Tvv2MU>DiANQ1wv~p{W7axU0WB~IPL^fNv;6n}dGE&GlHD&=h{kvhQ z`%I0Qk)oWfcd-tn2r-(amQs zGGzP#F@G{STWxUz284~RxJa3tt==}TQ5f7?8F(iaZ3WU}Za?NNct$TIz`=o8rJBjv z8ZBcMz$T4-!f-7b@8Qj0s=-`ueIp6x+lshr&8hWFFzjQFc~l3ymk6X;hPSkG0kV9dT5jZ8y1ZFcwmnmZrK`e9kU z2js5XUnfbjK6Gnr=qbgNlQZiuW%XClYK5FUdtN@{ME=#d^X*GucAc=&0+$|(Z+LCn zStLq_X|J?gnk;&Sn9c>{jj(oxb=t*6?*1YQU8&^gisxcUX&A4oTIxj(X@Q` zrd(q1hw~|GaOoU)o=81qaq9Bs9LL69KOi?H^@oy%At6C-IY|X8Iv|7{z8gkf#G+&) z0MEIXP0R*j`IuTzHt^$;Akd#kd-C|Wt=THIxBX4$hE;trpN=c~mnhv&w}*bezd3Ec zzNX97O*8R#vbaE?!uqbpM0ec@p)CJ~1B+2_aXW+mTB74i_hB9T0rCEd2JufIov&8= z>Dw<(|MRo+ESY|e6AooC_R03%Iw~0rcW;j#qtw^EN$5-Xv6K-A)EXg2HBtNiky3N@ zMkORD?baQd#q&c_9mL3?m*}RycbxUNvgpLta+LGv7cxb^avSp;oal88L6Ta8db7yZ z_i?t+fvig2Cw7MH)j;<&x4zRMmh{%I<{Z6hF5+r>6}x19E+?Ebs|N|te-~>0_8974 zMpU()y#k_RE)$gv6+1S6CQ%=z!fQfskI@KU5>>vR{)e);q(|r4;f9m6um4bPB6JAO zy*RD}t>(~JR4Lyg;o!_G7tNMJ0;uV$fe~`A*iirTh^%#y-x6S-zO>foy1ocd%VFyh zJ}Q4Rf-W6#aw>)wjfL2o8Vj}ao|ThRF}cJ?!cBVn!i$!joD%)MtQrv5qO{0fHK}oO zN^qr34MID`35n&luvS`pJ-xumDbPFXza#Xdw;8>V^0wA}CrnVY zBO>fej(S#ysxY2&E{sCH=HZ7W|);l}I&z0u+vf!f)YPLgUbK)%28$Aj;9 zIYSVCihACj_~+V%dTY-9?R@(tx_~~-c?Z-!g=ZUC>jeQnmPo&YubjZ&@KQJ0Kb@)O zl2AEOKb+|71W_12wOg&(G|^i&E77lJ_|fQB#1|oh!7^POPf2kdaS`)70Y4bMA+-QG zb&ju($klR^_%GOJ`9I@YIep?*dKp|N=U{EWL+QtJjhw;SeQiF+8Nc&9 z#P?Nr-eG_{+%JO!@nPx2EMk1uv@V3P@#oOBnPsGP<~A|{pRR+_ukTY-=OKhq|6{YAzOHJ#NY5d_x9t@OnD?-6 zw_S<6hzd_BTz|P%vH|)tmnI=wx)m~wh>E)mNa6;Mjmf@j00d=k2X@pXzpBRHxT1Ll zsa-m$Tg`DDR&BSw3*=~k83plO*}Rq!esR+C2IfaW9L>-nWVfjB7W8oKOzb?QTL8r~ zEdTzx<3dKt^`x$<--c(QXa1{5j;2Indy9Kp!p-2mC#m!DWJf)=Vd)379nI*CiL2{3 z~$H(Vs6SltN7? z4gBL?0h#_|5%8gwmX?;5mX?;5mX?;5mOIhu{2#Y65H^G1m%so3002ovPDHLkV1k2+ B)jR+I literal 0 HcmV?d00001 diff --git a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java new file mode 100644 index 0000000000..29f794645a --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.produceimage; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest(classes = ImageApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class DataProducerControllerIntegrationTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + private MockMvc mockMvc; + + @BeforeEach + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + void givenJpgTrue_whenGetImageDynamicType_ThenContentTypeIsJpg() throws Exception { + mockMvc.perform(get("/get-image-dynamic-type?jpg=true")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.IMAGE_JPEG)) + .andExpect(header().stringValues(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_JPEG_VALUE)); + } + + @Test + void givenJpgFalse_whenGetImageDynamicType_ThenContentTypeIsFalse() throws Exception { + mockMvc.perform(get("/get-image-dynamic-type?jpg=false")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.IMAGE_PNG)) + .andExpect(header().stringValues(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE)); + } + +} From bd44bc5f2d2ca7b7fe33aff4502b3a75094db191 Mon Sep 17 00:00:00 2001 From: "thibault.faure" Date: Mon, 4 Jul 2022 22:08:12 +0200 Subject: [PATCH 12/34] BAEL-842 fix failed build because of UserAccountUnitTest --- ...ntUnitTest.java => UserAccountIntegrationTest.java} | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) rename spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/{UserAccountUnitTest.java => UserAccountIntegrationTest.java} (84%) diff --git a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountUnitTest.java b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountIntegrationTest.java similarity index 84% rename from spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountUnitTest.java rename to spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountIntegrationTest.java index 507321bf8e..7c23153951 100644 --- a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountUnitTest.java +++ b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/springvalidation/UserAccountIntegrationTest.java @@ -1,9 +1,7 @@ package com.baeldung.springvalidation; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -15,7 +13,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc -public class UserAccountUnitTest { +public class UserAccountIntegrationTest { @Autowired private MockMvc mockMvc; @@ -46,10 +44,8 @@ public class UserAccountUnitTest { public void givenSaveBasicInfoStep1_whenIncorrectInput_thenError() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfoStep1") .accept(MediaType.TEXT_HTML)) - // .param("name", "test123") - // .param("password", "pass")) .andExpect(model().errorCount(2)) - // .andExpect(view().name("error")) + .andExpect(view().name("error")) .andExpect(status().isOk()) .andDo(print()); } From 27a3dd08d9d4f1ab30563f8de50e7a4651e34b1f Mon Sep 17 00:00:00 2001 From: panagiotiskakos Date: Sat, 16 Jul 2022 20:30:06 +0300 Subject: [PATCH 13/34] [JAVA-12192] Renamed to *ManualTest --- ...ationTest.java => MicrometerAtlasIntegrationManualTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename metrics/src/test/java/com/baeldung/metrics/micrometer/{MicrometerAtlasIntegrationTest.java => MicrometerAtlasIntegrationManualTest.java} (99%) diff --git a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationTest.java b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java similarity index 99% rename from metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationTest.java rename to metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java index 02ef926794..cb679b73fb 100644 --- a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java @@ -37,7 +37,7 @@ import com.netflix.spectator.atlas.AtlasConfig; /** * @author aiet */ -public class MicrometerAtlasIntegrationTest { +public class MicrometerAtlasIntegrationManualTest { private AtlasConfig atlasConfig; From 86b509da2a243adc6cb3510838743342ff14add7 Mon Sep 17 00:00:00 2001 From: panagiotiskakos Date: Thu, 21 Jul 2022 07:01:24 +0300 Subject: [PATCH 14/34] [JAVA-12192] Renamed to *ManualTest --- ...ntegrationManualTest.java => MicrometerAtlasManualTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename metrics/src/test/java/com/baeldung/metrics/micrometer/{MicrometerAtlasIntegrationManualTest.java => MicrometerAtlasManualTest.java} (99%) diff --git a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java similarity index 99% rename from metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java rename to metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java index cb679b73fb..8341befb83 100644 --- a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasIntegrationManualTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java @@ -37,7 +37,7 @@ import com.netflix.spectator.atlas.AtlasConfig; /** * @author aiet */ -public class MicrometerAtlasIntegrationManualTest { +public class MicrometerAtlasManualTest { private AtlasConfig atlasConfig; From b23fcdc4c4cd7cfbc23f6adf4944b6b8a9da7596 Mon Sep 17 00:00:00 2001 From: anuragkumawat Date: Thu, 21 Jul 2022 23:10:50 +0530 Subject: [PATCH 15/34] JAVA-13336 Refactor mockito modules (#12517) * JAVA-13336 Refactor mockito modules * JAVA-13336 Fix Jenkins build --- testing-modules/mockito-2/.gitignore | 14 ---- testing-modules/mockito-2/README.md | 10 --- testing-modules/mockito-2/pom.xml | 31 --------- .../mockito-2/src/main/resources/logback.xml | 13 ---- testing-modules/mockito/.gitignore | 7 +- testing-modules/mockito/README.md | 14 ++-- testing-modules/mockito/pom.xml | 67 +++---------------- .../mockito/additionalanswers/Book.java | 0 .../additionalanswers/BookRepository.java | 0 .../additionalanswers/BookService.java | 0 .../com/baeldung/mockito/fluentapi/Pizza.java | 0 .../mockito/fluentapi/PizzaService.java | 0 .../baeldung/mockito/java8/JobPosition.java | 0 .../baeldung/mockito/java8/JobService.java | 0 .../com/baeldung/mockito/java8/Person.java | 0 .../mockito/java8/UnemploymentService.java | 0 .../java8/UnemploymentServiceImpl.java | 0 .../mockito/mocksettings/AbstractCoffee.java | 0 .../mockito/mocksettings/SimpleService.java | 0 .../mocksettings/SpecialInterface.java | 0 .../baeldung/mockito/objectmapper/Flower.java | 0 .../FlowerJsonStringValidator.java | 0 .../mockito/whenvsdomethods/Employee.java | 0 .../IAmOnHolidayException.java | 0 .../mockito/src/main/resources/logback.xml | 8 +-- .../BookServiceUnitTest.java | 0 .../bddmockito/BDDMockitoUnitTest.java | 0 .../bddmockito/PhoneBookRepository.java | 0 .../mockito/bddmockito/PhoneBookService.java | 0 .../fluentapi/PizzaServiceUnitTest.java | 0 .../mockito/fluentapi/PizzaUnitTest.java | 0 .../ArgumentMatcherWithLambdaUnitTest.java | 0 .../ArgumentMatcherWithoutLambdaUnitTest.java | 0 .../java8/CustomAnswerWithLambdaUnitTest.java | 0 .../CustomAnswerWithoutLambdaUnitTest.java | 0 .../mockito/java8/JobServiceUnitTest.java | 0 .../UnemploymentServiceImplUnitTest.java | 0 .../LazyVerificationUnitTest.java | 0 .../misusing/ExpectedTestFailureRule.java | 0 .../MockitoUnecessaryStubUnitTest.java | 0 .../mocksettings/MockSettingsUnitTest.java | 0 .../FlowerJsonStringValidatorUnitTest.java | 0 .../WhenVsDoMethodsUnitTest.java | 0 testing-modules/pom.xml | 1 - 44 files changed, 24 insertions(+), 141 deletions(-) delete mode 100644 testing-modules/mockito-2/.gitignore delete mode 100644 testing-modules/mockito-2/README.md delete mode 100644 testing-modules/mockito-2/pom.xml delete mode 100644 testing-modules/mockito-2/src/main/resources/logback.xml rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/additionalanswers/Book.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/additionalanswers/BookRepository.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/additionalanswers/BookService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/java8/JobPosition.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/java8/JobService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/java8/Person.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/mocksettings/AbstractCoffee.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/mocksettings/SimpleService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/mocksettings/SpecialInterface.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/objectmapper/Flower.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/whenvsdomethods/Employee.java (100%) rename testing-modules/{mockito-2 => mockito}/src/main/java/com/baeldung/mockito/whenvsdomethods/IAmOnHolidayException.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/additionalanswers/BookServiceUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/bddmockito/BDDMockitoUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookRepository.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookService.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/lazyverification/LazyVerificationUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/misusing/ExpectedTestFailureRule.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/misusing/MockitoUnecessaryStubUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/mocksettings/MockSettingsUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java (100%) rename testing-modules/{mockito-2 => mockito}/src/test/java/com/baeldung/mockito/whenvsdomethods/WhenVsDoMethodsUnitTest.java (100%) diff --git a/testing-modules/mockito-2/.gitignore b/testing-modules/mockito-2/.gitignore deleted file mode 100644 index 7f300600e6..0000000000 --- a/testing-modules/mockito-2/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -*.class - -.settings -.project - -#folders# -/target -/src/main/webapp/WEB-INF/classes -*/META-INF/* - -# Packaged files # -*.jar -*.war -*.ear diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md deleted file mode 100644 index 6fd71bf305..0000000000 --- a/testing-modules/mockito-2/README.md +++ /dev/null @@ -1,10 +0,0 @@ -### Relevant articles - -- [Mockito’s Java 8 Features](https://www.baeldung.com/mockito-2-java-8) -- [Lazy Verification with Mockito 2](https://www.baeldung.com/mockito-2-lazy-verification) -- [Mockito Strict Stubbing and The UnnecessaryStubbingException](https://www.baeldung.com/mockito-unnecessary-stubbing-exception) -- [Mockito and Fluent APIs](https://www.baeldung.com/mockito-fluent-apis) -- [Mocking the ObjectMapper readValue() Method](https://www.baeldung.com/mockito-mock-jackson-read-value) -- [Introduction to Mockito’s AdditionalAnswers](https://www.baeldung.com/mockito-additionalanswers) -- [Difference Between when() and doXxx() Methods in Mockito](https://www.baeldung.com/java-mockito-when-vs-do) -- [Overview of Mockito MockSettings](https://www.baeldung.com/mockito-mocksettings) diff --git a/testing-modules/mockito-2/pom.xml b/testing-modules/mockito-2/pom.xml deleted file mode 100644 index e5812222eb..0000000000 --- a/testing-modules/mockito-2/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - mockito-2 - 0.0.1-SNAPSHOT - mockito-2 - jar - - - com.baeldung - testing-modules - 1.0.0-SNAPSHOT - - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - - - \ No newline at end of file diff --git a/testing-modules/mockito-2/src/main/resources/logback.xml b/testing-modules/mockito-2/src/main/resources/logback.xml deleted file mode 100644 index 7d900d8ea8..0000000000 --- a/testing-modules/mockito-2/src/main/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/testing-modules/mockito/.gitignore b/testing-modules/mockito/.gitignore index 83c05e60c8..7f300600e6 100644 --- a/testing-modules/mockito/.gitignore +++ b/testing-modules/mockito/.gitignore @@ -1,13 +1,14 @@ *.class +.settings +.project + #folders# /target -/neoDb* -/data /src/main/webapp/WEB-INF/classes */META-INF/* # Packaged files # *.jar *.war -*.ear \ No newline at end of file +*.ear diff --git a/testing-modules/mockito/README.md b/testing-modules/mockito/README.md index 6cc6bb8955..2870d1afcf 100644 --- a/testing-modules/mockito/README.md +++ b/testing-modules/mockito/README.md @@ -1,8 +1,12 @@ -========= +### Relevant articles -## Mockito Cookbooks and Examples - - -### Relevant Articles: +- [Mockito’s Java 8 Features](https://www.baeldung.com/mockito-2-java-8) +- [Lazy Verification with Mockito 2](https://www.baeldung.com/mockito-2-lazy-verification) +- [Mockito Strict Stubbing and The UnnecessaryStubbingException](https://www.baeldung.com/mockito-unnecessary-stubbing-exception) +- [Mockito and Fluent APIs](https://www.baeldung.com/mockito-fluent-apis) +- [Mocking the ObjectMapper readValue() Method](https://www.baeldung.com/mockito-mock-jackson-read-value) +- [Introduction to Mockito’s AdditionalAnswers](https://www.baeldung.com/mockito-additionalanswers) +- [Difference Between when() and doXxx() Methods in Mockito](https://www.baeldung.com/java-mockito-when-vs-do) +- [Overview of Mockito MockSettings](https://www.baeldung.com/mockito-mocksettings) - [Testing Callbacks with Mockito](https://www.baeldung.com/mockito-callbacks) - [Quick Guide to BDDMockito](https://www.baeldung.com/bdd-mockito) diff --git a/testing-modules/mockito/pom.xml b/testing-modules/mockito/pom.xml index 36f4a56dff..b55245f20c 100644 --- a/testing-modules/mockito/pom.xml +++ b/testing-modules/mockito/pom.xml @@ -4,75 +4,28 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 mockito - 0.1-SNAPSHOT + 0.0.1-SNAPSHOT mockito + jar com.baeldung - parent-java - 0.0.1-SNAPSHOT - ../../parent-java + testing-modules + 1.0.0-SNAPSHOT - org.springframework - spring-core - ${spring-framework.version} + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} - org.springframework - spring-context - ${spring-framework.version} - - - org.springframework.data - spring-data-jpa - ${spring-data.version} - - - org.eclipse.persistence - javax.persistence - ${javax.persistence.version} - - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - - org.springframework.boot - spring-boot-starter - ${spring-boot.version} - test - - - org.springframework.boot - spring-boot-starter-test - ${spring-boot.version} + org.mockito + mockito-junit-jupiter + ${mockito.version} test - - mockito - - - src/main/resources - true - - - - - - 2.0.4.RELEASE - 5.0.8.RELEASE - 2.0.9.RELEASE - - 2.0.2 - 2.1.1 - - \ No newline at end of file diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/Book.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/Book.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/Book.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/Book.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/BookRepository.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/BookRepository.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/BookRepository.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/BookRepository.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/BookService.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/BookService.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/additionalanswers/BookService.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/additionalanswers/BookService.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/JobPosition.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/JobPosition.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/JobPosition.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/JobPosition.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/JobService.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/JobService.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/JobService.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/JobService.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/Person.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/Person.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/Person.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/Person.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/AbstractCoffee.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/AbstractCoffee.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/AbstractCoffee.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/AbstractCoffee.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/SimpleService.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/SimpleService.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/SimpleService.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/SimpleService.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/SpecialInterface.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/SpecialInterface.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/mocksettings/SpecialInterface.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/mocksettings/SpecialInterface.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/Flower.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/objectmapper/Flower.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/Flower.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/objectmapper/Flower.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/whenvsdomethods/Employee.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/whenvsdomethods/Employee.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/whenvsdomethods/Employee.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/whenvsdomethods/Employee.java diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/whenvsdomethods/IAmOnHolidayException.java b/testing-modules/mockito/src/main/java/com/baeldung/mockito/whenvsdomethods/IAmOnHolidayException.java similarity index 100% rename from testing-modules/mockito-2/src/main/java/com/baeldung/mockito/whenvsdomethods/IAmOnHolidayException.java rename to testing-modules/mockito/src/main/java/com/baeldung/mockito/whenvsdomethods/IAmOnHolidayException.java diff --git a/testing-modules/mockito/src/main/resources/logback.xml b/testing-modules/mockito/src/main/resources/logback.xml index ec0dc2469a..7d900d8ea8 100644 --- a/testing-modules/mockito/src/main/resources/logback.xml +++ b/testing-modules/mockito/src/main/resources/logback.xml @@ -2,17 +2,11 @@ - web - %date [%thread] %-5level %logger{36} - %message%n + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/additionalanswers/BookServiceUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/additionalanswers/BookServiceUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/additionalanswers/BookServiceUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/additionalanswers/BookServiceUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/BDDMockitoUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/BDDMockitoUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/BDDMockitoUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/BDDMockitoUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookRepository.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookRepository.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookRepository.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookRepository.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookService.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookService.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookService.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/bddmockito/PhoneBookService.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/lazyverification/LazyVerificationUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/lazyverification/LazyVerificationUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/lazyverification/LazyVerificationUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/lazyverification/LazyVerificationUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/misusing/ExpectedTestFailureRule.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/misusing/ExpectedTestFailureRule.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/misusing/ExpectedTestFailureRule.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/misusing/ExpectedTestFailureRule.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/misusing/MockitoUnecessaryStubUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/misusing/MockitoUnecessaryStubUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/misusing/MockitoUnecessaryStubUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/misusing/MockitoUnecessaryStubUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/mocksettings/MockSettingsUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/mocksettings/MockSettingsUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/mocksettings/MockSettingsUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/mocksettings/MockSettingsUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/whenvsdomethods/WhenVsDoMethodsUnitTest.java b/testing-modules/mockito/src/test/java/com/baeldung/mockito/whenvsdomethods/WhenVsDoMethodsUnitTest.java similarity index 100% rename from testing-modules/mockito-2/src/test/java/com/baeldung/mockito/whenvsdomethods/WhenVsDoMethodsUnitTest.java rename to testing-modules/mockito/src/test/java/com/baeldung/mockito/whenvsdomethods/WhenVsDoMethodsUnitTest.java diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index f931cf6947..1601bfb804 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -29,7 +29,6 @@ junit5-annotations junit5-migration load-testing-comparison - mockito-2 mockito mockito-simple mocks From 50955510ca2395a6c7c5893023e7677f782dd8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C3=A7im=20Duran?= <49587041+elcim@users.noreply.github.com> Date: Thu, 21 Jul 2022 22:17:26 +0300 Subject: [PATCH 16/34] BAEL-5645 - Scanning Java Annotations at Runtime (#12511) * BAEL-5645 - Annotation scanners using Spring context, Spring core, reflections, java reflection, and Jandex libraries are implemented * BAEL-5645 - Library versions are incremented in pom.xml Co-authored-by: elcimduran --- .../spring-boot-libraries-2/pom.xml | 31 ++++++++ .../scanner/SampleAnnotatedClass.java | 14 ++++ .../annotation/scanner/SampleAnnotation.java | 14 ++++ .../scanner/SampleAnnotationScanner.java | 13 ++++ .../scanner/ScanNotSupportedException.java | 4 + .../scanner/UnexpectedScanException.java | 7 ++ .../jandexlib/JandexScannerService.java | 76 +++++++++++++++++++ .../JavaReflectionsScannerService.java | 58 ++++++++++++++ .../ReflectionsScannerService.java | 45 +++++++++++ .../SpringBeanAnnotationScannerService.java | 52 +++++++++++++ .../SpringCoreAnnotationScannerService.java | 42 ++++++++++ .../SampleAnnotationScannerUnitTest.java | 47 ++++++++++++ 12 files changed, 403 insertions(+) create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java create mode 100644 spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java diff --git a/spring-boot-modules/spring-boot-libraries-2/pom.xml b/spring-boot-modules/spring-boot-libraries-2/pom.xml index f62a341efc..79c090dde5 100644 --- a/spring-boot-modules/spring-boot-libraries-2/pom.xml +++ b/spring-boot-modules/spring-boot-libraries-2/pom.xml @@ -62,6 +62,16 @@ spqr 0.11.2 + + org.reflections + reflections + 0.10.2 + + + org.jboss + jandex + 2.4.3.Final + @@ -92,6 +102,27 @@ + + org.jboss.jandex + jandex-maven-plugin + 1.2.3 + + + compile + make-index + + jandex + + + + + ${project.build.outputDirectory} + + + + + + diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java new file mode 100644 index 0000000000..64849d6a3a --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java @@ -0,0 +1,14 @@ +package com.baeldung.annotation.scanner; + +@SampleAnnotation(name = "SampleAnnotatedClass") +public class SampleAnnotatedClass { + + @SampleAnnotation(name = "annotatedMethod") + public void annotatedMethod() { + //Do something + } + + public void notAnnotatedMethod() { + //Do something + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java new file mode 100644 index 0000000000..212e12e910 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java @@ -0,0 +1,14 @@ +package com.baeldung.annotation.scanner; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target({ METHOD, TYPE }) +@Retention(RUNTIME) +public @interface SampleAnnotation { + String name(); +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java new file mode 100644 index 0000000000..5cc9a2e8b3 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java @@ -0,0 +1,13 @@ +package com.baeldung.annotation.scanner; + +import java.util.List; + +public interface SampleAnnotationScanner { + List scanAnnotatedMethods(); + + List scanAnnotatedClasses(); + + boolean supportsMethodScan(); + + boolean supportsClassScan(); +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java new file mode 100644 index 0000000000..1566dc3fad --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java @@ -0,0 +1,4 @@ +package com.baeldung.annotation.scanner; + +public class ScanNotSupportedException extends RuntimeException{ +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java new file mode 100644 index 0000000000..bd7c129bfd --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java @@ -0,0 +1,7 @@ +package com.baeldung.annotation.scanner; + +public class UnexpectedScanException extends RuntimeException { + public UnexpectedScanException(Throwable ex) { + super(ex); + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java new file mode 100644 index 0000000000..fc10db223e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java @@ -0,0 +1,76 @@ +package com.baeldung.annotation.scanner.jandexlib; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Index; +import org.jboss.jandex.IndexReader; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.UnexpectedScanException; + +@Service +public class JandexScannerService implements SampleAnnotationScanner { + @Value("classpath:META-INF/jandex.idx") + private Resource appFile; + + @Override + public List scanAnnotatedMethods() { + try { + final IndexReader reader = new IndexReader(appFile.getInputStream()); + Index jandexFile = reader.read(); + final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + List annotatedMethods = new ArrayList<>(); + for (AnnotationInstance annotationInstance : appAnnotationList) { + if (annotationInstance.target() + .kind() == AnnotationTarget.Kind.METHOD) { + annotatedMethods.add(annotationInstance.value("name") + .value() + .toString()); + } + } + return Collections.unmodifiableList(annotatedMethods); + } catch (IOException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public List scanAnnotatedClasses() { + try { + final IndexReader reader = new IndexReader(appFile.getInputStream()); + Index jandexFile = reader.read(); + final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + List annotatedClasses = new ArrayList<>(); + for (AnnotationInstance annotationInstance : appAnnotationList) { + if (annotationInstance.target() + .kind() == AnnotationTarget.Kind.CLASS) { + annotatedClasses.add(annotationInstance.value("name") + .value() + .toString()); + } + } + return Collections.unmodifiableList(annotatedClasses); + } catch (IOException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java new file mode 100644 index 0000000000..2833bb1326 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java @@ -0,0 +1,58 @@ +package com.baeldung.annotation.scanner.javareflectionlib; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.UnexpectedScanException; + +@Service +public class JavaReflectionsScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + try { + Class clazz = ClassLoader.getSystemClassLoader() + .loadClass("com.baeldung.annotation.scanner.SampleAnnotatedClass"); + Method[] methods = clazz.getMethods(); + List annotatedMethods = new ArrayList<>(); + for (Method method : methods) { + SampleAnnotation annotation = method.getAnnotation(SampleAnnotation.class); + if (annotation != null) { + annotatedMethods.add(annotation.name()); + } + } + return Collections.unmodifiableList(annotatedMethods); + } catch (ClassNotFoundException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public List scanAnnotatedClasses() { + try { + Class clazz = ClassLoader.getSystemClassLoader() + .loadClass("com.baeldung.annotation.scanner.SampleAnnotatedClass"); + SampleAnnotation classAnnotation = clazz.getAnnotation(SampleAnnotation.class); + List annotatedClasses = new ArrayList<>(); + annotatedClasses.add(classAnnotation.name()); + return Collections.unmodifiableList(annotatedClasses); + } catch (ClassNotFoundException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java new file mode 100644 index 0000000000..82a10e21aa --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java @@ -0,0 +1,45 @@ +package com.baeldung.annotation.scanner.reflectionslib; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.reflections.Reflections; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; + +@Service +public class ReflectionsScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); + Set methods = reflections.getMethodsAnnotatedWith(SampleAnnotation.class); + return methods.stream() + .map(method -> method.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public List scanAnnotatedClasses() { + Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); + Set> types = reflections.getTypesAnnotatedWith(SampleAnnotation.class); + return types.stream() + .map(clazz -> clazz.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java new file mode 100644 index 0000000000..cd31ae686e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java @@ -0,0 +1,52 @@ +package com.baeldung.annotation.scanner.springcontextlib; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.ScanNotSupportedException; + +@Service +public class SpringBeanAnnotationScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + throw new ScanNotSupportedException(); + } + + @Override + public List scanAnnotatedClasses() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(SampleAnnotation.class)); + Set beanDefs = provider.findCandidateComponents("com.baeldung.annotation.scanner"); + List annotatedBeans = new ArrayList<>(); + for (BeanDefinition bd : beanDefs) { + if (bd instanceof AnnotatedBeanDefinition) { + Map annotAttributeMap = ((AnnotatedBeanDefinition) bd).getMetadata() + .getAnnotationAttributes(SampleAnnotation.class.getCanonicalName()); + annotatedBeans.add(annotAttributeMap.get("name") + .toString()); + } + } + return Collections.unmodifiableList(annotatedBeans); + } + + @Override + public boolean supportsMethodScan() { + return false; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java new file mode 100644 index 0000000000..f3421fe46d --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java @@ -0,0 +1,42 @@ +package com.baeldung.annotation.scanner.springcorelib; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.ClassUtils; + +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.SampleAnnotatedClass; +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.ScanNotSupportedException; + +@Service +public class SpringCoreAnnotationScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + final Class userClass = ClassUtils.getUserClass(SampleAnnotatedClass.class); + return Arrays.stream(userClass.getMethods()) + .filter(method -> AnnotationUtils.getAnnotation(method, SampleAnnotation.class) != null) + .map(method -> method.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public List scanAnnotatedClasses() { + throw new ScanNotSupportedException(); + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return false; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java new file mode 100644 index 0000000000..80eca2b4c5 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.annotation.scanner; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SampleAnnotationScannerUnitTest { + @Autowired + private List scannerList; + + @Test + public void givenPackage_whenScanAnnotatedClasses_thenAnnotationValues() { + final List annotatedClasses = scannerList.stream() + .filter(SampleAnnotationScanner::supportsClassScan) + .map(SampleAnnotationScanner::scanAnnotatedClasses) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertNotNull(annotatedClasses); + assertEquals(4, annotatedClasses.size()); + annotatedClasses.forEach(annotValue -> assertEquals("SampleAnnotatedClass", annotValue)); + } + + @Test + public void givenPackage_whenScanAnnotatedMethods_thenAnnotationValues() { + final List annotatedMethods = scannerList.stream() + .filter(SampleAnnotationScanner::supportsMethodScan) + .map(SampleAnnotationScanner::scanAnnotatedMethods) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertNotNull(annotatedMethods); + assertEquals(3, annotatedMethods.size()); + annotatedMethods.forEach(annotValue -> assertEquals("annotatedMethod", annotValue)); + } + +} From 8d894df26adc574c051abf68d45c946e062ddf8e Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Thu, 21 Jul 2022 17:47:35 -0300 Subject: [PATCH 17/34] BAEL-5365 Count in Spring Data MongoDB Repository (#12481) * BAEL-5370 - MongoDB Composite Key First Draft. * removing comments * BAEL-5370 Test could fail if ran in a different order: givenCompositeId_whenSearchingByIdObject_thenFound * BAEL-5370 removing compound index related stuff * removing first insert from assertThrows * first draft * removing Customer2 * first draft * adjustments * removed controlled * fixed formatting on Car --- .../count/SpringBootCountApplication.java | 13 ++ .../boot/count/dao/CarRepository.java | 16 +++ .../com/baeldung/boot/count/data/Car.java | 33 +++++ .../boot/count/service/CountCarService.java | 69 ++++++++++ .../CountCarServiceIntegrationTest.java | 118 ++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java new file mode 100644 index 0000000000..bb7351383c --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/SpringBootCountApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.boot.count; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +@EnableMongoRepositories(basePackages = { "com.baeldung.boot.count" }) +public class SpringBootCountApplication { + public static void main(String... args) { + SpringApplication.run(SpringBootCountApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java new file mode 100644 index 0000000000..b03298852e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/dao/CarRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.boot.count.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; + +import com.baeldung.boot.count.data.Car; + +public interface CarRepository extends MongoRepository { + @Query(value = "{brand: ?0}", count = true) + public long countBrand(String brand); + + Long countByBrand(String brand); + + @Query(value = "{}", count = true) + Long countWithAnnotation(); +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java new file mode 100644 index 0000000000..42b80d70b0 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/data/Car.java @@ -0,0 +1,33 @@ +package com.baeldung.boot.count.data; + +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Car { + private String name; + + private String brand; + + public Car() { + } + + public Car(String brand) { + this.brand = brand; + } + + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java new file mode 100644 index 0000000000..d4685847fb --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/count/service/CountCarService.java @@ -0,0 +1,69 @@ +package com.baeldung.boot.count.service; + +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.count.dao.CarRepository; +import com.baeldung.boot.count.data.Car; + +@Service +public class CountCarService { + + @Autowired + private CarRepository repo; + + @Autowired + private MongoTemplate mongo; + + public List findCars() { + return repo.findAll(); + } + + public Optional findCar(String id) { + return repo.findById(id); + } + + public Car insertCar(Car item) { + return repo.insert(item); + } + + public long getCountWithQueryAnnotation() { + return repo.countWithAnnotation(); + } + + public long getCountWithCrudRepository() { + return repo.count(); + } + + public long getCountBrandWithQueryMethod(String brand) { + return repo.countByBrand(brand); + } + + public long getCountWithExample(Car item) { + return repo.count(Example.of(item)); + } + + public long getCountWithExampleCriteria(Car item) { + Query query = new Query(); + query.addCriteria(Criteria.byExample(item)); + return mongo.count(query, Car.class); + } + + public long getCountBrandWithQueryAnnotation(String brand) { + return repo.countBrand(brand); + } + + public long getCountBrandWithCriteria(String brand) { + Query query = new Query(); + query.addCriteria(Criteria.where("brand") + .is(brand)); + return mongo.count(query, Car.class); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java new file mode 100644 index 0000000000..421ecd3a34 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/count/service/CountCarServiceIntegrationTest.java @@ -0,0 +1,118 @@ +package com.baeldung.boot.count.service; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.count.data.Car; + +@SpringBootTest +@DirtiesContext +@RunWith(SpringRunner.class) +public class CountCarServiceIntegrationTest { + @Autowired + private CountCarService service; + + Car car1 = new Car("B-A"); + + @Before + public void init() { + service.insertCar(car1); + service.insertCar(new Car("B-B")); + service.insertCar(new Car("B-C")); + } + + @Test + public void givenAllDocs_whenQueryAnnotationCount_thenCountEqualsSize() { + List all = service.findCars(); + + long count = service.getCountWithQueryAnnotation(); + + assertEquals(count, all.size()); + } + + @Test + public void givenAllDocs_whenCrudRepositoryCount_thenCountEqualsSize() { + List all = service.findCars(); + + long count = service.getCountWithCrudRepository(); + + assertEquals(count, all.size()); + } + + @Test + public void givenFilteredDocs_whenCriteriaCountByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithCriteria(filter); + + assertEquals(count, all); + } + + @Test + public void givenQueryAnnotation_whenCountingByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithQueryAnnotation(filter); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenQueryMethodCountByBrand_thenCountEqualsSize() { + String filter = "B-A"; + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(filter)) + .count(); + + long count = service.getCountBrandWithQueryMethod(filter); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenExampleCount_thenCountEqualsSize() { + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(car1.getBrand())) + .count(); + + long count = service.getCountWithExample(car1); + + assertEquals(count, all); + } + + @Test + public void givenFilteredDocs_whenExampleCriteriaCount_thenCountEqualsSize() { + long all = service.findCars() + .stream() + .filter(car -> car.getBrand() + .equals(car1.getBrand())) + .count(); + + long count = service.getCountWithExampleCriteria(car1); + + assertEquals(count, all); + } +} From 6b8313682e2bcb8c5e238c0605792eb7e1e8738f Mon Sep 17 00:00:00 2001 From: Kai Yuan Date: Fri, 22 Jul 2022 04:58:46 +0200 Subject: [PATCH 18/34] BAEL-5693 rm whitespace from a string (#12515) --- .../RemoveWhitespaceUnitTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 core-java-modules/core-java-string-operations-4/src/test/java/com/baeldung/removewhitespace/RemoveWhitespaceUnitTest.java diff --git a/core-java-modules/core-java-string-operations-4/src/test/java/com/baeldung/removewhitespace/RemoveWhitespaceUnitTest.java b/core-java-modules/core-java-string-operations-4/src/test/java/com/baeldung/removewhitespace/RemoveWhitespaceUnitTest.java new file mode 100644 index 0000000000..f749484ba9 --- /dev/null +++ b/core-java-modules/core-java-string-operations-4/src/test/java/com/baeldung/removewhitespace/RemoveWhitespaceUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.removewhitespace; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class RemoveWhitespaceUnitTest { + private final String myString = " I am a wonderful String ! "; + + @Test + void givenStringWithWhitespace_whenRemoveAllWhitespace_shouldGetExpectedResult() { + String result = myString.replaceAll("\\s", ""); + assertThat(result).isEqualTo("IamawonderfulString!"); + } + + @Test + void givenStringWithWhitespace_whenRemoveAllWhitespaceUsingStringUtils_shouldGetExpectedResult() { + String result = StringUtils.deleteWhitespace(myString); + assertThat(result).isEqualTo("IamawonderfulString!"); + } + + @Test + void givenStringWithWhitespace_whenReplaceConsecutiveSpacesWithSingleSpace_shouldGetExpectedResult() { + String result = myString.replaceAll("\\s+", " "); + assertThat(result).isEqualTo(" I am a wonderful String ! "); + assertThat(result.trim()).isEqualTo("I am a wonderful String !"); + } + + @Test + void givenStringWithWhitespace_whenNormalizeWithApacheCommons_shouldGetExpectedResult() { + String result = StringUtils.normalizeSpace(myString); + assertThat(result).isEqualTo("I am a wonderful String !"); + } +} From 735f657223734e017187b4f9b4dae7e930624af4 Mon Sep 17 00:00:00 2001 From: Haroon Khan Date: Fri, 22 Jul 2022 16:06:46 +0100 Subject: [PATCH 19/34] [JAVA-13130] Logging cleanup --- .../src/test/resources/logback-test.xml | 4 ++++ .../exception/detachedentity/HibernateUtil.java | 3 ++- .../src/test/resources/logback-test.xml | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 persistence-modules/hibernate-exceptions/src/test/resources/logback-test.xml diff --git a/libraries-security/src/test/resources/logback-test.xml b/libraries-security/src/test/resources/logback-test.xml index 8d4771e308..fcbdb8b5f7 100644 --- a/libraries-security/src/test/resources/logback-test.xml +++ b/libraries-security/src/test/resources/logback-test.xml @@ -6,6 +6,10 @@ + + + + diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/detachedentity/HibernateUtil.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/detachedentity/HibernateUtil.java index 0420755354..a7b1f496d9 100644 --- a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/detachedentity/HibernateUtil.java +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/detachedentity/HibernateUtil.java @@ -24,7 +24,8 @@ public class HibernateUtil { settings.put(Environment.USER, "sa"); settings.put(Environment.PASS, ""); settings.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect"); - settings.put(Environment.SHOW_SQL, "true"); + // enable to show Hibernate generated SQL + settings.put(Environment.SHOW_SQL, "false"); settings.put(Environment.FORMAT_SQL, "true"); settings.put(Environment.USE_SQL_COMMENTS, "true"); settings.put(Environment.HBM2DDL_AUTO, "update"); diff --git a/persistence-modules/hibernate-exceptions/src/test/resources/logback-test.xml b/persistence-modules/hibernate-exceptions/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..5d5620b2c1 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + + + + + \ No newline at end of file From a4691406f2b391651ca0826ae5afb2f4501280da Mon Sep 17 00:00:00 2001 From: victorsempere Date: Mon, 25 Jul 2022 05:51:00 +0200 Subject: [PATCH 20/34] BAEL-5328 (#12457) * BAEL-5328 First draft of the code to the article: https://drafts.baeldung.com/wp-admin/post.php?post=136328&action=edit * BAEL-5328 Fixed comment. Used entry point instead of endpoint * BAEL-5328 Added SecurityFilterChain configuration to allow requests to: * "/api/auth/**", "/swagger-ui-custom.html" ,"/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**", "/webjars/**", "/swagger-ui/index.html","/api-docs/**" As the spring-boot-starter-security has been started we need to add it to keep this article, simple. Fixed description of the login() method for the 200 httpstatus response * BAEL-5328 Added required attribute in @RequestBody of the login() method * BAEL-5328 Code formatting --- ...efaultGlobalSecuritySchemeApplication.java | 32 ++++++ ...GlobalSecuritySchemeOpenApiController.java | 61 +++++++++++ .../dto/ApplicationExceptionDto.java | 26 +++++ .../dto/LoginDto.java | 103 ++++++++++++++++++ .../dto/PingResponseDto.java | 84 ++++++++++++++ .../dto/TokenDto.java | 57 ++++++++++ 6 files changed, 363 insertions(+) create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/DefaultGlobalSecuritySchemeApplication.java create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/controller/DefaultGlobalSecuritySchemeOpenApiController.java create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/ApplicationExceptionDto.java create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/LoginDto.java create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/PingResponseDto.java create mode 100644 spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/TokenDto.java diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/DefaultGlobalSecuritySchemeApplication.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/DefaultGlobalSecuritySchemeApplication.java new file mode 100644 index 0000000000..1ce81a1e83 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/DefaultGlobalSecuritySchemeApplication.java @@ -0,0 +1,32 @@ +package com.baeldung.defaultglobalsecurityscheme; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityScheme; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info(title = "Apply Default Global SecurityScheme in springdoc-openapi", version = "1.0.0"), security = { @SecurityRequirement(name = "api_key") }) +@SecurityScheme(type = SecuritySchemeType.APIKEY, name = "api_key", in = SecuritySchemeIn.HEADER) +public class DefaultGlobalSecuritySchemeApplication { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.antMatchers("/api/auth/**", "/swagger-ui-custom.html", "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**", "/webjars/**", "/swagger-ui/index.html", "/api-docs/**") + .permitAll() + .anyRequest() + .authenticated()) + .build(); + } + + public static void main(String[] args) { + SpringApplication.run(DefaultGlobalSecuritySchemeApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/controller/DefaultGlobalSecuritySchemeOpenApiController.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/controller/DefaultGlobalSecuritySchemeOpenApiController.java new file mode 100644 index 0000000000..4ad7a2a2c3 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/controller/DefaultGlobalSecuritySchemeOpenApiController.java @@ -0,0 +1,61 @@ +package com.baeldung.defaultglobalsecurityscheme.controller; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import javax.validation.Valid; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.defaultglobalsecurityscheme.dto.LoginDto; +import com.baeldung.defaultglobalsecurityscheme.dto.ApplicationExceptionDto; +import com.baeldung.defaultglobalsecurityscheme.dto.PingResponseDto; +import com.baeldung.defaultglobalsecurityscheme.dto.TokenDto; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; + +@RestController +@RequestMapping("/") +public class DefaultGlobalSecuritySchemeOpenApiController { + @RequestMapping(method = RequestMethod.POST, value = "/login", produces = { "application/json" }, consumes = { "application/json" }) + @Operation(operationId = "login", responses = { + @ApiResponse(responseCode = "200", description = "api_key to be used in the secured-ping entry point", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = TokenDto.class)) }), + @ApiResponse(responseCode = "401", description = "Unauthorized request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }) }) + @SecurityRequirements() + public ResponseEntity login(@Parameter(name = "LoginDto", description = "Login") @Valid @RequestBody(required = true) LoginDto loginDto) { + TokenDto token = new TokenDto(); + token.setRaw("Generated Token"); + return ResponseEntity.ok(token); + } + + @Operation(operationId = "ping", responses = { + @ApiResponse(responseCode = "200", description = "Ping that needs an api_key attribute in the header", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = PingResponseDto.class), examples = { @ExampleObject(value = "{ pong: '2022-06-17T18:30:33.465+02:00' }") }) }), + @ApiResponse(responseCode = "401", description = "Unauthorized request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }), + @ApiResponse(responseCode = "403", description = "Forbidden request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }) }) + @RequestMapping(method = RequestMethod.GET, value = "/ping", produces = { "application/json" }) + public ResponseEntity ping(@RequestHeader(name = "api_key", required = false) String api_key) { + int year = 2000; + int month = 1; + int dayOfMonth = 1; + int hour = 0; + int minute = 0; + int second = 0; + int nanoSeccond = 0; + ZoneOffset offset = ZoneOffset.UTC; + PingResponseDto response = new PingResponseDto(); + response.setPong(OffsetDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoSeccond, offset)); + return ResponseEntity.ok(response); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/ApplicationExceptionDto.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/ApplicationExceptionDto.java new file mode 100644 index 0000000000..5fb63793c4 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/ApplicationExceptionDto.java @@ -0,0 +1,26 @@ +package com.baeldung.defaultglobalsecurityscheme.dto; + +public class ApplicationExceptionDto { + private long errorCode; + private String description; + + public ApplicationExceptionDto() { + super(); + } + + public long getErrorCode() { + return errorCode; + } + + public void setErrorCode(long errorCode) { + this.errorCode = errorCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/LoginDto.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/LoginDto.java new file mode 100644 index 0000000000..cf88cc4d98 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/LoginDto.java @@ -0,0 +1,103 @@ +package com.baeldung.defaultglobalsecurityscheme.dto; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * LoginDto + */ + +@JsonTypeName("Login") +public class LoginDto { + + @JsonProperty("user") + private String user; + + @JsonProperty("pass") + private String pass; + + public LoginDto user(String user) { + this.user = user; + return this; + } + + /** + * Get user + * @return user + */ + + @Schema(name = "user", required = true) + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public LoginDto pass(String pass) { + this.pass = pass; + return this; + } + + /** + * Get pass + * @return pass + */ + + @Schema(name = "pass", required = true) + public String getPass() { + return pass; + } + + public void setPass(String pass) { + this.pass = pass; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LoginDto login = (LoginDto) o; + return Objects.equals(this.user, login.user) && Objects.equals(this.pass, login.pass); + } + + @Override + public int hashCode() { + return Objects.hash(user, pass); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class LoginDto {\n"); + sb.append(" user: ") + .append(toIndentedString(user)) + .append("\n"); + sb.append(" pass: ") + .append(toIndentedString(pass)) + .append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString() + .replace("\n", "\n "); + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/PingResponseDto.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/PingResponseDto.java new file mode 100644 index 0000000000..0d367785d8 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/PingResponseDto.java @@ -0,0 +1,84 @@ +package com.baeldung.defaultglobalsecurityscheme.dto; + +import java.time.OffsetDateTime; +import java.util.Objects; + +import javax.validation.Valid; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * SecuredPingResponseDto + */ + +@JsonTypeName("PingResponse") +public class PingResponseDto { + + @JsonProperty("pong") + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private OffsetDateTime pong; + + public PingResponseDto pong(OffsetDateTime pong) { + this.pong = pong; + return this; + } + + /** + * Get pong + * @return pong + */ + @Valid + @Schema(name = "pong", required = false) + public OffsetDateTime getPong() { + return pong; + } + + public void setPong(OffsetDateTime pong) { + this.pong = pong; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PingResponseDto securedPingResponse = (PingResponseDto) o; + return Objects.equals(this.pong, securedPingResponse.pong); + } + + @Override + public int hashCode() { + return Objects.hash(pong); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PingResponseDto {\n"); + sb.append(" pong: ") + .append(toIndentedString(pong)) + .append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString() + .replace("\n", "\n "); + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/TokenDto.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/TokenDto.java new file mode 100644 index 0000000000..d8f7daa09c --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/defaultglobalsecurityscheme/dto/TokenDto.java @@ -0,0 +1,57 @@ +package com.baeldung.defaultglobalsecurityscheme.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * LoginDto + */ + +@JsonTypeName("Token") +public class TokenDto { + + @JsonProperty("raw") + private String raw; + + @Schema(name = "raw", example = "app token") + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } + + @Override + public String toString() { + return "TokenDto [raw=" + raw + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((raw == null) ? 0 : raw.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TokenDto other = (TokenDto) obj; + if (raw == null) { + if (other.raw != null) + return false; + } else if (!raw.equals(other.raw)) + return false; + return true; + } + +} From bda1a947f7cdfa98605caf63c981db951afc90fe Mon Sep 17 00:00:00 2001 From: panagiotiskakos Date: Mon, 25 Jul 2022 15:47:51 +0300 Subject: [PATCH 21/34] [JAVA-13410] Replaced @Mappings with sequential @Mapping --- .../main/java/com/baeldung/mapper/EmployeeMapper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mapstruct/src/main/java/com/baeldung/mapper/EmployeeMapper.java b/mapstruct/src/main/java/com/baeldung/mapper/EmployeeMapper.java index 8e00103d0e..716b05c7d9 100644 --- a/mapstruct/src/main/java/com/baeldung/mapper/EmployeeMapper.java +++ b/mapstruct/src/main/java/com/baeldung/mapper/EmployeeMapper.java @@ -6,17 +6,20 @@ import com.baeldung.entity.Division; import com.baeldung.entity.Employee; import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import java.util.List; @Mapper public interface EmployeeMapper { - @Mappings({ @Mapping(target = "employeeId", source = "entity.id"), @Mapping(target = "employeeName", source = "entity.name"), @Mapping(target = "employeeStartDt", source = "entity.startDt", dateFormat = "dd-MM-yyyy HH:mm:ss") }) + @Mapping(target = "employeeId", source = "entity.id") + @Mapping(target = "employeeName", source = "entity.name") + @Mapping(target = "employeeStartDt", source = "entity.startDt", dateFormat = "dd-MM-yyyy HH:mm:ss") EmployeeDTO employeeToEmployeeDTO(Employee entity); - @Mappings({ @Mapping(target = "id", source = "dto.employeeId"), @Mapping(target = "name", source = "dto.employeeName"), @Mapping(target = "startDt", source = "dto.employeeStartDt", dateFormat = "dd-MM-yyyy HH:mm:ss") }) + @Mapping(target = "id", source = "dto.employeeId") + @Mapping(target = "name", source = "dto.employeeName") + @Mapping(target = "startDt", source = "dto.employeeStartDt", dateFormat = "dd-MM-yyyy HH:mm:ss") Employee employeeDTOtoEmployee(EmployeeDTO dto); DivisionDTO divisionToDivisionDTO(Division entity); From e12f0d064f3e7496221d16393477b6794c15fed4 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Mon, 25 Jul 2022 12:27:02 -0300 Subject: [PATCH 22/34] JAVA-13615 GitHub Issue: The code for A* is in the src/test/java directory, not the src/main/java directory --- .../{test => main}/java/com/baeldung/algorithms/astar/Graph.java | 0 .../java/com/baeldung/algorithms/astar/GraphNode.java | 0 .../java/com/baeldung/algorithms/astar/RouteFinder.java | 0 .../java/com/baeldung/algorithms/astar/RouteNode.java | 0 .../{test => main}/java/com/baeldung/algorithms/astar/Scorer.java | 0 .../baeldung/algorithms/astar/underground/HaversineScorer.java | 0 .../java/com/baeldung/algorithms/astar/underground/Station.java | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/Graph.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/GraphNode.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/RouteFinder.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/RouteNode.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/Scorer.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java (100%) rename algorithms-modules/algorithms-miscellaneous-2/src/{test => main}/java/com/baeldung/algorithms/astar/underground/Station.java (100%) diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Graph.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/Graph.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Graph.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/Graph.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/GraphNode.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/GraphNode.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/GraphNode.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/GraphNode.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteFinder.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/RouteFinder.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteFinder.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/RouteFinder.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteNode.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/RouteNode.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/RouteNode.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/RouteNode.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Scorer.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/Scorer.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/Scorer.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/Scorer.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/underground/HaversineScorer.java diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/Station.java b/algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/underground/Station.java similarity index 100% rename from algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/Station.java rename to algorithms-modules/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/astar/underground/Station.java From 2c901e1d677623c63ed17abc9dfa8c2d26cae9c3 Mon Sep 17 00:00:00 2001 From: "thibault.faure" Date: Sat, 16 Jul 2022 00:57:06 +0200 Subject: [PATCH 23/34] BAEL-5663 code for the filter java stream to only one element article --- core-java-modules/core-java-streams-4/pom.xml | 10 +++ .../filteronlyoneelement/BenchmarkRunner.java | 56 ++++++++++++ .../filteronlyoneelement/FilterUtils.java | 50 +++++++++++ .../FilterUtilsUnitTest.java | 88 +++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java create mode 100644 core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java create mode 100644 core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index beed277f78..65de1d666c 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -43,6 +43,16 @@ 3.23.1 test + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-generator.version} + diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java new file mode 100644 index 0000000000..327bdc4df3 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java @@ -0,0 +1,56 @@ +package com.baeldung.streams.filteronlyoneelement; + +import java.util.function.Predicate; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +public class BenchmarkRunner { + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @State(Scope.Benchmark) + public static class MyState { + final Stream getIntegers() { + return IntStream.range(1, 1000000) + .boxed(); + } + + final Predicate PREDICATE = i -> i == 751879; + } + + @Benchmark + public void evaluateFindUniqueElementMatchingPredicate_WithReduction(Blackhole blackhole, MyState state) { + blackhole.consume(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(state.getIntegers(), state.PREDICATE)); + } + + @Benchmark + public void evaluateFindUniqueElementMatchingPredicate_WithCollectingAndThen(Blackhole blackhole, MyState state) { + blackhole.consume(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(state.getIntegers(), state.PREDICATE)); + } + + @Benchmark + public void evaluateGetUniqueElementMatchingPredicate_WithReduction(Blackhole blackhole, MyState state) { + try { + FilterUtils.getUniqueElementMatchingPredicate_WithReduction(state.getIntegers(), state.PREDICATE); + } catch (IllegalStateException exception) { + blackhole.consume(exception); + } + } + + @Benchmark + public void evaluateGetUniqueElementMatchingPredicate_WithCollectingAndThen(Blackhole blackhole, MyState state) { + try { + FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(state.getIntegers(), state.PREDICATE); + } catch (IllegalStateException exception) { + blackhole.consume(exception); + } + } + +} diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java new file mode 100644 index 0000000000..65905a7bc4 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java @@ -0,0 +1,50 @@ +package com.baeldung.streams.filteronlyoneelement; + +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FilterUtils { + + public static Optional findUniqueElementMatchingPredicate_WithReduction(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.reducing((a, b) -> null)); + } + + public static T getUniqueElementMatchingPredicate_WithReduction(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .reduce((a, b) -> { + throw new IllegalStateException("Too many elements match the predicate"); + }) + .orElseThrow(() -> new IllegalStateException("No element matches the predicate")); + } + + public static Optional findUniqueElementMatchingPredicate_WithCollectingAndThen(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.collectingAndThen(Collectors.toList(), list -> Optional.ofNullable(findUniqueElement(list)))); + } + + private static T findUniqueElement(List elements) { + if (elements.size() == 1) { + return elements.get(0); + } + return null; + } + + public static T getUniqueElementMatchingPredicate_WithCollectingAndThen(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.collectingAndThen(Collectors.toList(), FilterUtils::getUniqueElement)); + } + + private static T getUniqueElement(List elements) { + if (elements.size() > 1) { + throw new IllegalStateException("Too many elements match the predicate"); + } else if (elements.size() == 0) { + throw new IllegalStateException("No element matches the predicate"); + } + return elements.get(0); + } + +} diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java new file mode 100644 index 0000000000..531dcc5abb --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java @@ -0,0 +1,88 @@ +package com.baeldung.streams.filteronlyoneelement; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class FilterUtilsUnitTest { + + private static final Predicate IS_STRICTLY_GREATER_THAN5 = i -> i > 5; + private static final Predicate IS_STRICTLY_GREATER_THAN4 = i -> i > 4; + private static final Predicate IS_STRICTLY_GREATER_THAN3 = i -> i > 3; + + private Stream getIntegers() { + return Stream.of(1, 2, 3, 4, 5); + } + + @Test + void givenNoElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenNoneFound() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN5) + .isEmpty()); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN3) + .isEmpty()); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenFindsIt() { + assertEquals(5, FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN4) + .get()); + } + + @Test + void givenNoElementMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithReduction_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN5)); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithReduction_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN3)); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenGetIt() { + assertEquals(5, FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN4)); + } + + @Test + void givenNoElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN5) + .isEmpty()); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN3) + .isEmpty()); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenFindsIt() { + assertEquals(5, FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN4) + .get()); + } + + @Test + void givenNoElementMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithCollectingAndThen_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN5)); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithCollectingAndThen_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN3)); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenGetIt() { + assertEquals(5, FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN4)); + } + +} From 324cb08a48bbf0e5a08a70947c7e136d236cdd28 Mon Sep 17 00:00:00 2001 From: panagiotiskakos Date: Tue, 26 Jul 2022 08:14:19 +0300 Subject: [PATCH 24/34] [JAVA-8691] --- persistence-modules/spring-data-jpa-enterprise/pom.xml | 2 +- .../src/test/resources/application-tc-jdbc.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/persistence-modules/spring-data-jpa-enterprise/pom.xml b/persistence-modules/spring-data-jpa-enterprise/pom.xml index 587261dccc..16294cd3cc 100644 --- a/persistence-modules/spring-data-jpa-enterprise/pom.xml +++ b/persistence-modules/spring-data-jpa-enterprise/pom.xml @@ -87,7 +87,7 @@ 1.3.1.Final - 1.12.2 + 1.17.3 \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/resources/application-tc-jdbc.yml b/persistence-modules/spring-data-jpa-enterprise/src/test/resources/application-tc-jdbc.yml index ad5906fa6e..d340e29bd0 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/resources/application-tc-jdbc.yml +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/resources/application-tc-jdbc.yml @@ -1,6 +1,7 @@ spring: datasource: url: jdbc:tc:postgresql:11.1:///integration-tests-db + driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver jpa: hibernate: ddl-auto: create \ No newline at end of file From 80a4ca1c2b82e0a756b5288f24b7d171ed4b4e33 Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Tue, 26 Jul 2022 12:41:56 +0530 Subject: [PATCH 25/34] JAVA-13625 Updated/upgraded Mockito Annotations Code --- testing-modules/mockito-simple/pom.xml | 33 ++++------------- .../java/com/baeldung/mockito/MockFinals.java | 35 ------------------- .../mockito/MockitoAnnotationUnitTest.java | 25 ++++++++----- ...ionsInitWithMockitoJUnitRuleUnitTest.java} | 2 +- ...kitoAnnotationsInjectIntoSpyUnitTest.java} | 5 ++- 5 files changed, 26 insertions(+), 74 deletions(-) delete mode 100644 testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinals.java rename testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/{MockitoInitWithMockitoJUnitRuleUnitTest.java => MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java} (90%) rename testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/{MockitoInjectIntoSpyUnitTest.java => MockitoAnnotationsInjectIntoSpyUnitTest.java} (84%) diff --git a/testing-modules/mockito-simple/pom.xml b/testing-modules/mockito-simple/pom.xml index af0c63520a..6b056d09b5 100644 --- a/testing-modules/mockito-simple/pom.xml +++ b/testing-modules/mockito-simple/pom.xml @@ -29,35 +29,16 @@ spring-context ${spring-framework.version} - - org.springframework.data - spring-data-jpa - ${spring-data.version} - - - org.eclipse.persistence - javax.persistence - ${javax.persistence.version} - + org.apache.commons commons-lang3 ${commons-lang3.version} + - - org.springframework.boot - spring-boot-starter - ${spring-boot.version} - test - - - org.springframework.boot - spring-boot-starter-test - ${spring-boot.version} - test - + org.mockito mockito-junit-jupiter @@ -77,12 +58,10 @@ - 2.0.4.RELEASE - 5.0.8.RELEASE - 2.0.9.RELEASE + 2.6.4 + 5.3.20 - 2.0.2 - 2.1.1 + 4.6.1 diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinals.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinals.java deleted file mode 100644 index 6ff791ae06..0000000000 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinals.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.mockito; - -import org.junit.Test; - -import static org.junit.Assert.assertNotEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MockFinals { - - @Test - public void whenMockFinalClassMockWorks() { - - FinalList finalList = new FinalList(); - - FinalList mock = mock(FinalList.class); - when(mock.size()).thenReturn(2); - - assertNotEquals(mock.size(), finalList.size()); - - } - - @Test - public void whenMockFinalMethodMockWorks() { - - MyList myList = new MyList(); - - MyList mock = mock(MyList.class); - when(mock.finalMethod()).thenReturn(1); - - assertNotEquals(mock.finalMethod(), myList.finalMethod()); - } - - - } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java index 1d3d6b1428..bd68afac75 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java @@ -1,16 +1,22 @@ package com.baeldung.mockito; -import org.junit.Before; -import org.junit.Test; -import org.mockito.*; +import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; -//@RunWith(MockitoJUnitRunner.class) +@RunWith(MockitoJUnitRunner.class) public class MockitoAnnotationUnitTest { @Mock @@ -19,11 +25,14 @@ public class MockitoAnnotationUnitTest { @Spy private List spiedList = new ArrayList<>(); + // Use either @RunWith(MockitoJUnitRunner.class) or manually openMocks in the @Before method + /* @Before public void init() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } - + */ + // tests @Test @@ -91,7 +100,7 @@ public class MockitoAnnotationUnitTest { ArgumentCaptor argCaptor; @Test - public void whenUseCaptorAnnotation_thenTheSam() { + public void whenUseCaptorAnnotation_thenTheSame() { mockedList.add("one"); Mockito.verify(mockedList).add(argCaptor.capture()); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInitWithMockitoJUnitRuleUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java similarity index 90% rename from testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInitWithMockitoJUnitRuleUnitTest.java rename to testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java index 1bbe13ec84..88a9410101 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInitWithMockitoJUnitRuleUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java @@ -11,7 +11,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; -public class MockitoInitWithMockitoJUnitRuleUnitTest { +public class MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest { @Rule public MockitoRule initRule = MockitoJUnit.rule(); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInjectIntoSpyUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java similarity index 84% rename from testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInjectIntoSpyUnitTest.java rename to testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java index d6a11bbc7d..9d3a00f8b9 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoInjectIntoSpyUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java @@ -5,18 +5,17 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.*; -import org.mockito.junit.MockitoJUnitRunner; import java.util.Map; import static org.junit.Assert.assertEquals; @RunWith(MockitoJUnitRunner.class) -public class MockitoInjectIntoSpyUnitTest { +public class MockitoAnnotationsInjectIntoSpyUnitTest { @Before public void init() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); spyDic = Mockito.spy(new MyDictionary(wordMap)); } From 4dab3eb46d82c34060ad4dbf77cdb2eb49ea2d11 Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Tue, 26 Jul 2022 12:58:41 +0530 Subject: [PATCH 26/34] JAVA-12033 Upgraded assertion libraries and minor cleanup --- ...a => MockitoWhenThenExamplesUnitTest.java} | 74 +++++++++---------- 1 file changed, 36 insertions(+), 38 deletions(-) rename testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/{MockitoConfigExamplesUnitTest.java => MockitoWhenThenExamplesUnitTest.java} (84%) diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoConfigExamplesUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java similarity index 84% rename from testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoConfigExamplesUnitTest.java rename to testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java index 6a5f797b41..d110fff00f 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoConfigExamplesUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java @@ -1,19 +1,18 @@ package com.baeldung.mockito; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + import org.junit.Test; import org.mockito.Mockito; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.*; - -import com.baeldung.mockito.MyList; - -public class MockitoConfigExamplesUnitTest { - - // tests +public class MockitoWhenThenExamplesUnitTest { @Test public final void whenMockReturnBehaviorIsConfigured_thenBehaviorIsVerified() { @@ -21,7 +20,7 @@ public class MockitoConfigExamplesUnitTest { when(listMock.add(anyString())).thenReturn(false); final boolean added = listMock.add(randomAlphabetic(6)); - assertThat(added, is(false)); + assertThat(added).isFalse(); } @Test @@ -30,7 +29,7 @@ public class MockitoConfigExamplesUnitTest { doReturn(false).when(listMock).add(anyString()); final boolean added = listMock.add(randomAlphabetic(6)); - assertThat(added, is(false)); + assertThat(added).isFalse(); } @Test(expected = IllegalStateException.class) @@ -41,14 +40,6 @@ public class MockitoConfigExamplesUnitTest { listMock.add(randomAlphabetic(6)); } - @Test(expected = NullPointerException.class) - public final void whenMethodHasNoReturnType_whenConfiguringBehaviorOfMethod_thenPossible() { - final MyList listMock = Mockito.mock(MyList.class); - doThrow(NullPointerException.class).when(listMock).clear(); - - listMock.clear(); - } - @Test public final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingOnlyOnce_thenNoExceptionIsThrown() { final MyList listMock = Mockito.mock(MyList.class); @@ -56,6 +47,14 @@ public class MockitoConfigExamplesUnitTest { listMock.add(randomAlphabetic(6)); } + + @Test(expected = NullPointerException.class) + public final void whenMethodHasNoReturnType_whenConfiguringBehaviorOfMethod_thenPossible() { + final MyList listMock = Mockito.mock(MyList.class); + doThrow(NullPointerException.class).when(listMock).clear(); + + listMock.clear(); + } @Test(expected = IllegalStateException.class) public final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingTwice_thenExceptionIsThrown() { @@ -66,23 +65,6 @@ public class MockitoConfigExamplesUnitTest { listMock.add(randomAlphabetic(6)); } - @Test - public final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMethodIsCalled() { - final MyList listMock = Mockito.mock(MyList.class); - when(listMock.size()).thenCallRealMethod(); - - assertThat(listMock.size(), equalTo(1)); - } - - @Test - public final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMethodIsCalled() { - final MyList listMock = Mockito.mock(MyList.class); - doAnswer(invocation -> "Always the same").when(listMock).get(anyInt()); - - final String element = listMock.get(1); - assertThat(element, is(equalTo("Always the same"))); - } - @Test(expected = NullPointerException.class) public final void givenSpy_whenConfiguringBehaviorOfSpy_thenCorrectlyConfigured() { final MyList instance = new MyList(); @@ -91,5 +73,21 @@ public class MockitoConfigExamplesUnitTest { doThrow(NullPointerException.class).when(spy).size(); spy.size(); } + + @Test + public final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMethodIsCalled() { + final MyList listMock = Mockito.mock(MyList.class); + when(listMock.size()).thenCallRealMethod(); + assertThat(listMock).hasSize(1); + } + + @Test + public final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMethodIsCalled() { + final MyList listMock = Mockito.mock(MyList.class); + doAnswer(invocation -> "Always the same").when(listMock).get(anyInt()); + + final String element = listMock.get(1); + assertThat(element).isEqualTo("Always the same"); + } } From 4e13672a9369c6dc6835ee5cc4133877ae0a62ae Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Tue, 26 Jul 2022 18:23:50 +0530 Subject: [PATCH 27/34] JAVA-13627 Removed MockitoMockIntegrationTest as it was a duplicate, other cleanup and API upgrades --- .../mockito/MockitoMockIntegrationTest.java | 69 ------------------- .../baeldung/mockito/MockitoMockUnitTest.java | 46 ++++++------- 2 files changed, 22 insertions(+), 93 deletions(-) delete mode 100644 testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockIntegrationTest.java diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockIntegrationTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockIntegrationTest.java deleted file mode 100644 index 944d41316d..0000000000 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockIntegrationTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.baeldung.mockito; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.MockSettings; -import org.mockito.exceptions.verification.TooFewActualInvocations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.*; - -public class MockitoMockIntegrationTest { - - private static class CustomAnswer implements Answer { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - return false; - } - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Test - public void whenUsingSimpleMock_thenCorrect() { - MyList listMock = mock(MyList.class); - when(listMock.add(anyString())).thenReturn(false); - boolean added = listMock.add(randomAlphabetic(6)); - - verify(listMock).add(anyString()); - assertThat(added, is(false)); - } - - @Test - public void whenUsingMockWithName_thenCorrect() { - MyList listMock = mock(MyList.class, "myMock"); - when(listMock.add(anyString())).thenReturn(false); - listMock.add(randomAlphabetic(6)); - - thrown.expect(TooFewActualInvocations.class); - thrown.expectMessage(containsString("myMock.add")); - - verify(listMock, times(2)).add(anyString()); - } - - @Test - public void whenUsingMockWithAnswer_thenCorrect() { - MyList listMock = mock(MyList.class, new CustomAnswer()); - boolean added = listMock.add(randomAlphabetic(6)); - - verify(listMock).add(anyString()); - assertThat(added, is(false)); - } - - @Test - public void whenUsingMockWithSettings_thenCorrect() { - MockSettings customSettings = withSettings().defaultAnswer(new CustomAnswer()); - MyList listMock = mock(MyList.class, customSettings); - boolean added = listMock.add(randomAlphabetic(6)); - - verify(listMock).add(anyString()); - assertThat(added, is(false)); - } -} \ No newline at end of file diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java index 27af3d8d1e..80f01338e6 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java @@ -1,15 +1,16 @@ package com.baeldung.mockito; -import static org.mockito.Mockito.*; - -import static org.junit.Assert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.containsString; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; import org.junit.Test; -import org.junit.Rule; -import org.junit.rules.ExpectedException; import org.mockito.MockSettings; import org.mockito.exceptions.verification.TooFewActualInvocations; import org.mockito.invocation.InvocationOnMock; @@ -17,16 +18,6 @@ import org.mockito.stubbing.Answer; public class MockitoMockUnitTest { - private static class CustomAnswer implements Answer { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - return false; - } - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void whenUsingSimpleMock_thenCorrect() { MyList listMock = mock(MyList.class); @@ -34,7 +25,7 @@ public class MockitoMockUnitTest { boolean added = listMock.add(randomAlphabetic(6)); verify(listMock).add(anyString()); - assertThat(added, is(false)); + assertThat(added).isFalse(); } @Test @@ -43,19 +34,26 @@ public class MockitoMockUnitTest { when(listMock.add(anyString())).thenReturn(false); listMock.add(randomAlphabetic(6)); - thrown.expect(TooFewActualInvocations.class); - thrown.expectMessage(containsString("myMock.add")); - - verify(listMock, times(2)).add(anyString()); + Throwable exceptionThrown = assertThrows(TooFewActualInvocations.class, + () -> verify(listMock, times(2)).add(anyString())); + + assertThat(exceptionThrown.getMessage()).contains("myMock.add"); } + private static class CustomAnswer implements Answer { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return false; + } + } + @Test public void whenUsingMockWithAnswer_thenCorrect() { MyList listMock = mock(MyList.class, new CustomAnswer()); boolean added = listMock.add(randomAlphabetic(6)); verify(listMock).add(anyString()); - assertThat(added, is(false)); + assertThat(added).isFalse(); } @Test @@ -65,6 +63,6 @@ public class MockitoMockUnitTest { boolean added = listMock.add(randomAlphabetic(6)); verify(listMock).add(anyString()); - assertThat(added, is(false)); + assertThat(added).isFalse(); } } \ No newline at end of file From 2268d19caa8bd558310e00b11a0e7ce6c4edd6f0 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 26 Jul 2022 20:01:43 +0530 Subject: [PATCH 28/34] JAVA-13134: Fix references to parents --- lightrun/api-service/pom.xml | 8 +-- lightrun/pom.xml | 7 +++ lightrun/tasks-service/pom.xml | 8 +-- lightrun/users-service/pom.xml | 8 +-- persistence-modules/fauna/pom.xml | 11 ++-- spring-cloud-modules/pom.xml | 57 ++++++++++--------- .../spring-cloud-archaius/pom.xml | 4 +- .../spring-cloud-eureka/pom.xml | 3 +- .../spring-cloud-hystrix/pom.xml | 2 +- .../echo-demo/pom.xml | 1 - .../spring-cloud-netflix-sidecar/pom.xml | 7 +-- .../sidecar-demo/pom.xml | 1 - .../spring-cloud-openfeign/pom.xml | 7 +-- .../spring-cloud-zuul/pom.xml | 4 +- .../spring-resttemplate-2/pom.xml | 2 +- 15 files changed, 68 insertions(+), 62 deletions(-) diff --git a/lightrun/api-service/pom.xml b/lightrun/api-service/pom.xml index ed9fc2152b..0541f6c5cb 100644 --- a/lightrun/api-service/pom.xml +++ b/lightrun/api-service/pom.xml @@ -10,10 +10,9 @@ Aggregator Service for LightRun Article - org.springframework.boot - spring-boot-starter-parent - 2.6.7 - + com.baelduung + lightrun + 0.0.1-SNAPSHOT @@ -43,6 +42,7 @@ 17 + 3.17.0 \ No newline at end of file diff --git a/lightrun/pom.xml b/lightrun/pom.xml index 4902688748..1fc8e5ea70 100644 --- a/lightrun/pom.xml +++ b/lightrun/pom.xml @@ -9,6 +9,13 @@ lightrun Services for LightRun Article pom + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + tasks-service diff --git a/lightrun/tasks-service/pom.xml b/lightrun/tasks-service/pom.xml index 5d4bf8b6d5..19b5f0d98e 100644 --- a/lightrun/tasks-service/pom.xml +++ b/lightrun/tasks-service/pom.xml @@ -10,10 +10,9 @@ Tasks Service for LightRun Article - org.springframework.boot - spring-boot-starter-parent - 2.6.7 - + com.baelduung + lightrun + 0.0.1-SNAPSHOT @@ -64,6 +63,7 @@ 17 + 3.17.0 \ No newline at end of file diff --git a/lightrun/users-service/pom.xml b/lightrun/users-service/pom.xml index 0be696bbf0..2db0d37037 100644 --- a/lightrun/users-service/pom.xml +++ b/lightrun/users-service/pom.xml @@ -10,10 +10,9 @@ Users Service for LightRun Article - org.springframework.boot - spring-boot-starter-parent - 2.6.7 - + com.baelduung + lightrun + 0.0.1-SNAPSHOT @@ -60,6 +59,7 @@ 17 + 3.17.0 \ No newline at end of file diff --git a/persistence-modules/fauna/pom.xml b/persistence-modules/fauna/pom.xml index 2f5da68ede..8c985e0b7c 100644 --- a/persistence-modules/fauna/pom.xml +++ b/persistence-modules/fauna/pom.xml @@ -9,11 +9,11 @@ fauna Blogging Service built with FaunaDB - - org.springframework.boot - spring-boot-starter-parent - 2.6.2 - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 @@ -54,6 +54,7 @@ 17 + 3.17.0 \ No newline at end of file diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 6d44cb015b..d76b3407f0 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -17,41 +17,42 @@ - spring-cloud-loadbalancer - spring-cloud-config - spring-cloud-eureka - spring-cloud-hystrix + spring-cloud-archaius + spring-cloud-aws spring-cloud-bootstrap - spring-cloud-ribbon-client - spring-cloud-zookeeper + spring-cloud-bus + spring-cloud-circuit-breaker + spring-cloud-config + spring-cloud-connectors-heroku + spring-cloud-consul + spring-cloud-contract + spring-cloud-dapr + spring-cloud-data-flow + spring-cloud-docker + spring-cloud-eureka + spring-cloud-eureka-self-preservation + spring-cloud-functions spring-cloud-gateway + spring-cloud-hystrix + spring-cloud-kubernetes + spring-cloud-loadbalancer + spring-cloud-netflix-feign + spring-cloud-netflix-sidecar + spring-cloud-openfeign + spring-cloud-open-service-broker + spring-cloud-ribbon-client + spring-cloud-ribbon-retry + spring-cloud-security + spring-cloud-sentinel + spring-cloud-sleuth spring-cloud-stream spring-cloud-stream-starters - spring-cloud-connectors-heroku - spring-cloud-aws - spring-cloud-consul - spring-cloud-zuul-eureka-integration - spring-cloud-contract - spring-cloud-kubernetes - spring-cloud-open-service-broker - spring-cloud-archaius - spring-cloud-functions - spring-cloud-vault - spring-cloud-security spring-cloud-task + spring-cloud-vault + spring-cloud-zookeeper spring-cloud-zuul + spring-cloud-zuul-eureka-integration spring-cloud-zuul-fallback - spring-cloud-ribbon-retry - spring-cloud-circuit-breaker - spring-cloud-eureka-self-preservation - spring-cloud-openfeign - spring-cloud-netflix-feign - spring-cloud-sentinel - spring-cloud-dapr - spring-cloud-docker - spring-cloud-bus - spring-cloud-data-flow - spring-cloud-sleuth diff --git a/spring-cloud-modules/spring-cloud-archaius/pom.xml b/spring-cloud-modules/spring-cloud-archaius/pom.xml index 1208daaba6..66b7bb9b19 100644 --- a/spring-cloud-modules/spring-cloud-archaius/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/pom.xml @@ -16,11 +16,11 @@ - basic-config additional-sources-simple + basic-config + dynamodb-config extra-configs jdbc-config - dynamodb-config zookeeper-config diff --git a/spring-cloud-modules/spring-cloud-eureka/pom.xml b/spring-cloud-modules/spring-cloud-eureka/pom.xml index 2a9c4f5fde..23523f2c2f 100644 --- a/spring-cloud-modules/spring-cloud-eureka/pom.xml +++ b/spring-cloud-modules/spring-cloud-eureka/pom.xml @@ -16,10 +16,11 @@ - spring-cloud-eureka-server spring-cloud-eureka-client + spring-cloud-eureka-client-profiles spring-cloud-eureka-feign-client spring-cloud-eureka-feign-client-integration-test + spring-cloud-eureka-server diff --git a/spring-cloud-modules/spring-cloud-hystrix/pom.xml b/spring-cloud-modules/spring-cloud-hystrix/pom.xml index e1f30c25dc..41548ba36a 100644 --- a/spring-cloud-modules/spring-cloud-hystrix/pom.xml +++ b/spring-cloud-modules/spring-cloud-hystrix/pom.xml @@ -15,9 +15,9 @@ + feign-rest-consumer rest-producer rest-consumer - feign-rest-consumer \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-netflix-sidecar/echo-demo/pom.xml b/spring-cloud-modules/spring-cloud-netflix-sidecar/echo-demo/pom.xml index 60b6eab020..d8b1654eaa 100644 --- a/spring-cloud-modules/spring-cloud-netflix-sidecar/echo-demo/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-sidecar/echo-demo/pom.xml @@ -9,7 +9,6 @@ com.baeldung.cloud spring-cloud-netflix-sidecar 0.0.1-SNAPSHOT - ../pom.xml diff --git a/spring-cloud-modules/spring-cloud-netflix-sidecar/pom.xml b/spring-cloud-modules/spring-cloud-netflix-sidecar/pom.xml index 0d95714bf9..3a72496279 100644 --- a/spring-cloud-modules/spring-cloud-netflix-sidecar/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-sidecar/pom.xml @@ -11,10 +11,9 @@ Netflix Sidecar project for Spring Boot - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT diff --git a/spring-cloud-modules/spring-cloud-netflix-sidecar/sidecar-demo/pom.xml b/spring-cloud-modules/spring-cloud-netflix-sidecar/sidecar-demo/pom.xml index 3c8d498456..200897652f 100644 --- a/spring-cloud-modules/spring-cloud-netflix-sidecar/sidecar-demo/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-sidecar/sidecar-demo/pom.xml @@ -11,7 +11,6 @@ com.baeldung.cloud spring-cloud-netflix-sidecar 0.0.1-SNAPSHOT - ../pom.xml diff --git a/spring-cloud-modules/spring-cloud-openfeign/pom.xml b/spring-cloud-modules/spring-cloud-openfeign/pom.xml index 480663eb1c..5657577cb0 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/pom.xml +++ b/spring-cloud-modules/spring-cloud-openfeign/pom.xml @@ -9,10 +9,9 @@ OpenFeign project for Spring Boot - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT diff --git a/spring-cloud-modules/spring-cloud-zuul/pom.xml b/spring-cloud-modules/spring-cloud-zuul/pom.xml index e99cbdf355..b04a21da1c 100644 --- a/spring-cloud-modules/spring-cloud-zuul/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul/pom.xml @@ -17,9 +17,9 @@ spring-zuul-foos-resource - spring-zuul-ui - spring-zuul-rate-limiting spring-zuul-post-filter + spring-zuul-rate-limiting + spring-zuul-ui diff --git a/spring-web-modules/spring-resttemplate-2/pom.xml b/spring-web-modules/spring-resttemplate-2/pom.xml index b87b245da9..0228b1dc4f 100644 --- a/spring-web-modules/spring-resttemplate-2/pom.xml +++ b/spring-web-modules/spring-resttemplate-2/pom.xml @@ -12,7 +12,7 @@ com.baeldung parent-boot-2 0.0.1-SNAPSHOT - ../../parent-boot-2/pom.xml + ../../parent-boot-2 From d083a20aa92d1064416009512e2c99a561c4e14c Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Tue, 26 Jul 2022 20:11:45 +0100 Subject: [PATCH 29/34] BAEL-5686: Implementing a Map with Multiple Keys (#12531) --- .../map/multikey/BaseClassUserCache.java | 24 +++++++ .../map/multikey/MultipleMapsUserCache.java | 25 ++++++++ .../java/com/baeldung/map/multikey/User.java | 13 ++++ .../map/multikey/WrapperClassUserCache.java | 42 +++++++++++++ .../multikey/WrapperInterfaceUserCache.java | 62 +++++++++++++++++++ .../multikey/BaseClassUserCacheUnitTest.java | 32 ++++++++++ .../MultipleMapsUserCacheUnitTest.java | 33 ++++++++++ .../WrapperClassUserCacheUnitTest.java | 33 ++++++++++ .../WrapperInterfaceUserCacheUnitTest.java | 33 ++++++++++ 9 files changed, 297 insertions(+) create mode 100644 core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/BaseClassUserCache.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/MultipleMapsUserCache.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/User.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperClassUserCache.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperInterfaceUserCache.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/BaseClassUserCacheUnitTest.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/MultipleMapsUserCacheUnitTest.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperClassUserCacheUnitTest.java create mode 100644 core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperInterfaceUserCacheUnitTest.java diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/BaseClassUserCache.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/BaseClassUserCache.java new file mode 100644 index 0000000000..1449727efc --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/BaseClassUserCache.java @@ -0,0 +1,24 @@ +package com.baeldung.map.multikey; + +import java.util.HashMap; +import java.util.Map; + +public class BaseClassUserCache { + private final Map cache = new HashMap<>(); + + public User getById(String id) { + return cache.get(id); + } + + public User getById(Long id) { + return cache.get(id); + } + + public void storeById(String id, User user) { + cache.put(id, user); + } + + public void storeById(Long id, User user) { + cache.put(id, user); + } +} diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/MultipleMapsUserCache.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/MultipleMapsUserCache.java new file mode 100644 index 0000000000..6b7e56f209 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/MultipleMapsUserCache.java @@ -0,0 +1,25 @@ +package com.baeldung.map.multikey; + +import java.util.HashMap; +import java.util.Map; + +public class MultipleMapsUserCache { + private final Map stringCache = new HashMap<>(); + private final Map longCache = new HashMap<>(); + + public User getById(String id) { + return stringCache.get(id); + } + + public User getById(Long id) { + return longCache.get(id); + } + + public void storeById(String id, User user) { + stringCache.put(id, user); + } + + public void storeById(Long id, User user) { + longCache.put(id, user); + } +} diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/User.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/User.java new file mode 100644 index 0000000000..392587d305 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/User.java @@ -0,0 +1,13 @@ +package com.baeldung.map.multikey; + +public class User { + private final String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperClassUserCache.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperClassUserCache.java new file mode 100644 index 0000000000..3ce920ead1 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperClassUserCache.java @@ -0,0 +1,42 @@ +package com.baeldung.map.multikey; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class WrapperClassUserCache { + private Map cache = new HashMap<>(); + + public User getById(CacheKey key) { + return cache.get(key); + } + + public void storeById(CacheKey key, User user) { + cache.put(key, user); + } + + public static class CacheKey { + private final Object value; + + public CacheKey(String value) { + this.value = value; + } + + public CacheKey(Long value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CacheKey cacheKey = (CacheKey) o; + return value.equals(cacheKey.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } +} diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperInterfaceUserCache.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperInterfaceUserCache.java new file mode 100644 index 0000000000..586a1bdee7 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/multikey/WrapperInterfaceUserCache.java @@ -0,0 +1,62 @@ +package com.baeldung.map.multikey; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class WrapperInterfaceUserCache { + private Map cache = new HashMap<>(); + + public User getById(CacheKey key) { + return cache.get(key); + } + + public void storeById(CacheKey key, User user) { + cache.put(key, user); + } + + public interface CacheKey { + } + + public static class StringCacheKey implements CacheKey{ + private final String value; + + public StringCacheKey(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StringCacheKey that = (StringCacheKey) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } + + public static class LongCacheKey implements CacheKey { + private final Long value; + + public LongCacheKey(Long value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LongCacheKey that = (LongCacheKey) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } +} diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/BaseClassUserCacheUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/BaseClassUserCacheUnitTest.java new file mode 100644 index 0000000000..6a35e4c10a --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/BaseClassUserCacheUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.map.multikey; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BaseClassUserCacheUnitTest { + private BaseClassUserCache cache = new BaseClassUserCache(); + + @BeforeEach + public void setup() { + cache.storeById("a", new User("User A")); + cache.storeById("b", new User("User B")); + cache.storeById(3L, new User("User 3")); + cache.storeById(4L, new User("User 4")); + } + + @Test + public void getByString() { + User user = cache.getById("b"); + assertNotNull(user); + assertEquals("User B", user.getName()); + } + + @Test + public void getByLong() { + User user = cache.getById(4L); + assertNotNull(user); + assertEquals("User 4", user.getName()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/MultipleMapsUserCacheUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/MultipleMapsUserCacheUnitTest.java new file mode 100644 index 0000000000..0b8473c0df --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/MultipleMapsUserCacheUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.map.multikey; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class MultipleMapsUserCacheUnitTest { + private MultipleMapsUserCache cache = new MultipleMapsUserCache(); + + @BeforeEach + public void setup() { + cache.storeById("a", new User("User A")); + cache.storeById("b", new User("User B")); + cache.storeById(3L, new User("User 3")); + cache.storeById(4L, new User("User 4")); + } + + @Test + public void getByString() { + User user = cache.getById("b"); + assertNotNull(user); + assertEquals("User B", user.getName()); + } + + @Test + public void getByLong() { + User user = cache.getById(4L); + assertNotNull(user); + assertEquals("User 4", user.getName()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperClassUserCacheUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperClassUserCacheUnitTest.java new file mode 100644 index 0000000000..caff7ef050 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperClassUserCacheUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.map.multikey; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class WrapperClassUserCacheUnitTest { + private WrapperClassUserCache cache = new WrapperClassUserCache(); + + @BeforeEach + public void setup() { + cache.storeById(new WrapperClassUserCache.CacheKey("a"), new User("User A")); + cache.storeById(new WrapperClassUserCache.CacheKey("b"), new User("User B")); + cache.storeById(new WrapperClassUserCache.CacheKey(3L), new User("User 3")); + cache.storeById(new WrapperClassUserCache.CacheKey(4L), new User("User 4")); + } + + @Test + public void getByString() { + User user = cache.getById(new WrapperClassUserCache.CacheKey("b")); + assertNotNull(user); + assertEquals("User B", user.getName()); + } + + @Test + public void getByLong() { + User user = cache.getById(new WrapperClassUserCache.CacheKey(4L)); + assertNotNull(user); + assertEquals("User 4", user.getName()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperInterfaceUserCacheUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperInterfaceUserCacheUnitTest.java new file mode 100644 index 0000000000..211e6aa182 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/multikey/WrapperInterfaceUserCacheUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.map.multikey; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class WrapperInterfaceUserCacheUnitTest { + private WrapperInterfaceUserCache cache = new WrapperInterfaceUserCache(); + + @BeforeEach + public void setup() { + cache.storeById(new WrapperInterfaceUserCache.StringCacheKey("a"), new User("User A")); + cache.storeById(new WrapperInterfaceUserCache.StringCacheKey("b"), new User("User B")); + cache.storeById(new WrapperInterfaceUserCache.LongCacheKey(3L), new User("User 3")); + cache.storeById(new WrapperInterfaceUserCache.LongCacheKey(4L), new User("User 4")); + } + + @Test + public void getByString() { + User user = cache.getById(new WrapperInterfaceUserCache.StringCacheKey("b")); + assertNotNull(user); + assertEquals("User B", user.getName()); + } + + @Test + public void getByLong() { + User user = cache.getById(new WrapperInterfaceUserCache.LongCacheKey(4L)); + assertNotNull(user); + assertEquals("User 4", user.getName()); + } +} \ No newline at end of file From ba18865ff3aa6a2906c5188e0e72581e41348486 Mon Sep 17 00:00:00 2001 From: Tapan Avasthi Date: Wed, 27 Jul 2022 05:51:31 +0530 Subject: [PATCH 30/34] BAEL-4840: Read Flux into a single InputStream (#12500) Co-authored-by: Tapan Avasthi --- .../databuffer/DataBufferToInputStream.java | 94 +++++++++++++++++++ .../DataBufferToInputStreamUnitTest.java | 77 +++++++++++++++ .../src/test/resources/user-response.json | 72 ++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 spring-5-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java create mode 100644 spring-5-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java create mode 100644 spring-5-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json diff --git a/spring-5-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java b/spring-5-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java new file mode 100644 index 0000000000..82f0658f51 --- /dev/null +++ b/spring-5-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java @@ -0,0 +1,94 @@ +package com.baeldung.databuffer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.web.reactive.function.BodyExtractors; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Flux; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +public class DataBufferToInputStream { + private static final Logger logger = LoggerFactory.getLogger(DataBufferToInputStream.class); + private static final String REQUEST_ENDPOINT = "https://gorest.co.in/public/v2/users"; + + private static WebClient getWebClient() { + WebClient.Builder webClientBuilder = WebClient.builder(); + return webClientBuilder.build(); + } + + public static InputStream getResponseAsInputStream(WebClient client, String url) throws IOException, InterruptedException { + + PipedOutputStream pipedOutputStream = new PipedOutputStream(); + PipedInputStream pipedInputStream = new PipedInputStream(1024 * 10); + pipedInputStream.connect(pipedOutputStream); + + Flux body = client.get() + .uri(url) + .exchangeToFlux(clientResponse -> { + return clientResponse.body(BodyExtractors.toDataBuffers()); + }) + .doOnError(error -> { + logger.error("error occurred while reading body", error); + }) + .doFinally(s -> { + try { + pipedOutputStream.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .doOnCancel(() -> { + logger.error("Get request is cancelled"); + }); + + DataBufferUtils.write(body, pipedOutputStream) + .log("Writing to output buffer") + .subscribe(); + return pipedInputStream; + } + + private static String readContentFromPipedInputStream(PipedInputStream stream) throws IOException { + StringBuffer contentStringBuffer = new StringBuffer(); + try { + Thread pipeReader = new Thread(() -> { + try { + contentStringBuffer.append(readContent(stream)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + pipeReader.start(); + pipeReader.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + stream.close(); + } + + return String.valueOf(contentStringBuffer); + } + + private static String readContent(InputStream stream) throws IOException { + StringBuffer contentStringBuffer = new StringBuffer(); + byte[] tmp = new byte[stream.available()]; + int byteCount = stream.read(tmp, 0, tmp.length); + logger.info(String.format("read %d bytes from the stream\n", byteCount)); + contentStringBuffer.append(new String(tmp)); + return String.valueOf(contentStringBuffer); + } + + public static void main(String[] args) throws IOException, InterruptedException { + WebClient webClient = getWebClient(); + InputStream inputStream = getResponseAsInputStream(webClient, REQUEST_ENDPOINT); + Thread.sleep(3000); + String content = readContentFromPipedInputStream((PipedInputStream) inputStream); + logger.info("response content: \n{}", content.replace("}", "}\n")); + } +} diff --git a/spring-5-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java b/spring-5-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java new file mode 100644 index 0000000000..b885919bbb --- /dev/null +++ b/spring-5-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java @@ -0,0 +1,77 @@ +package databuffer; + +import com.baeldung.databuffer.DataBufferToInputStream; + +import io.restassured.internal.util.IOUtils; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +class DataBufferToInputStreamUnitTest { + private String getResponseStub() throws IOException { + InputStream inputStream = null; + BufferedReader reader = null; + String content = null; + try { + inputStream = this.getClass() + .getClassLoader() + .getResourceAsStream("user-response.json"); + if (inputStream != null) { + reader = new BufferedReader(new InputStreamReader(inputStream)); + content = reader.lines() + .collect(Collectors.joining(System.lineSeparator())); + } + } catch (Exception ex) { + throw new RuntimeException("exception caught while getting response stub"); + } finally { + reader.close(); + inputStream.close(); + } + return content; + } + + private InputStream getResponseStubAsInputStream() { + return this.getClass() + .getClassLoader() + .getResourceAsStream("user-response.json"); + } + + private WebClient getMockWebClient() throws IOException { + String content = getResponseStub(); + ClientResponse clientResponse = ClientResponse.create(HttpStatus.OK) + .header("Content-Type", "application/json") + .body(content) + .build(); + + ExchangeFunction exchangeFunction = clientRequest -> Mono.just(clientResponse); + + WebClient.Builder webClientBuilder = WebClient.builder() + .exchangeFunction(exchangeFunction); + WebClient webClient = webClientBuilder.build(); + return webClient; + } + + @Test + public void testResponseAsInputStream() throws IOException, InterruptedException { + String mockUrl = Mockito.anyString(); + WebClient mockWebClient = getMockWebClient(); + InputStream inputStream = DataBufferToInputStream.getResponseAsInputStream(mockWebClient, mockUrl); + byte[] expectedBytes = IOUtils.toByteArray(getResponseStubAsInputStream()); + byte[] actualBytes = IOUtils.toByteArray(inputStream); + assertArrayEquals(expectedBytes, actualBytes); + } +} \ No newline at end of file diff --git a/spring-5-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json b/spring-5-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json new file mode 100644 index 0000000000..33c03dc492 --- /dev/null +++ b/spring-5-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json @@ -0,0 +1,72 @@ +[ + { + "id": 2683, + "name": "Maheswar Kocchar", + "email": "maheswar_kocchar@kihn.info", + "gender": "male", + "status": "active" + }, + { + "id": 2680, + "name": "Lakshminath Khan", + "email": "lakshminath_khan@barrows-cormier.biz", + "gender": "female", + "status": "inactive" + }, + { + "id": 2679, + "name": "Tarun Arora", + "email": "tarun_arora@rolfson.net", + "gender": "female", + "status": "inactive" + }, + { + "id": 2678, + "name": "Agnivesh Dubashi", + "email": "dubashi_agnivesh@senger.name", + "gender": "male", + "status": "inactive" + }, + { + "id": 2677, + "name": "Dhanu Gowda", + "email": "gowda_dhanu@hayes.org", + "gender": "male", + "status": "active" + }, + { + "id": 2675, + "name": "Harinakshi Pilla Jr.", + "email": "pilla_jr_harinakshi@rutherford-monahan.com", + "gender": "female", + "status": "inactive" + }, + { + "id": 2673, + "name": "Kalpana Prajapat", + "email": "prajapat_kalpana@wilkinson-schaefer.net", + "gender": "female", + "status": "active" + }, + { + "id": 2672, + "name": "Chakradhar Jha", + "email": "jha_chakradhar@baumbach.info", + "gender": "male", + "status": "active" + }, + { + "id": 2670, + "name": "Divaakar Deshpande Jr.", + "email": "deshpande_jr_divaakar@mertz.info", + "gender": "female", + "status": "inactive" + }, + { + "id": 2669, + "name": "Prasanna Mehra", + "email": "prasanna_mehra@ruecker-larkin.name", + "gender": "female", + "status": "active" + } +] \ No newline at end of file From b055a790be1c4b54efad2c1baa06773791fbc9ef Mon Sep 17 00:00:00 2001 From: AttilaUhrin Date: Wed, 27 Jul 2022 06:00:18 +0200 Subject: [PATCH 31/34] Add Spring JMS testing examples. (#12518) --- spring-jms/pom.xml | 19 ++++ .../spring/jms/testing/JmsApplication.java | 13 +++ .../spring/jms/testing/JmsConfig.java | 34 ++++++ .../spring/jms/testing/MessageListener.java | 20 ++++ .../spring/jms/testing/MessageSender.java | 21 ++++ .../EmbeddedActiveMqIntegrationTest.java | 91 ++++++++++++++++ ...TestContainersActiveMqIntegrationTest.java | 101 ++++++++++++++++++ 7 files changed, 299 insertions(+) create mode 100644 spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java create mode 100644 spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java create mode 100644 spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java create mode 100644 spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java create mode 100644 spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java create mode 100644 spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java diff --git a/spring-jms/pom.xml b/spring-jms/pom.xml index 09bf854221..ab202402f3 100644 --- a/spring-jms/pom.xml +++ b/spring-jms/pom.xml @@ -41,6 +41,25 @@ ${spring-boot-test.version} test + + + org.mockito + mockito-core + 4.6.1 + test + + + org.apache.activemq.tooling + activemq-junit + 5.16.5 + test + + + org.testcontainers + testcontainers + 1.17.3 + test + diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java new file mode 100644 index 0000000000..0a89d422b4 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.jms.testing; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan +public class JmsApplication { + + public static void main(String[] args) { + ApplicationContext context = new AnnotationConfigApplicationContext(JmsApplication.class); + } +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java new file mode 100644 index 0000000000..92abb32861 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.jms.testing; + +import javax.jms.ConnectionFactory; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; + +@Configuration +@EnableJms +public class JmsConfig { + + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java new file mode 100644 index 0000000000..f66a99c876 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.jms.testing; + +import javax.jms.JMSException; +import javax.jms.TextMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +@Component +public class MessageListener { + + private static final Logger logger = LoggerFactory.getLogger(MessageListener.class); + + @JmsListener(destination = "queue-1") + public void sampleJmsListenerMethod(TextMessage message) throws JMSException { + logger.info("JMS listener received text message: {}", message.getText()); + } +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java new file mode 100644 index 0000000000..6cb199b0e9 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.jms.testing; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +@Component +public class MessageSender { + + @Autowired + private JmsTemplate jmsTemplate; + + private static final Logger logger = LoggerFactory.getLogger(MessageSender.class); + + public void sendTextMessage(String destination, String message) { + logger.info("Sending message to {} destination with text {}", destination, message); + jmsTemplate.send(destination, s -> s.createTextMessage(message)); + } +} diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java new file mode 100644 index 0000000000..6644ee50ac --- /dev/null +++ b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java @@ -0,0 +1,91 @@ +package com.baeldung.spring.jms.testing; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.junit.EmbeddedActiveMQBroker; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.spring.jms.testing.EmbeddedActiveMqIntegrationTest.TestConfiguration; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TestConfiguration.class }) +public class EmbeddedActiveMqIntegrationTest { + + @ClassRule + public static EmbeddedActiveMQBroker embeddedBroker = new EmbeddedActiveMQBroker(); + + @SpyBean + private MessageListener messageListener; + + @SpyBean + private MessageSender messageSender; + + @Test + public void whenListening_thenReceivingCorrectMessage() throws JMSException { + String queueName = "queue-1"; + String messageText = "Test message"; + + embeddedBroker.pushMessage(queueName, messageText); + assertEquals(1, embeddedBroker.getMessageCount(queueName)); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(TextMessage.class); + + Mockito.verify(messageListener, Mockito.timeout(100)) + .sampleJmsListenerMethod(messageCaptor.capture()); + + TextMessage receivedMessage = messageCaptor.getValue(); + assertEquals(messageText, receivedMessage.getText()); + } + + @Test + public void whenSendingMessage_thenCorrectQueueAndMessageText() throws JMSException { + String queueName = "queue-2"; + String messageText = "Test message"; + + messageSender.sendTextMessage(queueName, messageText); + + assertEquals(1, embeddedBroker.getMessageCount(queueName)); + TextMessage sentMessage = embeddedBroker.peekTextMessage(queueName); + assertEquals(messageText, sentMessage.getText()); + } + + @Configuration + @EnableJms + static class TestConfiguration { + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + return new ActiveMQConnectionFactory(embeddedBroker.getVmURL()); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + } + +} diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java new file mode 100644 index 0000000000..d117b90423 --- /dev/null +++ b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java @@ -0,0 +1,101 @@ +package com.baeldung.spring.jms.testing; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.assertj.core.api.Assertions; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.spring.jms.testing.TestContainersActiveMqIntegrationTest.TestConfiguration; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TestConfiguration.class, MessageSender.class }) +public class TestContainersActiveMqIntegrationTest { + + @ClassRule + public static GenericContainer activeMqContainer = new GenericContainer<>(DockerImageName.parse("rmohr/activemq:5.14.3")).withExposedPorts(61616); + + @SpyBean + private MessageListener messageListener; + + @Autowired + private MessageSender messageSender; + + @Autowired + private JmsTemplate jmsTemplate; + + @Test + public void whenListening_thenReceivingCorrectMessage() throws JMSException { + String queueName = "queue-1"; + String messageText = "Test message"; + + jmsTemplate.send(queueName, s -> s.createTextMessage(messageText)); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(TextMessage.class); + + Mockito.verify(messageListener, Mockito.timeout(100)) + .sampleJmsListenerMethod(messageCaptor.capture()); + + TextMessage receivedMessage = messageCaptor.getValue(); + assertEquals(messageText, receivedMessage.getText()); + } + + @Test + public void whenSendingMessage_thenCorrectQueueAndMessageText() throws JMSException { + String queueName = "queue-2"; + String messageText = "Test message"; + + messageSender.sendTextMessage(queueName, messageText); + + Message sentMessage = jmsTemplate.receive(queueName); + Assertions.assertThat(sentMessage) + .isInstanceOf(TextMessage.class); + + assertEquals(messageText, ((TextMessage) sentMessage).getText()); + } + + @Configuration + @EnableJms + static class TestConfiguration { + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + String brokerUrlFormat = "tcp://%s:%d"; + String brokerUrl = String.format(brokerUrlFormat, activeMqContainer.getHost(), activeMqContainer.getFirstMappedPort()); + return new ActiveMQConnectionFactory(brokerUrl); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + } + +} From ad61eaa45a5e643cecb1ddcfed5066029033c7f4 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Wed, 27 Jul 2022 10:23:01 +0530 Subject: [PATCH 32/34] JAVA-13134 --- spring-cloud-modules/pom.xml | 59 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index d76b3407f0..6d44cb015b 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -17,42 +17,41 @@ - spring-cloud-archaius - spring-cloud-aws - spring-cloud-bootstrap - spring-cloud-bus - spring-cloud-circuit-breaker - spring-cloud-config - spring-cloud-connectors-heroku - spring-cloud-consul - spring-cloud-contract - spring-cloud-dapr - spring-cloud-data-flow - spring-cloud-docker - spring-cloud-eureka - spring-cloud-eureka-self-preservation - spring-cloud-functions - spring-cloud-gateway - spring-cloud-hystrix - spring-cloud-kubernetes spring-cloud-loadbalancer - spring-cloud-netflix-feign - spring-cloud-netflix-sidecar - spring-cloud-openfeign - spring-cloud-open-service-broker + spring-cloud-config + spring-cloud-eureka + spring-cloud-hystrix + spring-cloud-bootstrap spring-cloud-ribbon-client - spring-cloud-ribbon-retry - spring-cloud-security - spring-cloud-sentinel - spring-cloud-sleuth + spring-cloud-zookeeper + spring-cloud-gateway spring-cloud-stream spring-cloud-stream-starters - spring-cloud-task - spring-cloud-vault - spring-cloud-zookeeper - spring-cloud-zuul + spring-cloud-connectors-heroku + spring-cloud-aws + spring-cloud-consul spring-cloud-zuul-eureka-integration + spring-cloud-contract + spring-cloud-kubernetes + spring-cloud-open-service-broker + spring-cloud-archaius + spring-cloud-functions + spring-cloud-vault + spring-cloud-security + spring-cloud-task + spring-cloud-zuul spring-cloud-zuul-fallback + spring-cloud-ribbon-retry + spring-cloud-circuit-breaker + spring-cloud-eureka-self-preservation + spring-cloud-openfeign + spring-cloud-netflix-feign + spring-cloud-sentinel + spring-cloud-dapr + spring-cloud-docker + spring-cloud-bus + spring-cloud-data-flow + spring-cloud-sleuth From cf4225a9eaae0d2e6439236b5c7f35bb854bea8e Mon Sep 17 00:00:00 2001 From: Avin Buricha Date: Wed, 27 Jul 2022 20:01:18 +0530 Subject: [PATCH 33/34] Moved article code to new module (#12423) --- core-java-modules/core-java-11-2/README.md | 3 +- core-java-modules/core-java-11-3/README.md | 6 +++ core-java-modules/core-java-11-3/pom.xml | 37 +++++++++++++++++++ .../HttpClientParametersLiveTest.java | 0 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 core-java-modules/core-java-11-3/README.md create mode 100644 core-java-modules/core-java-11-3/pom.xml rename core-java-modules/{core-java-11-2 => core-java-11-3}/src/test/java/com/baeldung/httpclient/parameters/HttpClientParametersLiveTest.java (100%) diff --git a/core-java-modules/core-java-11-2/README.md b/core-java-modules/core-java-11-2/README.md index b864e1ca99..62acd33188 100644 --- a/core-java-modules/core-java-11-2/README.md +++ b/core-java-modules/core-java-11-2/README.md @@ -12,5 +12,4 @@ This module contains articles about Java 11 core features - [Java HTTPS Client Certificate Authentication](https://www.baeldung.com/java-https-client-certificate-authentication) - [Call Methods at Runtime Using Java Reflection](https://www.baeldung.com/java-method-reflection) - [Java HttpClient Basic Authentication](https://www.baeldung.com/java-httpclient-basic-auth) -- [Java HttpClient With SSL](https://www.baeldung.com/java-httpclient-ssl) -- [Adding Parameters to Java HttpClient Requests](https://www.baeldung.com/java-httpclient-request-parameters) +- [Java HttpClient With SSL](https://www.baeldung.com/java-httpclient-ssl) \ No newline at end of file diff --git a/core-java-modules/core-java-11-3/README.md b/core-java-modules/core-java-11-3/README.md new file mode 100644 index 0000000000..f46ab02bca --- /dev/null +++ b/core-java-modules/core-java-11-3/README.md @@ -0,0 +1,6 @@ +## Core Java 11 + +This module contains articles about Java 11 core features + +### Relevant articles +- [Adding Parameters to Java HttpClient Requests](https://www.baeldung.com/java-httpclient-request-parameters) diff --git a/core-java-modules/core-java-11-3/pom.xml b/core-java-modules/core-java-11-3/pom.xml new file mode 100644 index 0000000000..b4a4591b28 --- /dev/null +++ b/core-java-modules/core-java-11-3/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + core-java-11-3 + 0.1.0-SNAPSHOT + core-java-11-3 + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../pom.xml + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + + + + 11 + 11 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/parameters/HttpClientParametersLiveTest.java b/core-java-modules/core-java-11-3/src/test/java/com/baeldung/httpclient/parameters/HttpClientParametersLiveTest.java similarity index 100% rename from core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/parameters/HttpClientParametersLiveTest.java rename to core-java-modules/core-java-11-3/src/test/java/com/baeldung/httpclient/parameters/HttpClientParametersLiveTest.java From 1eeb2721e7c378a3f6040dd2e8a58a5dc9644ede Mon Sep 17 00:00:00 2001 From: Christian GERMAN Date: Thu, 28 Jul 2022 14:30:02 +0200 Subject: [PATCH 34/34] BAEL-5589 - Skipping tests with docker from pipeline. --- .../{IntegrationTest.java => KeycloakTestContainers.java} | 6 +++--- ...erIntegrationTest.java => UserControllerManualTest.java} | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) rename spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/{IntegrationTest.java => KeycloakTestContainers.java} (95%) rename spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/{UserControllerIntegrationTest.java => UserControllerManualTest.java} (77%) diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/IntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java similarity index 95% rename from spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/IntegrationTest.java rename to spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java index 902c27b16e..44e24c98d1 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/IntegrationTest.java +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java @@ -26,11 +26,11 @@ import org.springframework.web.reactive.function.client.WebClient; import dasniko.testcontainers.keycloak.KeycloakContainer; import io.restassured.RestAssured; -@ContextConfiguration(initializers = { IntegrationTest.Initializer.class }) +@ContextConfiguration(initializers = { KeycloakTestContainers.Initializer.class }) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public abstract class IntegrationTest { +public abstract class KeycloakTestContainers { - private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationTest.class.getName()); + private static final Logger LOGGER = LoggerFactory.getLogger(KeycloakTestContainers.class.getName()); @LocalServerPort private int port; diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerManualTest.java similarity index 77% rename from spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerIntegrationTest.java rename to spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerManualTest.java index 4015612860..817c8ae130 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/UserControllerManualTest.java @@ -5,7 +5,11 @@ import static org.hamcrest.Matchers.equalTo; import org.junit.jupiter.api.Test; -class UserControllerIntegrationTest extends IntegrationTest { +/** + * Requires Docker running on the machine to run without errors + * Therefore, skipped from pipeline + */ +class UserControllerManualTest extends KeycloakTestContainers { @Test void givenAuthenticatedUser_whenGetMe_shouldReturnMyInfo() {