From 24833b7e92ef4511f50d94a5e4f865f5b60d3002 Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Mon, 13 Apr 2020 17:23:23 +0300 Subject: [PATCH 001/118] BAEL-3896: OpenAPI JSON Objects in Query Params --- spring-rest-http/README.md | 1 + .../jsonparam/JsonParamController.java | 55 +++++++++++++++++++ .../baeldung/jsonparam/ParamObjectDTO.java | 33 +++++++++++ 3 files changed, 89 insertions(+) create mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java create mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java diff --git a/spring-rest-http/README.md b/spring-rest-http/README.md index 35793cb281..cba017eb74 100644 --- a/spring-rest-http/README.md +++ b/spring-rest-http/README.md @@ -13,3 +13,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring RequestMapping](https://www.baeldung.com/spring-requestmapping) - [Guide to DeferredResult in Spring](https://www.baeldung.com/spring-deferred-result) - [Using JSON Patch in Spring REST APIs](https://www.baeldung.com/spring-rest-json-patch) +- [OpenAPI JSON Objects in Query Params](https://www.baeldung.com/openapi-json-objects-in-query-params) diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java b/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java new file mode 100644 index 0000000000..60797cf104 --- /dev/null +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java @@ -0,0 +1,55 @@ +package com.baeldung.jsonparam; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; + +@Controller +@RestController +@RequestMapping("/api") +public class JsonParamController { + + @GetMapping(value = "/something") + public String testQueryParamApi(@RequestParam("params") String params) { + // params={"type":"foo","color":"green"} + ParamObjectDTO paramObjectDTO; + ObjectMapper objectMapper = new ObjectMapper(); + try { + paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); + System.out.println(paramObjectDTO); + // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object + } catch (JsonParseException e) { + e.printStackTrace(); + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return params; + } + + + @PostMapping(value = "/something") + public String testBodyParamApi(@RequestBody String params) { + // params={"type":"foo","color":"green"} + ParamObjectDTO paramObjectDTO; + ObjectMapper objectMapper = new ObjectMapper(); + try { + paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); + System.out.println(paramObjectDTO); + // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object + } catch (JsonParseException e) { + e.printStackTrace(); + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return params; + } + +} diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java b/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java new file mode 100644 index 0000000000..a738180fa6 --- /dev/null +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java @@ -0,0 +1,33 @@ +package com.baeldung.jsonparam; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ParamObjectDTO { + private String type; + private String color; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + @Override + public String toString() { + return "ParamObjectDTO{" + + "type='" + type + '\'' + + ", color='" + color + '\'' + + '}'; + } +} From f0bdbde7a4634cee6e6575a785234674eb12ddf8 Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Tue, 21 Apr 2020 19:05:42 +0300 Subject: [PATCH 002/118] BAEL-3896: OpenAPI JSON Objects in Query Params v2 --- .../jsonparam/JsonParamController.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java b/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java index 60797cf104..d2a09296c2 100644 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java @@ -1,19 +1,20 @@ package com.baeldung.jsonparam; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; +import com.baeldung.controllers.DeferredResultController; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; -import java.io.IOException; - @Controller @RestController @RequestMapping("/api") public class JsonParamController { + private final static Logger LOG = LoggerFactory.getLogger(DeferredResultController.class); - @GetMapping(value = "/something") + @GetMapping(value = "/tickets") public String testQueryParamApi(@RequestParam("params") String params) { // params={"type":"foo","color":"green"} ParamObjectDTO paramObjectDTO; @@ -22,18 +23,28 @@ public class JsonParamController { paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); System.out.println(paramObjectDTO); // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object - } catch (JsonParseException e) { - e.printStackTrace(); - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + } catch (JsonProcessingException e) { + LOG.info("Json Processing Exception"); } return params; } + @GetMapping(value = "/tickets2") + public String testGetBodyParamApi(@RequestBody String params) { + // params={"type":"foo","color":"green"} + ParamObjectDTO paramObjectDTO; + ObjectMapper objectMapper = new ObjectMapper(); + try { + paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); + System.out.println(paramObjectDTO); + // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object + } catch (JsonProcessingException e) { + LOG.info("Json Processing Exception"); + } + return params; + } - @PostMapping(value = "/something") + @PostMapping(value = "/tickets") public String testBodyParamApi(@RequestBody String params) { // params={"type":"foo","color":"green"} ParamObjectDTO paramObjectDTO; @@ -42,12 +53,8 @@ public class JsonParamController { paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); System.out.println(paramObjectDTO); // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object - } catch (JsonParseException e) { - e.printStackTrace(); - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + } catch (JsonProcessingException e) { + LOG.info("Json Processing Exception"); } return params; } From 7241496289f39ec18a381d76c6747f09fb28ad0a Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 27 Apr 2020 18:44:09 +0200 Subject: [PATCH 003/118] Fix controllers to use Post/Redirect/Get Forms should use Post/Redirect/Get pattern. --- .../java/com/baeldung/crud/controllers/UserController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-modules/spring-boot-crud/src/main/java/com/baeldung/crud/controllers/UserController.java b/spring-boot-modules/spring-boot-crud/src/main/java/com/baeldung/crud/controllers/UserController.java index 726be6a384..8a7ef96f1e 100644 --- a/spring-boot-modules/spring-boot-crud/src/main/java/com/baeldung/crud/controllers/UserController.java +++ b/spring-boot-modules/spring-boot-crud/src/main/java/com/baeldung/crud/controllers/UserController.java @@ -36,7 +36,7 @@ public class UserController { userRepository.save(user); model.addAttribute("users", userRepository.findAll()); - return "index"; + return "redirect:/index"; } @GetMapping("/edit/{id}") @@ -55,7 +55,7 @@ public class UserController { userRepository.save(user); model.addAttribute("users", userRepository.findAll()); - return "index"; + return "redirect:/index"; } @GetMapping("/delete/{id}") From 1077dc82a5575bf5dc856016c6f0a32c4ab475a9 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 28 Apr 2020 10:54:49 +0200 Subject: [PATCH 004/118] Fix tests to check for forward to index --- .../test/java/com/baeldung/crud/UserControllerUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-modules/spring-boot-crud/src/test/java/com/baeldung/crud/UserControllerUnitTest.java b/spring-boot-modules/spring-boot-crud/src/test/java/com/baeldung/crud/UserControllerUnitTest.java index 033108c195..f1455f7a73 100644 --- a/spring-boot-modules/spring-boot-crud/src/test/java/com/baeldung/crud/UserControllerUnitTest.java +++ b/spring-boot-modules/spring-boot-crud/src/test/java/com/baeldung/crud/UserControllerUnitTest.java @@ -41,7 +41,7 @@ public class UserControllerUnitTest { when(mockedBindingResult.hasErrors()).thenReturn(false); - assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("index"); + assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("redirect:/index"); } @Test @@ -64,7 +64,7 @@ public class UserControllerUnitTest { when(mockedBindingResult.hasErrors()).thenReturn(false); - assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("index"); + assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("redirect:/index"); } @Test From a6fc46e3f6ed643215ae21ca28d22b095c4a839c Mon Sep 17 00:00:00 2001 From: Gergo Petrik Date: Mon, 4 May 2020 16:40:20 +0200 Subject: [PATCH 005/118] ABA problem in concurrency --- .../java/com/baeldung/abaproblem/Account.java | 34 +++++++ .../baeldung/abaproblem/AccountUnitTest.java | 93 +++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java new file mode 100644 index 0000000000..0204c31fea --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java @@ -0,0 +1,34 @@ +package com.baeldung.abaproblem; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class Account { + + private AtomicInteger balance = new AtomicInteger(0); + + public int getBalance() { + return balance.get(); + } + + public boolean withdraw(int amount) throws InterruptedException { + int current = getBalance(); + if (current < amount) { + throw new RuntimeException("Not sufficient balance"); + } + precessBalance(); + return balance.compareAndSet(current, current - amount); + } + + private void precessBalance() throws InterruptedException { + if ("thread 1".equals(Thread.currentThread().getName())) { + TimeUnit.SECONDS.sleep(2); + } + } + + public boolean deposit(int amount) { + int current = balance.get(); + return balance.compareAndSet(current, current + amount); + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java new file mode 100644 index 0000000000..ab88a0f447 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.abaproblem; + +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AccountUnitTest { + + private Account account; + + @BeforeEach + public void setUp() { + account = new Account(); + } + + @Test + public void zeroBalanceInitializationTest() { + assertEquals(0, account.getBalance()); + } + + @Test + public void depositTest() { + final int moneyToDeposit = 50; + + assertTrue(account.deposit(moneyToDeposit)); + + assertEquals(moneyToDeposit, account.getBalance()); + } + + @Test + public void withdrawTest() throws InterruptedException { + final int defaultBalance = 50; + final int moneyToWithdraw = 20; + + account.deposit(defaultBalance); + + assertTrue(account.withdraw(moneyToWithdraw)); + + assertEquals(defaultBalance - moneyToWithdraw, account.getBalance()); + } + + @Test + public void withdrawWithoutSufficientBalanceTest() { + assertThrows(RuntimeException.class, () -> account.withdraw(10)); + } + + @Test + public void abaProblemTest() throws InterruptedException { + final int defaultBalance = 50; + + final int amountToWithdrawByThreadA = 20; + final int amountToWithdrawByThreadB = 10; + final int amountToDepositByThreadB = 10; + + account.deposit(defaultBalance); + + Thread threadA = new Thread(() -> { + try { + // this will take longer due to the name of the thread + assertTrue(account.withdraw(amountToWithdrawByThreadA)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }, "tread 1"); + + Thread threadB = new Thread(() -> { + + assertTrue(account.deposit(amountToDepositByThreadB)); + assertEquals(defaultBalance + amountToDepositByThreadB, account.getBalance()); + try { + // this will be fast due to the name of the thread + assertTrue(account.withdraw(amountToWithdrawByThreadB)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + // thread 1 didn't finish yet, so the original value will be in place for it + assertEquals(defaultBalance, account.getBalance()); + + }, "thread 2"); + + threadA.start(); + threadB.start(); + threadA.join(); + threadB.join(); + + // compareAndSet operation succeeds for thread 1 + assertEquals(defaultBalance - amountToWithdrawByThreadA, account.getBalance()); + } +} From 68dc88528e488db5aef951d8578bcfb33c46cd81 Mon Sep 17 00:00:00 2001 From: Gergo Petrik Date: Thu, 7 May 2020 11:45:40 +0200 Subject: [PATCH 006/118] added transaction recording --- .../java/com/baeldung/abaproblem/Account.java | 21 ++++++++++++++++--- .../baeldung/abaproblem/AccountUnitTest.java | 14 +++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java index 0204c31fea..558245283a 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java @@ -1,34 +1,49 @@ package com.baeldung.abaproblem; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class Account { private AtomicInteger balance = new AtomicInteger(0); + private List transactionDates = new ArrayList<>(); public int getBalance() { return balance.get(); } + public List getTransactionDates() { + return transactionDates; + } + public boolean withdraw(int amount) throws InterruptedException { int current = getBalance(); if (current < amount) { throw new RuntimeException("Not sufficient balance"); } precessBalance(); - return balance.compareAndSet(current, current - amount); + boolean result = balance.compareAndSet(current, current - amount); + if (result) { + transactionDates.add(System.currentTimeMillis()); + } + return result; } private void precessBalance() throws InterruptedException { - if ("thread 1".equals(Thread.currentThread().getName())) { + if ("thread1".equals(Thread.currentThread().getName())) { TimeUnit.SECONDS.sleep(2); } } public boolean deposit(int amount) { int current = balance.get(); - return balance.compareAndSet(current, current + amount); + boolean result = balance.compareAndSet(current, current + amount); + if (result) { + transactionDates.add(System.currentTimeMillis()); + } + return result; } } diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java index ab88a0f447..457580b96c 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java +++ b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java @@ -4,6 +4,7 @@ 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.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -19,6 +20,7 @@ public class AccountUnitTest { @Test public void zeroBalanceInitializationTest() { assertEquals(0, account.getBalance()); + assertTrue(account.getTransactionDates().isEmpty()); } @Test @@ -55,7 +57,9 @@ public class AccountUnitTest { final int amountToWithdrawByThreadB = 10; final int amountToDepositByThreadB = 10; + assertTrue(account.getTransactionDates().isEmpty()); account.deposit(defaultBalance); + assertEquals(1, account.getTransactionDates().size()); Thread threadA = new Thread(() -> { try { @@ -64,7 +68,7 @@ public class AccountUnitTest { } catch (InterruptedException e) { throw new RuntimeException(e); } - }, "tread 1"); + }, "thread1"); Thread threadB = new Thread(() -> { @@ -80,7 +84,7 @@ public class AccountUnitTest { // thread 1 didn't finish yet, so the original value will be in place for it assertEquals(defaultBalance, account.getBalance()); - }, "thread 2"); + }, "thread2"); threadA.start(); threadB.start(); @@ -89,5 +93,11 @@ public class AccountUnitTest { // compareAndSet operation succeeds for thread 1 assertEquals(defaultBalance - amountToWithdrawByThreadA, account.getBalance()); + + //but there are other transactions + assertNotEquals(2, account.getTransactionDates().size()); + + // thread 2 did two modifications as well + assertEquals(4, account.getTransactionDates().size()); } } From 69c50660de908d542a87bb2f9ca3896ba7c3f5ca Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Sun, 10 May 2020 09:47:28 -0400 Subject: [PATCH 007/118] BAEL-3951: Added JDK 14 record example and associated tests. --- .../com/baeldung/java14/record/Person.java | 22 +++ .../baeldung/java14/record/PersonTest.java | 150 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java create mode 100644 core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java diff --git a/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java new file mode 100644 index 0000000000..33243c4ecf --- /dev/null +++ b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java @@ -0,0 +1,22 @@ +package com.baeldung.java14.record; + +import java.util.Objects; + +public record Person (String name, String address) { + + public static String UNKWOWN_ADDRESS = "Unknown"; + public static String UNNAMED = "Unnamed"; + + public Person { + Objects.requireNonNull(name); + Objects.requireNonNull(address); + } + + public Person(String name) { + this(name, UNKWOWN_ADDRESS); + } + + public static Person unnamed(String address) { + return new Person(UNNAMED, address); + } +} diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java new file mode 100644 index 0000000000..4a7d4ede5f --- /dev/null +++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java @@ -0,0 +1,150 @@ +package com.baeldung.java14.record; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class PersonTest { + + @Test + public void givenSameNameAndAddress_whenEquals_thenPersonsEqual() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person1 = new Person(name, address); + Person person2 = new Person(name, address); + + assertTrue(person1.equals(person2)); + } + + @Test + public void givenDifferentObject_whenEquals_thenNotEqual() { + + Person person = new Person("John Doe", "100 Linda Ln."); + + assertFalse(person.equals(new Object())); + } + + @Test + public void givenDifferentName_whenEquals_thenPersonsNotEqual() { + + String address = "100 Linda Ln."; + + Person person1 = new Person("Jane Doe", address); + Person person2 = new Person("John Doe", address); + + assertFalse(person1.equals(person2)); + } + + @Test + public void givenDifferentAddress_whenEquals_thenPersonsNotEqual() { + + String name = "John Doe"; + + Person person1 = new Person(name, "100 Linda Ln."); + Person person2 = new Person(name, "200 London Ave."); + + assertFalse(person1.equals(person2)); + } + + @Test + public void givenSameNameAndAddress_whenHashCode_thenPersonsEqual() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person1 = new Person(name, address); + Person person2 = new Person(name, address); + + assertEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenDifferentObject_whenHashCode_thenNotEqual() { + + Person person = new Person("John Doe", "100 Linda Ln."); + + assertNotEquals(person.hashCode(), new Object().hashCode()); + } + + @Test + public void givenDifferentName_whenHashCode_thenPersonsNotEqual() { + + String address = "100 Linda Ln."; + + Person person1 = new Person("Jane Doe", address); + Person person2 = new Person("John Doe", address); + + assertNotEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenDifferentAddress_whenHashCode_thenPersonsNotEqual() { + + String name = "John Doe"; + + Person person1 = new Person(name, "100 Linda Ln."); + Person person2 = new Person(name, "200 London Ave."); + + assertNotEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenValidNameAndAddress_whenGetNameAndAddress_thenExpectedValuesReturned() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person = new Person(name, address); + + assertEquals(name, person.name()); + assertEquals(address, person.address()); + } + + @Test + public void givenValidNameAndAddress_whenToString_thenCorrectStringReturned() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person = new Person(name, address); + + assertEquals("Person[name=" + name + ", address=" + address + "]", person.toString()); + } + + @Test(expected = NullPointerException.class) + public void givenNullName_whenConstruct_thenErrorThrown() { + new Person(null, "100 Linda Ln."); + } + + @Test(expected = NullPointerException.class) + public void givenNullAddress_whenConstruct_thenErrorThrown() { + new Person("John Doe", null); + } + + @Test + public void givenUnknownAddress_whenConstructing_thenAddressPopulated() { + + String name = "John Doe"; + + Person person = new Person(name); + + assertEquals(name, person.name()); + assertEquals(Person.UNKWOWN_ADDRESS, person.address()); + } + + @Test + public void givenUnnamed_whenConstructingThroughFactory_thenNamePopulated() { + + String address = "100 Linda Ln."; + + Person person = Person.unnamed(address); + + assertEquals(Person.UNNAMED, person.name()); + assertEquals(address, person.address()); + } +} From 4f7b0d6a645625d115293133f48eb993a6d7b733 Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Sun, 10 May 2020 18:40:27 +0200 Subject: [PATCH 008/118] First commit --- persistence-modules/spring-data-jpa-5/pom.xml | 58 +++++++++++++++++++ .../main/java/com/baeldung/Application.java | 58 +++++++++++++++++++ .../java/com/baeldung/model/Customer.java | 27 +++++++++ .../java/com/baeldung/model/CustomerDto.java | 34 +++++++++++ .../repository/CustomerRepository.java | 13 +++++ .../com/baeldung/service/CustomerService.java | 50 ++++++++++++++++ .../com/baeldung/util/CustomerMapper.java | 15 +++++ 7 files changed, 255 insertions(+) create mode 100644 persistence-modules/spring-data-jpa-5/pom.xml create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java diff --git a/persistence-modules/spring-data-jpa-5/pom.xml b/persistence-modules/spring-data-jpa-5/pom.xml new file mode 100644 index 0000000000..df1cc6c0c4 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + spring-data-jpa-5 + spring-data-jpa-5 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.mapstruct + mapstruct-jdk8 + 1.3.1.Final + provided + + + org.springframework.boot + spring-boot-starter-cache + + + + + src/main/java + + + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.mapstruct + mapstruct-processor + 1.3.1.Final + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..64d0a5e6c6 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java @@ -0,0 +1,58 @@ +package com.baeldung; + +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; + +import com.baeldung.model.Customer; +import com.baeldung.model.CustomerDto; +import com.baeldung.service.CustomerService; + +@SpringBootApplication @EnableCaching +public class Application { + + @Autowired CustomerService service; + @Autowired CacheManager cacheManager; + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Application.class); + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean public CommandLineRunner commandLineRunner(ApplicationContext ctx) throws Exception { + logger.info("-- BASIC LOAD AND SAVE --"); + basicLoadAndSave(); + logger.info("-- BASIC LOAD AND SAVE + MAPPER --"); + basicLoadAndSaveWithMapper(); + return null; + } + + private void basicLoadAndSave() { + Customer myCustomer = service.addCustomer("John", "Doe"); + logger.info("Insert -- " + myCustomer.toString()); + myCustomer = service.updateCustomer(myCustomer.id, "john@doe.com", "+00", "Route 66"); + logger.info("Update -- " + myCustomer.toString()); + } + + private void basicLoadAndSaveWithMapper() { + CustomerDto dto = new CustomerDto(); + dto.firstName = "Johnny"; + dto.lastName = "Doe"; + Customer entity = service.addCustomer(dto); + logger.info("Insert -- " + entity.toString()); + CustomerDto dto2 = new CustomerDto(); + dto2.id = entity.id; + dto2.address = "Mountain View"; + dto2.email = "doe@mail.com"; + dto2.phone = "+44"; + entity = service.updateCustomer(dto2); + logger.info("Update -- " + entity.toString()); + } + +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java new file mode 100644 index 0000000000..91808e7971 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java @@ -0,0 +1,27 @@ +package com.baeldung.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Customer { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + public long id; + public String firstName; + public String lastName; + public String address; + public String email; + public String phone; + //... + public String phone99; + + public Customer() {} + + @Override public String toString() { + return String.format("Customer %s %s, Address: %s, Email: %s, Phone: %s", + this.firstName, this.lastName, this.address, this.email, this.phone); + } +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java new file mode 100644 index 0000000000..8f7803fc32 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java @@ -0,0 +1,34 @@ +package com.baeldung.model; + +public class CustomerDto { + public long id; + public String firstName; + public String lastName; + public String address; + public String email; + public String phone; + //... + public String phone99; + + public CustomerDto() {} + + public CustomerDto(Customer c) { + this.id = c.id; + this.firstName = c.firstName; + this.lastName = c.lastName; + this.address = c.address; + this.email = c.email; + this.phone = c.phone; + } + + public Customer convertToEntity() { + Customer c = new Customer(); + c.id = id; + c.firstName = firstName; + c.lastName = lastName; + c.address = address; + c.email = email; + c.phone = phone; + return c; + } +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java new file mode 100644 index 0000000000..dcde6c3b46 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.repository; + +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.model.Customer; + +@Repository +public interface CustomerRepository extends CrudRepository { + @Cacheable("customers") + Customer findById(long id); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java new file mode 100644 index 0000000000..56afc9e80d --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java @@ -0,0 +1,50 @@ +package com.baeldung.service; + +import javax.transaction.Transactional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.model.Customer; +import com.baeldung.model.CustomerDto; +import com.baeldung.repository.CustomerRepository; +import com.baeldung.util.CustomerMapper; + +@Service @Transactional +public class CustomerService { + + @Autowired CustomerRepository repo; + @Autowired CustomerMapper mapper; + + public Customer addCustomer(String firstName, String lastName) { + Customer myCustomer = new Customer(); + myCustomer.firstName = firstName; + myCustomer.lastName = lastName; + repo.save(myCustomer); + return myCustomer; + } + + public Customer updateCustomer(long id, String email, String phone, String address) { + Customer myCustomer = repo.findById(id); + myCustomer.address = address; + myCustomer.email = email; + myCustomer.phone = phone; + repo.save(myCustomer); + return myCustomer; + } + + public Customer addCustomer(CustomerDto dto) { + Customer myCustomer = new Customer(); + mapper.updateCustomerFromDto(dto, myCustomer); + repo.save(myCustomer); + return myCustomer; + } + + public Customer updateCustomer(CustomerDto dto) { + Customer myCustomer = repo.findById(dto.id); + mapper.updateCustomerFromDto(dto, myCustomer); + repo.save(myCustomer); + return myCustomer; + } + +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java new file mode 100644 index 0000000000..d4f264e33a --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java @@ -0,0 +1,15 @@ +package com.baeldung.util; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; + +import com.baeldung.model.Customer; +import com.baeldung.model.CustomerDto; + +@Mapper(componentModel = "spring") +public interface CustomerMapper { + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateCustomerFromDto(CustomerDto dto, @MappingTarget Customer entity); +} From 48d1c94dc0942a5b2e111c1af02260adc19df174 Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Wed, 13 May 2020 06:06:58 -0400 Subject: [PATCH 009/118] BAEL-3951: Corrected misspelling. --- .../com/baeldung/java14/record/Person.java | 44 +-- .../baeldung/java14/record/PersonTest.java | 300 +++++++++--------- 2 files changed, 172 insertions(+), 172 deletions(-) diff --git a/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java index 33243c4ecf..56cc9f30d9 100644 --- a/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java +++ b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/record/Person.java @@ -1,22 +1,22 @@ -package com.baeldung.java14.record; - -import java.util.Objects; - -public record Person (String name, String address) { - - public static String UNKWOWN_ADDRESS = "Unknown"; - public static String UNNAMED = "Unnamed"; - - public Person { - Objects.requireNonNull(name); - Objects.requireNonNull(address); - } - - public Person(String name) { - this(name, UNKWOWN_ADDRESS); - } - - public static Person unnamed(String address) { - return new Person(UNNAMED, address); - } -} +package com.baeldung.java14.record; + +import java.util.Objects; + +public record Person (String name, String address) { + + public static String UNKNOWN_ADDRESS = "Unknown"; + public static String UNNAMED = "Unnamed"; + + public Person { + Objects.requireNonNull(name); + Objects.requireNonNull(address); + } + + public Person(String name) { + this(name, UNKNOWN_ADDRESS); + } + + public static Person unnamed(String address) { + return new Person(UNNAMED, address); + } +} diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java index 4a7d4ede5f..2a5195efc1 100644 --- a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java +++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/record/PersonTest.java @@ -1,150 +1,150 @@ -package com.baeldung.java14.record; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class PersonTest { - - @Test - public void givenSameNameAndAddress_whenEquals_thenPersonsEqual() { - - String name = "John Doe"; - String address = "100 Linda Ln."; - - Person person1 = new Person(name, address); - Person person2 = new Person(name, address); - - assertTrue(person1.equals(person2)); - } - - @Test - public void givenDifferentObject_whenEquals_thenNotEqual() { - - Person person = new Person("John Doe", "100 Linda Ln."); - - assertFalse(person.equals(new Object())); - } - - @Test - public void givenDifferentName_whenEquals_thenPersonsNotEqual() { - - String address = "100 Linda Ln."; - - Person person1 = new Person("Jane Doe", address); - Person person2 = new Person("John Doe", address); - - assertFalse(person1.equals(person2)); - } - - @Test - public void givenDifferentAddress_whenEquals_thenPersonsNotEqual() { - - String name = "John Doe"; - - Person person1 = new Person(name, "100 Linda Ln."); - Person person2 = new Person(name, "200 London Ave."); - - assertFalse(person1.equals(person2)); - } - - @Test - public void givenSameNameAndAddress_whenHashCode_thenPersonsEqual() { - - String name = "John Doe"; - String address = "100 Linda Ln."; - - Person person1 = new Person(name, address); - Person person2 = new Person(name, address); - - assertEquals(person1.hashCode(), person2.hashCode()); - } - - @Test - public void givenDifferentObject_whenHashCode_thenNotEqual() { - - Person person = new Person("John Doe", "100 Linda Ln."); - - assertNotEquals(person.hashCode(), new Object().hashCode()); - } - - @Test - public void givenDifferentName_whenHashCode_thenPersonsNotEqual() { - - String address = "100 Linda Ln."; - - Person person1 = new Person("Jane Doe", address); - Person person2 = new Person("John Doe", address); - - assertNotEquals(person1.hashCode(), person2.hashCode()); - } - - @Test - public void givenDifferentAddress_whenHashCode_thenPersonsNotEqual() { - - String name = "John Doe"; - - Person person1 = new Person(name, "100 Linda Ln."); - Person person2 = new Person(name, "200 London Ave."); - - assertNotEquals(person1.hashCode(), person2.hashCode()); - } - - @Test - public void givenValidNameAndAddress_whenGetNameAndAddress_thenExpectedValuesReturned() { - - String name = "John Doe"; - String address = "100 Linda Ln."; - - Person person = new Person(name, address); - - assertEquals(name, person.name()); - assertEquals(address, person.address()); - } - - @Test - public void givenValidNameAndAddress_whenToString_thenCorrectStringReturned() { - - String name = "John Doe"; - String address = "100 Linda Ln."; - - Person person = new Person(name, address); - - assertEquals("Person[name=" + name + ", address=" + address + "]", person.toString()); - } - - @Test(expected = NullPointerException.class) - public void givenNullName_whenConstruct_thenErrorThrown() { - new Person(null, "100 Linda Ln."); - } - - @Test(expected = NullPointerException.class) - public void givenNullAddress_whenConstruct_thenErrorThrown() { - new Person("John Doe", null); - } - - @Test - public void givenUnknownAddress_whenConstructing_thenAddressPopulated() { - - String name = "John Doe"; - - Person person = new Person(name); - - assertEquals(name, person.name()); - assertEquals(Person.UNKWOWN_ADDRESS, person.address()); - } - - @Test - public void givenUnnamed_whenConstructingThroughFactory_thenNamePopulated() { - - String address = "100 Linda Ln."; - - Person person = Person.unnamed(address); - - assertEquals(Person.UNNAMED, person.name()); - assertEquals(address, person.address()); - } -} +package com.baeldung.java14.record; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class PersonTest { + + @Test + public void givenSameNameAndAddress_whenEquals_thenPersonsEqual() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person1 = new Person(name, address); + Person person2 = new Person(name, address); + + assertTrue(person1.equals(person2)); + } + + @Test + public void givenDifferentObject_whenEquals_thenNotEqual() { + + Person person = new Person("John Doe", "100 Linda Ln."); + + assertFalse(person.equals(new Object())); + } + + @Test + public void givenDifferentName_whenEquals_thenPersonsNotEqual() { + + String address = "100 Linda Ln."; + + Person person1 = new Person("Jane Doe", address); + Person person2 = new Person("John Doe", address); + + assertFalse(person1.equals(person2)); + } + + @Test + public void givenDifferentAddress_whenEquals_thenPersonsNotEqual() { + + String name = "John Doe"; + + Person person1 = new Person(name, "100 Linda Ln."); + Person person2 = new Person(name, "200 London Ave."); + + assertFalse(person1.equals(person2)); + } + + @Test + public void givenSameNameAndAddress_whenHashCode_thenPersonsEqual() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person1 = new Person(name, address); + Person person2 = new Person(name, address); + + assertEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenDifferentObject_whenHashCode_thenNotEqual() { + + Person person = new Person("John Doe", "100 Linda Ln."); + + assertNotEquals(person.hashCode(), new Object().hashCode()); + } + + @Test + public void givenDifferentName_whenHashCode_thenPersonsNotEqual() { + + String address = "100 Linda Ln."; + + Person person1 = new Person("Jane Doe", address); + Person person2 = new Person("John Doe", address); + + assertNotEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenDifferentAddress_whenHashCode_thenPersonsNotEqual() { + + String name = "John Doe"; + + Person person1 = new Person(name, "100 Linda Ln."); + Person person2 = new Person(name, "200 London Ave."); + + assertNotEquals(person1.hashCode(), person2.hashCode()); + } + + @Test + public void givenValidNameAndAddress_whenGetNameAndAddress_thenExpectedValuesReturned() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person = new Person(name, address); + + assertEquals(name, person.name()); + assertEquals(address, person.address()); + } + + @Test + public void givenValidNameAndAddress_whenToString_thenCorrectStringReturned() { + + String name = "John Doe"; + String address = "100 Linda Ln."; + + Person person = new Person(name, address); + + assertEquals("Person[name=" + name + ", address=" + address + "]", person.toString()); + } + + @Test(expected = NullPointerException.class) + public void givenNullName_whenConstruct_thenErrorThrown() { + new Person(null, "100 Linda Ln."); + } + + @Test(expected = NullPointerException.class) + public void givenNullAddress_whenConstruct_thenErrorThrown() { + new Person("John Doe", null); + } + + @Test + public void givenUnknownAddress_whenConstructing_thenAddressPopulated() { + + String name = "John Doe"; + + Person person = new Person(name); + + assertEquals(name, person.name()); + assertEquals(Person.UNKNOWN_ADDRESS, person.address()); + } + + @Test + public void givenUnnamed_whenConstructingThroughFactory_thenNamePopulated() { + + String address = "100 Linda Ln."; + + Person person = Person.unnamed(address); + + assertEquals(Person.UNNAMED, person.name()); + assertEquals(address, person.address()); + } +} From 9ea4e4f04ef90d3267f0c2ab7dd6f8431f6a03e1 Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Sat, 16 May 2020 17:56:00 +0200 Subject: [PATCH 010/118] Simplified + refactored --- .../main/java/com/baeldung/Application.java | 14 ++++------- .../java/com/baeldung/model/Customer.java | 9 +++----- .../java/com/baeldung/model/CustomerDto.java | 23 +++++++------------ .../com/baeldung/service/CustomerService.java | 9 +++----- 4 files changed, 19 insertions(+), 36 deletions(-) diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java index 64d0a5e6c6..34e86fe135 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java @@ -34,22 +34,18 @@ public class Application { } private void basicLoadAndSave() { - Customer myCustomer = service.addCustomer("John", "Doe"); + Customer myCustomer = service.addCustomer("John"); logger.info("Insert -- " + myCustomer.toString()); - myCustomer = service.updateCustomer(myCustomer.id, "john@doe.com", "+00", "Route 66"); + myCustomer = service.updateCustomer(myCustomer.id, "+00"); logger.info("Update -- " + myCustomer.toString()); } private void basicLoadAndSaveWithMapper() { - CustomerDto dto = new CustomerDto(); - dto.firstName = "Johnny"; - dto.lastName = "Doe"; + CustomerDto dto = new CustomerDto(null); + dto.name = "Johnny"; Customer entity = service.addCustomer(dto); logger.info("Insert -- " + entity.toString()); - CustomerDto dto2 = new CustomerDto(); - dto2.id = entity.id; - dto2.address = "Mountain View"; - dto2.email = "doe@mail.com"; + CustomerDto dto2 = new CustomerDto(entity.id); dto2.phone = "+44"; entity = service.updateCustomer(dto2); logger.info("Update -- " + entity.toString()); diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java index 91808e7971..28c5d5c76c 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java @@ -10,10 +10,7 @@ public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public long id; - public String firstName; - public String lastName; - public String address; - public String email; + public String name; public String phone; //... public String phone99; @@ -21,7 +18,7 @@ public class Customer { public Customer() {} @Override public String toString() { - return String.format("Customer %s %s, Address: %s, Email: %s, Phone: %s", - this.firstName, this.lastName, this.address, this.email, this.phone); + return String.format("Customer %s, Phone: %s", + this.name, this.phone); } } diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java index 8f7803fc32..c4601d5b81 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java @@ -1,33 +1,26 @@ package com.baeldung.model; public class CustomerDto { - public long id; - public String firstName; - public String lastName; - public String address; - public String email; + private long id; + public String name; public String phone; //... - public String phone99; + private String phone99; - public CustomerDto() {} + public CustomerDto(long id) { + this.id = id; + } public CustomerDto(Customer c) { this.id = c.id; - this.firstName = c.firstName; - this.lastName = c.lastName; - this.address = c.address; - this.email = c.email; + this.name = c.name; this.phone = c.phone; } public Customer convertToEntity() { Customer c = new Customer(); c.id = id; - c.firstName = firstName; - c.lastName = lastName; - c.address = address; - c.email = email; + c.name = name; c.phone = phone; return c; } diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java index 56afc9e80d..3101cd8ece 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java @@ -16,18 +16,15 @@ public class CustomerService { @Autowired CustomerRepository repo; @Autowired CustomerMapper mapper; - public Customer addCustomer(String firstName, String lastName) { + public Customer addCustomer(String name) { Customer myCustomer = new Customer(); - myCustomer.firstName = firstName; - myCustomer.lastName = lastName; + myCustomer.name = name; repo.save(myCustomer); return myCustomer; } - public Customer updateCustomer(long id, String email, String phone, String address) { + public Customer updateCustomer(long id, String phone) { Customer myCustomer = repo.findById(id); - myCustomer.address = address; - myCustomer.email = email; myCustomer.phone = phone; repo.save(myCustomer); return myCustomer; From 12ef94be3959112f2b177c570b33c77cc09264b2 Mon Sep 17 00:00:00 2001 From: Gergo Petrik Date: Sun, 17 May 2020 10:07:47 +0200 Subject: [PATCH 011/118] added revision number and cas failure count --- .../java/com/baeldung/abaproblem/Account.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java index 558245283a..ee1bdcd55b 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/abaproblem/Account.java @@ -1,39 +1,53 @@ package com.baeldung.abaproblem; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class Account { - private AtomicInteger balance = new AtomicInteger(0); - private List transactionDates = new ArrayList<>(); + private AtomicInteger balance; + private AtomicInteger transactionCount; + private ThreadLocal currentThreadCASFailureCount; + + public Account() { + this.balance = new AtomicInteger(0); + this.transactionCount = new AtomicInteger(0); + this.currentThreadCASFailureCount = new ThreadLocal<>(); + this.currentThreadCASFailureCount.set(0); + } public int getBalance() { return balance.get(); } - public List getTransactionDates() { - return transactionDates; + public int getTransactionCount() { + return transactionCount.get(); } - public boolean withdraw(int amount) throws InterruptedException { + public int getCurrentThreadCASFailureCount() { + return currentThreadCASFailureCount.get(); + } + + public boolean withdraw(int amount) { int current = getBalance(); - if (current < amount) { - throw new RuntimeException("Not sufficient balance"); - } - precessBalance(); + maybeWait(); boolean result = balance.compareAndSet(current, current - amount); if (result) { - transactionDates.add(System.currentTimeMillis()); + transactionCount.incrementAndGet(); + } else { + int currentCASFailureCount = currentThreadCASFailureCount.get(); + currentThreadCASFailureCount.set(currentCASFailureCount + 1); } return result; } - private void precessBalance() throws InterruptedException { + private void maybeWait() { if ("thread1".equals(Thread.currentThread().getName())) { - TimeUnit.SECONDS.sleep(2); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } } @@ -41,7 +55,10 @@ public class Account { int current = balance.get(); boolean result = balance.compareAndSet(current, current + amount); if (result) { - transactionDates.add(System.currentTimeMillis()); + transactionCount.incrementAndGet(); + } else { + int currentCASFailureCount = currentThreadCASFailureCount.get(); + currentThreadCASFailureCount.set(currentCASFailureCount + 1); } return result; } From 5b0097f698047fd89ed157439f9403f8cea73f13 Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Mon, 18 May 2020 09:52:39 +0300 Subject: [PATCH 012/118] BAEL-3896: OpenAPI JSON Objects in Query Params - Swagger file --- .../jsonparam/JsonParamController.java | 62 ------- .../baeldung/jsonparam/ParamObjectDTO.java | 33 ---- .../jsonParamOpenApiSwaggerDefinition | 154 ++++++++++++++++++ 3 files changed, 154 insertions(+), 95 deletions(-) delete mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java delete mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java create mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java b/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java deleted file mode 100644 index d2a09296c2..0000000000 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/JsonParamController.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jsonparam; - -import com.baeldung.controllers.DeferredResultController; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; - -@Controller -@RestController -@RequestMapping("/api") -public class JsonParamController { - private final static Logger LOG = LoggerFactory.getLogger(DeferredResultController.class); - - @GetMapping(value = "/tickets") - public String testQueryParamApi(@RequestParam("params") String params) { - // params={"type":"foo","color":"green"} - ParamObjectDTO paramObjectDTO; - ObjectMapper objectMapper = new ObjectMapper(); - try { - paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); - System.out.println(paramObjectDTO); - // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object - } catch (JsonProcessingException e) { - LOG.info("Json Processing Exception"); - } - return params; - } - - @GetMapping(value = "/tickets2") - public String testGetBodyParamApi(@RequestBody String params) { - // params={"type":"foo","color":"green"} - ParamObjectDTO paramObjectDTO; - ObjectMapper objectMapper = new ObjectMapper(); - try { - paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); - System.out.println(paramObjectDTO); - // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object - } catch (JsonProcessingException e) { - LOG.info("Json Processing Exception"); - } - return params; - } - - @PostMapping(value = "/tickets") - public String testBodyParamApi(@RequestBody String params) { - // params={"type":"foo","color":"green"} - ParamObjectDTO paramObjectDTO; - ObjectMapper objectMapper = new ObjectMapper(); - try { - paramObjectDTO = objectMapper.readValue(params, ParamObjectDTO.class); - System.out.println(paramObjectDTO); - // use paramObjectDTO where you have {"type":"foo","color":"green"} JSON data as Object - } catch (JsonProcessingException e) { - LOG.info("Json Processing Exception"); - } - return params; - } - -} diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java b/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java deleted file mode 100644 index a738180fa6..0000000000 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/ParamObjectDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.jsonparam; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ParamObjectDTO { - private String type; - private String color; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getColor() { - return color; - } - - public void setColor(String color) { - this.color = color; - } - - @Override - public String toString() { - return "ParamObjectDTO{" + - "type='" + type + '\'' + - ", color='" + color + '\'' + - '}'; - } -} diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition new file mode 100644 index 0000000000..9f9bcb788a --- /dev/null +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition @@ -0,0 +1,154 @@ +swagger: '2.0' +... +paths: + /tickets: + get: + parameters: + - in: query + name: params + required: true + description: A JSON object with the `type` and `color` properties + type: string + example: '{"type":"foo","color":"green"}' + +swagger: '2.0' +... +paths: + /tickets: + post: + requestBody: + description: Parameter is an object that should be serialized as JSON + content: + application/json: + schema: + type: string + example: '{"type":"foo","color":"green"}' + responses: + '200': + description: successful process + +"/api/tickets": { + "get": { + "tags": [ + "account-resource" + ], + "summary": "testQueryParamApi", + "operationId": "testQueryParamApiUsingGET", + "produces": [ + "*/*" + ], + "parameters": [ + { + "name": "params", + "in": "query", + "description": "params", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + }, + "deprecated": false + }, + "post": { + "tags": [ + "account-resource" + ], + "summary": "testBodyParamApi", + "operationId": "testBodyParamApiUsingPOST", + "consumes": [ + "application/json" + ], + "produces": [ + "*/*" + ], + "parameters": [ + { + "in": "body", + "name": "params", + "description": "params", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "201": { + "description": "Created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + }, + "deprecated": false + } +}, +"/api/tickets2": { + "get": { + "tags": [ + "account-resource" + ], + "summary": "testGetBodyParamApi", + "operationId": "testGetBodyParamApiUsingGET", + "produces": [ + "*/*" + ], + "parameters": [ + { + "in": "body", + "name": "params", + "description": "params", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + }, + "deprecated": false + } +} From c9453fe33a0a296e6d41161b9fb4b6e27ecd3bef Mon Sep 17 00:00:00 2001 From: Gergo Petrik Date: Mon, 18 May 2020 16:33:03 +0200 Subject: [PATCH 013/118] adding account unit test --- .../baeldung/abaproblem/AccountUnitTest.java | 65 +++++++++---------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java index 457580b96c..aa5f0f7997 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java +++ b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/abaproblem/AccountUnitTest.java @@ -5,7 +5,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class AccountUnitTest { @@ -20,7 +19,8 @@ public class AccountUnitTest { @Test public void zeroBalanceInitializationTest() { assertEquals(0, account.getBalance()); - assertTrue(account.getTransactionDates().isEmpty()); + assertEquals(0, account.getTransactionCount()); + assertEquals(0, account.getCurrentThreadCASFailureCount()); } @Test @@ -44,60 +44,55 @@ public class AccountUnitTest { assertEquals(defaultBalance - moneyToWithdraw, account.getBalance()); } - @Test - public void withdrawWithoutSufficientBalanceTest() { - assertThrows(RuntimeException.class, () -> account.withdraw(10)); - } - @Test public void abaProblemTest() throws InterruptedException { final int defaultBalance = 50; - final int amountToWithdrawByThreadA = 20; - final int amountToWithdrawByThreadB = 10; - final int amountToDepositByThreadB = 10; + final int amountToWithdrawByThread1 = 20; + final int amountToWithdrawByThread2 = 10; + final int amountToDepositByThread2 = 10; - assertTrue(account.getTransactionDates().isEmpty()); + assertEquals(0, account.getTransactionCount()); + assertEquals(0, account.getCurrentThreadCASFailureCount()); account.deposit(defaultBalance); - assertEquals(1, account.getTransactionDates().size()); + assertEquals(1, account.getTransactionCount()); + + Thread thread1 = new Thread(() -> { + + // this will take longer due to the name of the thread + assertTrue(account.withdraw(amountToWithdrawByThread1)); + + // thread 1 fails to capture ABA problem + assertNotEquals(1, account.getCurrentThreadCASFailureCount()); - Thread threadA = new Thread(() -> { - try { - // this will take longer due to the name of the thread - assertTrue(account.withdraw(amountToWithdrawByThreadA)); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } }, "thread1"); - Thread threadB = new Thread(() -> { + Thread thread2 = new Thread(() -> { - assertTrue(account.deposit(amountToDepositByThreadB)); - assertEquals(defaultBalance + amountToDepositByThreadB, account.getBalance()); - try { - // this will be fast due to the name of the thread - assertTrue(account.withdraw(amountToWithdrawByThreadB)); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + assertTrue(account.deposit(amountToDepositByThread2)); + assertEquals(defaultBalance + amountToDepositByThread2, account.getBalance()); + + // this will be fast due to the name of the thread + assertTrue(account.withdraw(amountToWithdrawByThread2)); // thread 1 didn't finish yet, so the original value will be in place for it assertEquals(defaultBalance, account.getBalance()); + assertEquals(0, account.getCurrentThreadCASFailureCount()); }, "thread2"); - threadA.start(); - threadB.start(); - threadA.join(); - threadB.join(); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(); // compareAndSet operation succeeds for thread 1 - assertEquals(defaultBalance - amountToWithdrawByThreadA, account.getBalance()); + assertEquals(defaultBalance - amountToWithdrawByThread1, account.getBalance()); //but there are other transactions - assertNotEquals(2, account.getTransactionDates().size()); + assertNotEquals(2, account.getTransactionCount()); // thread 2 did two modifications as well - assertEquals(4, account.getTransactionDates().size()); + assertEquals(4, account.getTransactionCount()); } } From cd51e118df520c67f9e2c58b13c3c1bfca494d82 Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Mon, 18 May 2020 19:15:18 +0200 Subject: [PATCH 014/118] Fixed compilation error --- .../src/main/java/com/baeldung/model/CustomerDto.java | 4 ++++ .../src/main/java/com/baeldung/service/CustomerService.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java index c4601d5b81..74b909aad8 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java @@ -17,6 +17,10 @@ public class CustomerDto { this.phone = c.phone; } + public long getId() { + return this.id; + } + public Customer convertToEntity() { Customer c = new Customer(); c.id = id; diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java index 3101cd8ece..9ebbb0c814 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java @@ -38,7 +38,7 @@ public class CustomerService { } public Customer updateCustomer(CustomerDto dto) { - Customer myCustomer = repo.findById(dto.id); + Customer myCustomer = repo.findById(dto.getId()); mapper.updateCustomerFromDto(dto, myCustomer); repo.save(myCustomer); return myCustomer; From 658835bfe850d598462331509c8c7745f816f6eb Mon Sep 17 00:00:00 2001 From: Kirill Vlasov Date: Tue, 19 May 2020 15:53:40 +0500 Subject: [PATCH 015/118] BAEL-3824 Circular view path exception --- .../spring-boot-mvc-3/.gitignore | 25 ++++++++++++++++ .../spring-boot-mvc-3/README.md | 5 ++++ spring-boot-modules/spring-boot-mvc-3/pom.xml | 29 +++++++++++++++++++ .../CircularViewPathApplication.java | 21 ++++++++++++++ .../CircularViewPathController.java | 16 ++++++++++ .../src/main/resources/logback.xml | 13 +++++++++ .../src/main/resources/templates/path.html | 13 +++++++++ 7 files changed, 122 insertions(+) create mode 100644 spring-boot-modules/spring-boot-mvc-3/.gitignore create mode 100644 spring-boot-modules/spring-boot-mvc-3/README.md create mode 100644 spring-boot-modules/spring-boot-mvc-3/pom.xml create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/circularviewpath/CircularViewPathApplication.java create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/controller/circularviewpath/CircularViewPathController.java create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/resources/logback.xml create mode 100644 spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/path.html diff --git a/spring-boot-modules/spring-boot-mvc-3/.gitignore b/spring-boot-modules/spring-boot-mvc-3/.gitignore new file mode 100644 index 0000000000..82eca336e3 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/README.md b/spring-boot-modules/spring-boot-mvc-3/README.md new file mode 100644 index 0000000000..1050adb2d6 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/README.md @@ -0,0 +1,5 @@ +## Spring Boot MVC + +This module contains articles about Spring Web MVC in Spring Boot projects. + +### Relevant Articles: diff --git a/spring-boot-modules/spring-boot-mvc-3/pom.xml b/spring-boot-modules/spring-boot-mvc-3/pom.xml new file mode 100644 index 0000000000..64e8a99c6c --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + spring-boot-mvc-3 + spring-boot-mvc-3 + jar + Module For Spring Boot MVC Web + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/circularviewpath/CircularViewPathApplication.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/circularviewpath/CircularViewPathApplication.java new file mode 100644 index 0000000000..deb50e2ed7 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/circularviewpath/CircularViewPathApplication.java @@ -0,0 +1,21 @@ +package com.baeldung.circularviewpath; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Spring Boot launcher for an application + * + */ +@SpringBootApplication(scanBasePackages = "com.baeldung.controller.circularviewpath") +public class CircularViewPathApplication { + + /** + * Launches a Spring Boot application + * + * @param args null + */ + public static void main(String[] args) { + SpringApplication.run(CircularViewPathApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/controller/circularviewpath/CircularViewPathController.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/controller/circularviewpath/CircularViewPathController.java new file mode 100644 index 0000000000..a4d6a97f7d --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/controller/circularviewpath/CircularViewPathController.java @@ -0,0 +1,16 @@ +package com.baeldung.controller.circularviewpath; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class CircularViewPathController { + + /** + * A request mapping which may cause circular view path exception + */ + @GetMapping("/path") + public String path() { + return "path"; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/logback.xml b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/path.html b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/path.html new file mode 100644 index 0000000000..b329797275 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/path.html @@ -0,0 +1,13 @@ + + + + + + + path.html + + + +

path.html

+ + \ No newline at end of file From 020fcd9229cf29513632bf816b1faea171c35db3 Mon Sep 17 00:00:00 2001 From: musibs Date: Sat, 23 May 2020 15:23:26 +0530 Subject: [PATCH 016/118] BAEL 4064 Out of Memory Error --- .../error/oom/TestExecutorService.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java b/core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java new file mode 100644 index 0000000000..d51faa055d --- /dev/null +++ b/core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java @@ -0,0 +1,39 @@ +package com.baeldung.error.oom; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +import org.junit.jupiter.api.Test; + +public class TestExecutorService { + + @Test + public void givenAnExecutorService_WhenMoreTasksSubmitted_ThenAdditionalTasksWait() { + + //Given + int noOfThreads = 5; + ExecutorService executorService = Executors.newFixedThreadPool(noOfThreads); + + Runnable runnableTask = () -> { + try { + TimeUnit.HOURS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }; + + //When + IntStream.rangeClosed(1, 10) + .forEach(i -> executorService.submit(runnableTask)); + + //Then + assertThat(((ThreadPoolExecutor )executorService).getQueue().size(), is(equalTo(5))); + } +} From 59afec1c00dcdabcdd3110d3815c0840a6bcc9a2 Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Sat, 23 May 2020 20:06:43 +0300 Subject: [PATCH 017/118] BAEL-3896: OpenAPI JSON Objects in Query Params - README file revert + required changes --- spring-rest-http/README.md | 1 - .../jsonParamOpenApiSwagger3Definition | 32 ++ .../jsonParamOpenApiSwaggerDefinition | 276 ++++++++++-------- 3 files changed, 179 insertions(+), 130 deletions(-) create mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition diff --git a/spring-rest-http/README.md b/spring-rest-http/README.md index cba017eb74..35793cb281 100644 --- a/spring-rest-http/README.md +++ b/spring-rest-http/README.md @@ -13,4 +13,3 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring RequestMapping](https://www.baeldung.com/spring-requestmapping) - [Guide to DeferredResult in Spring](https://www.baeldung.com/spring-deferred-result) - [Using JSON Patch in Spring REST APIs](https://www.baeldung.com/spring-rest-json-patch) -- [OpenAPI JSON Objects in Query Params](https://www.baeldung.com/openapi-json-objects-in-query-params) diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition new file mode 100644 index 0000000000..218e24b12b --- /dev/null +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition @@ -0,0 +1,32 @@ +swagger: '3.0' +info: + title: Sample API to send JSON objects as query parameters using OpenAPI 3 + description: API description. + version: 1.0.0 + +paths: + /tickets: + get: + parameters: + - in: query + name: params + required: true + # Parameter is an object that should be serialized as JSON + content: + application/json: + schema: + type: object + properties: + type: + type: string + name: + color: string + responses: + '200': + description: successful process + '401': + description: Unauthorized + '403': + description: Forbidden + '404': + description: Not Found diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition index 9f9bcb788a..3261736e15 100644 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition +++ b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition @@ -1,5 +1,9 @@ swagger: '2.0' -... +info: + title: Sample API to send JSON objects as query parameters using OpenAPI 2 + description: API description. + version: 1.0.0 + paths: /tickets: get: @@ -10,10 +14,16 @@ paths: description: A JSON object with the `type` and `color` properties type: string example: '{"type":"foo","color":"green"}' + responses: + '200': + description: successful process + '401': + description: Unauthorized + '403': + description: Forbidden + '404': + description: Not Found -swagger: '2.0' -... -paths: /tickets: post: requestBody: @@ -26,129 +36,137 @@ paths: responses: '200': description: successful process + '201': + description: Created + '401': + description: Unauthorized + '403': + description: Forbidden + '404': + description: Not Found -"/api/tickets": { - "get": { - "tags": [ - "account-resource" - ], - "summary": "testQueryParamApi", - "operationId": "testQueryParamApiUsingGET", - "produces": [ - "*/*" - ], - "parameters": [ - { - "name": "params", - "in": "query", - "description": "params", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden" - }, - "404": { - "description": "Not Found" - } - }, - "deprecated": false - }, - "post": { - "tags": [ - "account-resource" - ], - "summary": "testBodyParamApi", - "operationId": "testBodyParamApiUsingPOST", - "consumes": [ - "application/json" - ], - "produces": [ - "*/*" - ], - "parameters": [ - { - "in": "body", - "name": "params", - "description": "params", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "string" - } - }, - "201": { - "description": "Created" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden" - }, - "404": { - "description": "Not Found" - } - }, - "deprecated": false - } -}, -"/api/tickets2": { - "get": { - "tags": [ - "account-resource" - ], - "summary": "testGetBodyParamApi", - "operationId": "testGetBodyParamApiUsingGET", - "produces": [ - "*/*" - ], - "parameters": [ - { - "in": "body", - "name": "params", - "description": "params", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden" - }, - "404": { - "description": "Not Found" - } - }, - "deprecated": false - } -} + /api/tickets: { + get: { + tags: [ + "account-resource" + ], + summary: "testQueryParamApi", + operationId: "testQueryParamApiUsingGET", + produces: [ + "*/*" + ], + parameters: [ + { + name: "params", + in: "query", + description: "params", + required: true, + type: "string" + } + ], + responses: { + 200: { + description: "OK", + schema: { + type: "string" + } + }, + 401: { + description: "Unauthorized" + }, + 403: { + description: "Forbidden" + }, + 404: { + description: "Not Found" + } + }, + deprecated: false + }, + post: { + tags: [ + "account-resource" + ], + summary: "testBodyParamApi", + operationId: "testBodyParamApiUsingPOST", + consumes: [ + "application/json" + ], + produces: [ + "*/*" + ], + parameters: [ + { + in: "body", + name: "params", + description: "params", + required: true, + schema: { + type: "string" + } + } + ], + responses: { + 200: { + description: "OK", + schema: { + type: "string" + } + }, + 201: { + description: "Created" + }, + 401: { + description: "Unauthorized" + }, + 403: { + description: "Forbidden" + }, + 404: { + description: "Not Found" + } + }, + deprecated: false + } + }, + /api/tickets2: { + get: { + tags: [ + "account-resource" + ], + summary: "testGetBodyParamApi", + operationId: "testGetBodyParamApiUsingGET", + produces: [ + "*/*" + ], + parameters: [ + { + in: "body", + name: "params", + description: "params", + required: true, + schema: { + type: "string" + } + } + ], + responses: { + 200: { + description: "OK", + schema: { + type: "string" + } + }, + 401: { + description: "Unauthorized" + }, + 403: { + description: "Forbidden" + }, + 404: { + description: "Not Found" + } + }, + deprecated: false + } + } From 8f1de1c3b702a07307e172b8745ece9c116f5f05 Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Sun, 24 May 2020 13:58:50 +0530 Subject: [PATCH 018/118] BAEL3889 - Kafka Mock Producer --- .../baeldung/kafka/EvenOddPartitioner.java | 16 +++ .../com/baeldung/kafka/KafkaProducer.java | 40 ++++++ .../baeldung/kafka/KafkaProducerUnitTest.java | 114 ++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java create mode 100644 libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java create mode 100644 libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java diff --git a/libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java b/libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java new file mode 100644 index 0000000000..12c86828dd --- /dev/null +++ b/libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java @@ -0,0 +1,16 @@ +package com.baeldung.kafka; + +import org.apache.kafka.clients.producer.internals.DefaultPartitioner; +import org.apache.kafka.common.Cluster; + +public class EvenOddPartitioner extends DefaultPartitioner { + + @Override + public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { + + if (((String)key).length() % 2 == 0) + return 0; + + return 1; + } +} diff --git a/libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java b/libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java new file mode 100644 index 0000000000..8574cd1c40 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java @@ -0,0 +1,40 @@ +package com.baeldung.kafka; + +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; + +import java.util.concurrent.Future; + +public class KafkaProducer { + + private final Producer producer; + + public KafkaProducer(Producer producer) { + this.producer = producer; + } + + public Future send(String key, String value) { + ProducerRecord record = new ProducerRecord("topic_sports_news", + key, value); + return producer.send(record); + } + + public void flush() { + producer.flush(); + } + + public void beginTransaction() { + producer.beginTransaction(); + } + + public void initTransaction() { + producer.initTransactions(); + } + + public void commitTransaction() { + producer.commitTransaction(); + } + + +} diff --git a/libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java b/libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java new file mode 100644 index 0000000000..ce3803322c --- /dev/null +++ b/libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java @@ -0,0 +1,114 @@ +package com.baeldung.kafka; + +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.apache.kafka.common.Cluster; +import org.apache.kafka.common.Node; +import org.apache.kafka.common.PartitionInfo; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static java.util.Collections.emptySet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class KafkaProducerUnitTest { + + private final String TOPIC_NAME = "topic_sports_news"; + + private KafkaProducer kafkaProducer; + private MockProducer mockProducer; + + private void buildMockProducer(boolean autoComplete) { + this.mockProducer = new MockProducer<>(autoComplete, new StringSerializer(), new StringSerializer()); + } + + @Test + void givenKeyValue_whenSend_thenVerifyHistory() throws ExecutionException, InterruptedException { + + buildMockProducer(true); + //when + kafkaProducer = new KafkaProducer(mockProducer); + Future recordMetadataFuture = kafkaProducer.send("data", "{\"site\" : \"baeldung\"}"); + + //then + assertTrue(mockProducer.history().size() == 1); + assertTrue(mockProducer.history().get(0).key().equalsIgnoreCase("data")); + assertTrue(recordMetadataFuture.get().partition() == 0); + + } + + @Test + void givenKeyValue_whenSend_thenSendOnlyAfterFlush() { + + buildMockProducer(false); + //when + kafkaProducer = new KafkaProducer(mockProducer); + Future record = kafkaProducer.send("data", "{\"site\" : \"baeldung\"}"); + assertFalse(record.isDone()); + + //then + kafkaProducer.flush(); + assertTrue(record.isDone()); + } + + @Test + void givenKeyValue_whenSend_thenReturnException() { + + buildMockProducer(false); + //when + kafkaProducer = new KafkaProducer(mockProducer); + Future record = kafkaProducer.send("site", "{\"site\" : \"baeldung\"}"); + RuntimeException e = new RuntimeException(); + mockProducer.errorNext(e); + //then + try { + record.get(); + } catch (ExecutionException | InterruptedException ex) { + assertEquals(e, ex.getCause()); + } + assertTrue(record.isDone()); + } + + @Test + void givenKeyValue_whenSendWithTxn_thenSendOnlyOnTxnCommit() { + + buildMockProducer(true); + //when + kafkaProducer = new KafkaProducer(mockProducer); + kafkaProducer.initTransaction(); + kafkaProducer.beginTransaction(); + Future record = kafkaProducer.send("data", "{\"site\" : \"baeldung\"}"); + + //then + assertTrue(mockProducer.history().isEmpty()); + kafkaProducer.commitTransaction(); + assertTrue(mockProducer.history().size() == 1); + } + + @Test + void givenKeyValue_whenSendWithPartitioning_thenVerifyPartitionNumber() throws ExecutionException, InterruptedException { + + PartitionInfo partitionInfo0 = new PartitionInfo(TOPIC_NAME, 0, null, null, null); + PartitionInfo partitionInfo1 = new PartitionInfo(TOPIC_NAME, 1, null, null, null); + List list = new ArrayList<>(); + list.add(partitionInfo0); + list.add(partitionInfo1); + Cluster cluster = new Cluster("kafkab", new ArrayList(), list, emptySet(), emptySet()); + this.mockProducer = new MockProducer<>(cluster, true, new EvenOddPartitioner(), new StringSerializer(), new StringSerializer()); + //when + kafkaProducer = new KafkaProducer(mockProducer); + Future recordMetadataFuture = kafkaProducer.send("partition", "{\"site\" : \"baeldung\"}"); + + //then + assertTrue(recordMetadataFuture.get().partition() == 1); + + } + +} \ No newline at end of file From 715147e7dc2ef0f13cf8b9845b2de049bc66073f Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Sun, 24 May 2020 11:44:26 +0200 Subject: [PATCH 019/118] Refactored packages, added test cases, added structured class case --- .../main/java/com/baeldung/Application.java | 54 ------------- .../PartialUpdateApplication.java | 20 +++++ .../partialupdate/model/ContactPhone.java | 22 ++++++ .../{ => partialupdate}/model/Customer.java | 0 .../model/CustomerDto.java | 0 .../model/CustomerStructured.java | 26 ++++++ .../repository/ContactPhoneRepository.java | 12 +++ .../repository/CustomerRepository.java | 4 +- .../CustomerStructuredRepository.java | 11 +++ .../service/CustomerService.java | 79 +++++++++++++++++++ .../util/CustomerMapper.java | 6 +- .../com/baeldung/service/CustomerService.java | 47 ----------- .../partialupdate/PartialUpdateUnitTest.java | 56 +++++++++++++ 13 files changed, 231 insertions(+), 106 deletions(-) delete mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java rename persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/{ => partialupdate}/model/Customer.java (100%) rename persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/{ => partialupdate}/model/CustomerDto.java (100%) create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java rename persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/{ => partialupdate}/repository/CustomerRepository.java (76%) create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java create mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java rename persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/{ => partialupdate}/util/CustomerMapper.java (73%) delete mode 100644 persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java create mode 100644 persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java deleted file mode 100644 index 34e86fe135..0000000000 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/Application.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung; - -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; - -import com.baeldung.model.Customer; -import com.baeldung.model.CustomerDto; -import com.baeldung.service.CustomerService; - -@SpringBootApplication @EnableCaching -public class Application { - - @Autowired CustomerService service; - @Autowired CacheManager cacheManager; - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Application.class); - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - - @Bean public CommandLineRunner commandLineRunner(ApplicationContext ctx) throws Exception { - logger.info("-- BASIC LOAD AND SAVE --"); - basicLoadAndSave(); - logger.info("-- BASIC LOAD AND SAVE + MAPPER --"); - basicLoadAndSaveWithMapper(); - return null; - } - - private void basicLoadAndSave() { - Customer myCustomer = service.addCustomer("John"); - logger.info("Insert -- " + myCustomer.toString()); - myCustomer = service.updateCustomer(myCustomer.id, "+00"); - logger.info("Update -- " + myCustomer.toString()); - } - - private void basicLoadAndSaveWithMapper() { - CustomerDto dto = new CustomerDto(null); - dto.name = "Johnny"; - Customer entity = service.addCustomer(dto); - logger.info("Insert -- " + entity.toString()); - CustomerDto dto2 = new CustomerDto(entity.id); - dto2.phone = "+44"; - entity = service.updateCustomer(dto2); - logger.info("Update -- " + entity.toString()); - } - -} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java new file mode 100644 index 0000000000..30f5dfa03d --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java @@ -0,0 +1,20 @@ +package com.baeldung.partialupdate; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; + +@SpringBootApplication +@EnableCaching +public class PartialUpdateApplication { + + @Autowired + CacheManager cacheManager; + + public static void main(String[] args) { + SpringApplication.run(PartialUpdateApplication.class, args); + } + +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java new file mode 100644 index 0000000000..9d611fa755 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java @@ -0,0 +1,22 @@ +package com.baeldung.partialupdate.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class ContactPhone { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public long id; + @Column(nullable=false) + public long customerId; + public String phone; + + @Override + public String toString() { + return phone; + } +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java similarity index 100% rename from persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/Customer.java rename to persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java similarity index 100% rename from persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/model/CustomerDto.java rename to persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java new file mode 100644 index 0000000000..67b534add2 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java @@ -0,0 +1,26 @@ +package com.baeldung.partialupdate.model; + +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class CustomerStructured { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public long id; + public String name; + @OneToMany(fetch = FetchType.EAGER, targetEntity=ContactPhone.class, mappedBy="customerId") + public List contactPhones; + + @Override public String toString() { + return String.format("Customer %s, Phone: %s", + this.name, this.contactPhones.stream().map(e -> e.toString()).reduce("", String::concat)); + } +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java new file mode 100644 index 0000000000..2e0b687227 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.partialupdate.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.partialupdate.model.ContactPhone; + +@Repository +public interface ContactPhoneRepository extends CrudRepository { + ContactPhone findById(long id); + ContactPhone findByCustomerId(long id); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java similarity index 76% rename from persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java rename to persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java index dcde6c3b46..bd33c03b6b 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/repository/CustomerRepository.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java @@ -1,10 +1,10 @@ -package com.baeldung.repository; +package com.baeldung.partialupdate.repository; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import com.baeldung.model.Customer; +import com.baeldung.partialupdate.model.Customer; @Repository public interface CustomerRepository extends CrudRepository { diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java new file mode 100644 index 0000000000..0f9fd1e92e --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.partialupdate.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.partialupdate.model.CustomerStructured; + +@Repository +public interface CustomerStructuredRepository extends CrudRepository { + CustomerStructured findById(long id); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java new file mode 100644 index 0000000000..f3a1c65ef1 --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java @@ -0,0 +1,79 @@ +package com.baeldung.partialupdate.service; + +import javax.transaction.Transactional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.partialupdate.model.ContactPhone; +import com.baeldung.partialupdate.model.Customer; +import com.baeldung.partialupdate.model.CustomerDto; +import com.baeldung.partialupdate.model.CustomerStructured; +import com.baeldung.partialupdate.repository.ContactPhoneRepository; +import com.baeldung.partialupdate.repository.CustomerRepository; +import com.baeldung.partialupdate.repository.CustomerStructuredRepository; +import com.baeldung.partialupdate.util.CustomerMapper; + +@Service +@Transactional +public class CustomerService { + + @Autowired + CustomerRepository repo; + @Autowired + CustomerStructuredRepository repo2; + @Autowired + ContactPhoneRepository repo3; + @Autowired + CustomerMapper mapper; + + public Customer addCustomer(String name) { + Customer myCustomer = new Customer(); + myCustomer.name = name; + repo.save(myCustomer); + return myCustomer; + } + + public Customer updateCustomer(long id, String phone) { + Customer myCustomer = repo.findById(id); + myCustomer.phone = phone; + repo.save(myCustomer); + return myCustomer; + } + + public Customer addCustomer(CustomerDto dto) { + Customer myCustomer = new Customer(); + mapper.updateCustomerFromDto(dto, myCustomer); + repo.save(myCustomer); + return myCustomer; + } + + public Customer updateCustomer(CustomerDto dto) { + Customer myCustomer = repo.findById(dto.getId()); + mapper.updateCustomerFromDto(dto, myCustomer); + repo.save(myCustomer); + return myCustomer; + } + + public CustomerStructured addCustomerStructured(String name) { + CustomerStructured myCustomer = new CustomerStructured(); + myCustomer.name = name; + repo2.save(myCustomer); + return myCustomer; + } + + public void addCustomerPhone(long customerId, String phone) { + ContactPhone myPhone = new ContactPhone(); + myPhone.phone = phone; + myPhone.customerId = customerId; + repo3.save(myPhone); + } + + public CustomerStructured updateCustomerStructured(long id, String name) { + CustomerStructured myCustomer = repo2.findById(id); + myCustomer.name = name; + repo2.save(myCustomer); + return myCustomer; + } + +} diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java similarity index 73% rename from persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java rename to persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java index d4f264e33a..8a666e3e6c 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/util/CustomerMapper.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java @@ -1,12 +1,12 @@ -package com.baeldung.util; +package com.baeldung.partialupdate.util; import org.mapstruct.BeanMapping; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValuePropertyMappingStrategy; -import com.baeldung.model.Customer; -import com.baeldung.model.CustomerDto; +import com.baeldung.partialupdate.model.Customer; +import com.baeldung.partialupdate.model.CustomerDto; @Mapper(componentModel = "spring") public interface CustomerMapper { diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java deleted file mode 100644 index 9ebbb0c814..0000000000 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/service/CustomerService.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.service; - -import javax.transaction.Transactional; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.baeldung.model.Customer; -import com.baeldung.model.CustomerDto; -import com.baeldung.repository.CustomerRepository; -import com.baeldung.util.CustomerMapper; - -@Service @Transactional -public class CustomerService { - - @Autowired CustomerRepository repo; - @Autowired CustomerMapper mapper; - - public Customer addCustomer(String name) { - Customer myCustomer = new Customer(); - myCustomer.name = name; - repo.save(myCustomer); - return myCustomer; - } - - public Customer updateCustomer(long id, String phone) { - Customer myCustomer = repo.findById(id); - myCustomer.phone = phone; - repo.save(myCustomer); - return myCustomer; - } - - public Customer addCustomer(CustomerDto dto) { - Customer myCustomer = new Customer(); - mapper.updateCustomerFromDto(dto, myCustomer); - repo.save(myCustomer); - return myCustomer; - } - - public Customer updateCustomer(CustomerDto dto) { - Customer myCustomer = repo.findById(dto.getId()); - mapper.updateCustomerFromDto(dto, myCustomer); - repo.save(myCustomer); - return myCustomer; - } - -} diff --git a/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java new file mode 100644 index 0000000000..dc9c8821ac --- /dev/null +++ b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.partialupdate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +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 com.baeldung.partialupdate.model.Customer; +import com.baeldung.partialupdate.model.CustomerDto; +import com.baeldung.partialupdate.model.CustomerStructured; +import com.baeldung.partialupdate.service.CustomerService; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PartialUpdateApplication.class) +public class PartialUpdateUnitTest { + + @Autowired + CustomerService service; + + @Test + public void loadAndSave_whenUpdate_thenSuccess() { + Customer myCustomer = service.addCustomer("John"); + myCustomer = service.updateCustomer(myCustomer.id, "+00"); + + assertEquals("+00", myCustomer.phone); + } + + @Test + public void loadAndSaveWithMapper_whenUpdate_thenSuccess() { + CustomerDto dto = new CustomerDto(new Customer()); + dto.name = "Johnny"; + Customer entity = service.addCustomer(dto); + + CustomerDto dto2 = new CustomerDto(entity.id); + dto2.phone = "+44"; + entity = service.updateCustomer(dto2); + + assertEquals("Johnny", entity.name); + } + + @Test + public void loadAndSaveStructuredEntity_whenUpdate_thenSuccess() { + CustomerStructured myCustomer = service.addCustomerStructured("John"); + assertEquals(null, myCustomer.contactPhones); + + service.addCustomerPhone(myCustomer.id, "+44"); + myCustomer = service.updateCustomerStructured(myCustomer.id, "Mr. John"); + + assertNotEquals(null, myCustomer.contactPhones); + assertEquals(1, myCustomer.contactPhones.size()); + } +} From ab1114fb7de6d78811c84132e461c0855255cf74 Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Sun, 24 May 2020 11:45:17 +0200 Subject: [PATCH 020/118] Refactored packages --- .../java/com/baeldung/partialupdate/model/Customer.java | 7 +++---- .../java/com/baeldung/partialupdate/model/CustomerDto.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java index 28c5d5c76c..b19d0b7952 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/Customer.java @@ -1,4 +1,4 @@ -package com.baeldung.model; +package com.baeldung.partialupdate.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -8,15 +8,14 @@ import javax.persistence.Id; @Entity public class Customer { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) public long id; public String name; public String phone; //... public String phone99; - public Customer() {} - @Override public String toString() { return String.format("Customer %s, Phone: %s", this.name, this.phone); diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java index 74b909aad8..4087838f9a 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java @@ -1,4 +1,4 @@ -package com.baeldung.model; +package com.baeldung.partialupdate.model; public class CustomerDto { private long id; From ce8d289cd9abdaadcf38225e25e747c62b309c51 Mon Sep 17 00:00:00 2001 From: musibs Date: Mon, 25 May 2020 09:45:10 +0530 Subject: [PATCH 021/118] Moved the testcase to core-java-lang-2 module --- .../src/test/java/com/baeldung/error/oom/TestExecutorService.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core-java-modules/{core-java-lang => core-java-lang-2}/src/test/java/com/baeldung/error/oom/TestExecutorService.java (100%) diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java b/core-java-modules/core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/error/oom/TestExecutorService.java rename to core-java-modules/core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java From 7943a59707c9534e2f24c90106b32efdcc771dbe Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Tue, 26 May 2020 17:23:59 +0530 Subject: [PATCH 022/118] BAEL3889 - Kafka Mock Producer --- .../src/main/java/com/baeldung/kafka/EvenOddPartitioner.java | 0 .../src/main/java/com/baeldung/kafka/KafkaProducer.java | 0 .../src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {libraries => libraries-6}/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java (100%) rename {libraries => libraries-6}/src/main/java/com/baeldung/kafka/KafkaProducer.java (100%) rename {libraries => libraries-6}/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java (100%) diff --git a/libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java b/libraries-6/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java similarity index 100% rename from libraries/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java rename to libraries-6/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java diff --git a/libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java b/libraries-6/src/main/java/com/baeldung/kafka/KafkaProducer.java similarity index 100% rename from libraries/src/main/java/com/baeldung/kafka/KafkaProducer.java rename to libraries-6/src/main/java/com/baeldung/kafka/KafkaProducer.java diff --git a/libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java b/libraries-6/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java similarity index 100% rename from libraries/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java rename to libraries-6/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java From 18d00eae62ea63c5d489f9dcb8eb96f196f424d2 Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Wed, 27 May 2020 11:57:14 +0300 Subject: [PATCH 023/118] BAEL-3896: OpenAPI JSON Objects in Query Params - swagger definitions moved in resources --- .../jsonParamOpenApiSwagger3Definition | 32 ---- .../jsonParamOpenApiSwaggerDefinition | 172 ------------------ .../openapi-2.json | 75 ++++++++ .../openapi-3.json | 37 ++++ 4 files changed, 112 insertions(+), 204 deletions(-) delete mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition delete mode 100644 spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition create mode 100644 spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json create mode 100644 spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition deleted file mode 100644 index 218e24b12b..0000000000 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwagger3Definition +++ /dev/null @@ -1,32 +0,0 @@ -swagger: '3.0' -info: - title: Sample API to send JSON objects as query parameters using OpenAPI 3 - description: API description. - version: 1.0.0 - -paths: - /tickets: - get: - parameters: - - in: query - name: params - required: true - # Parameter is an object that should be serialized as JSON - content: - application/json: - schema: - type: object - properties: - type: - type: string - name: - color: string - responses: - '200': - description: successful process - '401': - description: Unauthorized - '403': - description: Forbidden - '404': - description: Not Found diff --git a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition b/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition deleted file mode 100644 index 3261736e15..0000000000 --- a/spring-rest-http/src/main/java/com/baeldung/jsonparam/jsonParamOpenApiSwaggerDefinition +++ /dev/null @@ -1,172 +0,0 @@ -swagger: '2.0' -info: - title: Sample API to send JSON objects as query parameters using OpenAPI 2 - description: API description. - version: 1.0.0 - -paths: - /tickets: - get: - parameters: - - in: query - name: params - required: true - description: A JSON object with the `type` and `color` properties - type: string - example: '{"type":"foo","color":"green"}' - responses: - '200': - description: successful process - '401': - description: Unauthorized - '403': - description: Forbidden - '404': - description: Not Found - - /tickets: - post: - requestBody: - description: Parameter is an object that should be serialized as JSON - content: - application/json: - schema: - type: string - example: '{"type":"foo","color":"green"}' - responses: - '200': - description: successful process - '201': - description: Created - '401': - description: Unauthorized - '403': - description: Forbidden - '404': - description: Not Found - - /api/tickets: { - get: { - tags: [ - "account-resource" - ], - summary: "testQueryParamApi", - operationId: "testQueryParamApiUsingGET", - produces: [ - "*/*" - ], - parameters: [ - { - name: "params", - in: "query", - description: "params", - required: true, - type: "string" - } - ], - responses: { - 200: { - description: "OK", - schema: { - type: "string" - } - }, - 401: { - description: "Unauthorized" - }, - 403: { - description: "Forbidden" - }, - 404: { - description: "Not Found" - } - }, - deprecated: false - }, - post: { - tags: [ - "account-resource" - ], - summary: "testBodyParamApi", - operationId: "testBodyParamApiUsingPOST", - consumes: [ - "application/json" - ], - produces: [ - "*/*" - ], - parameters: [ - { - in: "body", - name: "params", - description: "params", - required: true, - schema: { - type: "string" - } - } - ], - responses: { - 200: { - description: "OK", - schema: { - type: "string" - } - }, - 201: { - description: "Created" - }, - 401: { - description: "Unauthorized" - }, - 403: { - description: "Forbidden" - }, - 404: { - description: "Not Found" - } - }, - deprecated: false - } - }, - /api/tickets2: { - get: { - tags: [ - "account-resource" - ], - summary: "testGetBodyParamApi", - operationId: "testGetBodyParamApiUsingGET", - produces: [ - "*/*" - ], - parameters: [ - { - in: "body", - name: "params", - description: "params", - required: true, - schema: { - type: "string" - } - } - ], - responses: { - 200: { - description: "OK", - schema: { - type: "string" - } - }, - 401: { - description: "Unauthorized" - }, - 403: { - description: "Forbidden" - }, - 404: { - description: "Not Found" - } - }, - deprecated: false - } - } diff --git a/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json new file mode 100644 index 0000000000..53272c9cdb --- /dev/null +++ b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json @@ -0,0 +1,75 @@ +swagger: "2.0" +info: + description: "This is a sample server." + version: "1.0.0" + title: "Sample API to send JSON objects as query parameters using OpenAPI 2" +tags: +- name: "tickets" + description: "Send Tickets as JSON Objects" +schemes: +- "https" +- "http" +paths: + /tickets: + get: + tags: + - "tickets" + summary: "Send an JSON Object as a query param" + parameters: + - name: "params" + in: "path" + description: "{\"type\":\"foo\",\"color\":\"green\"}" + required: true + type: "string" + responses: + "200": + description: "Successful operation" + "401": + description: "Unauthorized" + "403": + description: "Forbidden" + "404": + description: "Not found" + post: + tags: + - "tickets" + summary: "Send an JSON Object in body" + parameters: + - name: "params" + in: "body" + description: "Parameter is an JSON object with the `type` and `color` properties that should be serialized as JSON {\"type\":\"foo\",\"color\":\"green\"}" + required: true + schema: + type: string + responses: + "200": + description: "Successful operation" + "401": + description: "Unauthorized" + "403": + description: "Forbidden" + "404": + description: "Not found" + "405": + description: "Invalid input" + /tickets2: + get: + tags: + - "tickets" + summary: "Send an JSON Object in body of get reqest" + parameters: + - name: "params" + in: "body" + description: "Parameter is an JSON object with the `type` and `color` properties that should be serialized as JSON {\"type\":\"foo\",\"color\":\"green\"}" + required: true + schema: + type: string + responses: + "200": + description: "Successful operation" + "401": + description: "Unauthorized" + "403": + description: "Forbidden" + "404": + description: "Not found" diff --git a/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json new file mode 100644 index 0000000000..a0ed147b9d --- /dev/null +++ b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json @@ -0,0 +1,37 @@ +openapi: 3.0.1 +info: + title: Sample API to send JSON objects as query parameters using OpenAPI 3 + description: This is a sample server. + version: 1.0.0 +servers: +- url: /api +tags: +- name: tickets + description: Send Tickets as JSON Objects +paths: + /tickets: + get: + tags: + - tickets + summary: Send an JSON Object as a query param + parameters: + - name: params + in: query + description: '{"type":"foo","color":"green"}' + required: true + schema: + type: object + properties: + type: + type: "string" + color: + type: "string" + responses: + 200: + description: Successful operation + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not found From e1c3aed23b75c41a28e479ad01a31dcdfc051c66 Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Wed, 27 May 2020 19:43:04 +0200 Subject: [PATCH 024/118] Added @Query method + clean --- .../PartialUpdateApplication.java | 8 ------- .../partialupdate/model/ContactPhone.java | 4 ++-- .../partialupdate/model/CustomerDto.java | 12 +++++----- .../model/CustomerStructured.java | 7 +++--- .../repository/ContactPhoneRepository.java | 4 ++-- .../repository/CustomerRepository.java | 9 ++++++-- .../service/CustomerService.java | 8 +++++++ .../partialupdate/PartialUpdateUnitTest.java | 23 ++++++++++++------- 8 files changed, 44 insertions(+), 31 deletions(-) diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java index 30f5dfa03d..a750fcadf7 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java @@ -1,20 +1,12 @@ package com.baeldung.partialupdate; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication -@EnableCaching public class PartialUpdateApplication { - @Autowired - CacheManager cacheManager; - public static void main(String[] args) { SpringApplication.run(PartialUpdateApplication.class, args); } - } diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java index 9d611fa755..352e361bd9 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java @@ -8,11 +8,11 @@ import javax.persistence.Id; @Entity public class ContactPhone { - @Id + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public long id; @Column(nullable=false) - public long customerId; + public long customerId; public String phone; @Override diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java index 4087838f9a..0ecf206d9a 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java @@ -6,21 +6,21 @@ public class CustomerDto { public String phone; //... private String phone99; - + public CustomerDto(long id) { - this.id = id; + this.id = id; } - + public CustomerDto(Customer c) { this.id = c.id; this.name = c.name; this.phone = c.phone; } - + public long getId() { - return this.id; + return this.id; } - + public Customer convertToEntity() { Customer c = new Customer(); c.id = id; diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java index 67b534add2..dd053a963d 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java @@ -16,11 +16,12 @@ public class CustomerStructured { @GeneratedValue(strategy = GenerationType.IDENTITY) public long id; public String name; - @OneToMany(fetch = FetchType.EAGER, targetEntity=ContactPhone.class, mappedBy="customerId") + @OneToMany(fetch = FetchType.EAGER, targetEntity = ContactPhone.class, mappedBy = "customerId") public List contactPhones; - + @Override public String toString() { return String.format("Customer %s, Phone: %s", - this.name, this.contactPhones.stream().map(e -> e.toString()).reduce("", String::concat)); + this.name, this.contactPhones.stream() + .map(e -> e.toString()).reduce("", String::concat)); } } diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java index 2e0b687227..4668181e05 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java @@ -7,6 +7,6 @@ import com.baeldung.partialupdate.model.ContactPhone; @Repository public interface ContactPhoneRepository extends CrudRepository { - ContactPhone findById(long id); - ContactPhone findByCustomerId(long id); + ContactPhone findById(long id); + ContactPhone findByCustomerId(long id); } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java index bd33c03b6b..43e61df8ab 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java @@ -1,13 +1,18 @@ package com.baeldung.partialupdate.repository; -import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import com.baeldung.partialupdate.model.Customer; @Repository public interface CustomerRepository extends CrudRepository { - @Cacheable("customers") Customer findById(long id); + + @Modifying + @Query("update Customer u set u.phone = :phone where u.id = :id") + void updatePhone(@Param(value = "id") long id, @Param(value = "phone") String phone); } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java index f3a1c65ef1..9da97a7775 100644 --- a/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java +++ b/persistence-modules/spring-data-jpa-5/src/main/java/com/baeldung/partialupdate/service/CustomerService.java @@ -27,6 +27,14 @@ public class CustomerService { @Autowired CustomerMapper mapper; + public Customer getCustomer(long id) { + return repo.findById(id); + } + + public void updateCustomerWithCustomQuery(long id, String phone) { + repo.updatePhone(id, phone); + } + public Customer addCustomer(String name) { Customer myCustomer = new Customer(); myCustomer.name = name; diff --git a/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java index dc9c8821ac..7eea3a87e9 100644 --- a/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java +++ b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java @@ -25,11 +25,18 @@ public class PartialUpdateUnitTest { public void loadAndSave_whenUpdate_thenSuccess() { Customer myCustomer = service.addCustomer("John"); myCustomer = service.updateCustomer(myCustomer.id, "+00"); - assertEquals("+00", myCustomer.phone); } - @Test + @Test + public void customQuery_whenUpdate_thenSuccess() { + Customer myCustomer = service.addCustomer("John"); + service.updateCustomerWithCustomQuery(myCustomer.id, "+88"); + myCustomer = service.getCustomer(myCustomer.id); + assertEquals("+88", myCustomer.phone); + } + + @Test public void loadAndSaveWithMapper_whenUpdate_thenSuccess() { CustomerDto dto = new CustomerDto(new Customer()); dto.name = "Johnny"; @@ -38,19 +45,19 @@ public class PartialUpdateUnitTest { CustomerDto dto2 = new CustomerDto(entity.id); dto2.phone = "+44"; entity = service.updateCustomer(dto2); - + assertEquals("Johnny", entity.name); } - - @Test - public void loadAndSaveStructuredEntity_whenUpdate_thenSuccess() { + + @Test + public void loadAndSaveStructuredEntity_whenUpdate_thenSuccess() { CustomerStructured myCustomer = service.addCustomerStructured("John"); assertEquals(null, myCustomer.contactPhones); service.addCustomerPhone(myCustomer.id, "+44"); myCustomer = service.updateCustomerStructured(myCustomer.id, "Mr. John"); - + assertNotEquals(null, myCustomer.contactPhones); assertEquals(1, myCustomer.contactPhones.size()); - } + } } From 020aff116095c4a2d5546948ce617d5eeb1f71e6 Mon Sep 17 00:00:00 2001 From: Roque Santos Date: Wed, 27 May 2020 21:32:31 -0300 Subject: [PATCH 025/118] BAEL-3844 : Send request to a proxy using RestTemplate --- .../proxy/RequestFactoryLiveTest.java | 38 +++++++++++++ .../proxy/RestTemplateCustomizerLiveTest.java | 55 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java create mode 100644 spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java new file mode 100644 index 0000000000..f9ca66f14d --- /dev/null +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java @@ -0,0 +1,38 @@ +package com.baeldung.resttemplate.proxy; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Proxy.Type; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +public class RequestFactoryLiveTest { + + RestTemplate restTemplate; + + @Before + public void setUp() { + Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("201.91.82.155", 3128)); + + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + requestFactory.setProxy(proxy); + + restTemplate = new RestTemplate(requestFactory); + } + + @Test + public void givenRestTemplate_whenRequestedWithProxy_thenResponseBodyIsOk() { + ResponseEntity responseEntity = restTemplate.getForEntity("http://httpbin.org/get", String.class); + + assertThat(responseEntity.getStatusCode(), is(equalTo(HttpStatus.OK))); + } +} diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java new file mode 100644 index 0000000000..8f318b758b --- /dev/null +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java @@ -0,0 +1,55 @@ +package com.baeldung.resttemplate.proxy; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.apache.http.protocol.HttpContext; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.client.RestTemplateCustomizer; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +public class RestTemplateCustomizerLiveTest { + + RestTemplate restTemplate; + + @Before + public void setUp() { + restTemplate = new RestTemplateBuilder(new ProxyCustomizer()).build(); + } + + @Test + public void givenRestTemplate_whenRequestedWithProxy_thenResponseBodyIsOk() { + ResponseEntity responseEntity = restTemplate.getForEntity("http://httpbin.org/get", String.class); + + assertThat(responseEntity.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + private static class ProxyCustomizer implements RestTemplateCustomizer { + + @Override + public void customize(RestTemplate restTemplate) { + HttpHost proxy = new HttpHost("201.91.82.155", 3128); + HttpClient httpClient = HttpClientBuilder.create() + .setRoutePlanner(new DefaultProxyRoutePlanner(proxy) { + @Override + public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException { + return super.determineProxy(target, request, context); + } + }) + .build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + } + } +} From 6fb0ebb95c81069a318ff7a017866dcef19d7efa Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Thu, 28 May 2020 20:00:23 +0430 Subject: [PATCH 026/118] Dependency Upgrade for HikariCP --- libraries-data-db/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries-data-db/pom.xml b/libraries-data-db/pom.xml index f028ffe8c3..d51580ccbc 100644 --- a/libraries-data-db/pom.xml +++ b/libraries-data-db/pom.xml @@ -211,7 +211,7 @@ 5.0.2 5.0.4 3.2.0-m7 - 2.7.2 + 3.4.5 11.22.4 From 470d047e8dd21a4055e78d079666475075375296 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Fri, 29 May 2020 00:29:27 +0430 Subject: [PATCH 027/118] Introducing Constant Folding & Dead Code Elimination --- jmh/src/main/java/com/baeldung/BenchMark.java | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/jmh/src/main/java/com/baeldung/BenchMark.java b/jmh/src/main/java/com/baeldung/BenchMark.java index b0e1caf4dc..55157848ab 100644 --- a/jmh/src/main/java/com/baeldung/BenchMark.java +++ b/jmh/src/main/java/com/baeldung/BenchMark.java @@ -1,14 +1,20 @@ package com.baeldung; -import com.google.common.hash.HashFunction; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; import java.nio.charset.Charset; +import java.util.concurrent.TimeUnit; public class BenchMark { + @State(Scope.Benchmark) + public static class Log { + public int x = 8; + } + @State(Scope.Benchmark) public static class ExecutionPlan { @@ -45,4 +51,42 @@ public class BenchMark { // Do nothing } + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void doNothing() {} + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void objectCreation() { + new Object(); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public Object pillarsOfCreation() { + return new Object(); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void blackHole(Blackhole blackhole) { + blackhole.consume(new Object()); + } + + @Benchmark + public double foldedLog() { + int x = 8; + + return Math.log(x); + } + + @Benchmark + public double log(Log input) { + return Math.log(input.x); + } + } From 1a44c81de42d3d1d9b1b7364f0df7ec33c7d54a5 Mon Sep 17 00:00:00 2001 From: Gergo Petrik Date: Fri, 29 May 2020 16:04:02 +0200 Subject: [PATCH 028/118] using accessors for balance and stamp --- .../com/baeldung/atomicstampedreference/StampedAccount.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/atomicstampedreference/StampedAccount.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/atomicstampedreference/StampedAccount.java index 1a46e1ba52..415b24738a 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/atomicstampedreference/StampedAccount.java +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/atomicstampedreference/StampedAccount.java @@ -9,13 +9,11 @@ public class StampedAccount { private AtomicStampedReference account = new AtomicStampedReference<>(0, 0); public int getBalance() { - return this.account.get(new int[1]); + return account.getReference(); } public int getStamp() { - int[] stamps = new int[1]; - this.account.get(stamps); - return stamps[0]; + return account.getStamp(); } public boolean deposit(int funds) { From 0986bbcd622c6fd284b674bf85b65223b0c328e9 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Sat, 30 May 2020 09:23:53 +0430 Subject: [PATCH 029/118] On the next line --- jmh/src/main/java/com/baeldung/BenchMark.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jmh/src/main/java/com/baeldung/BenchMark.java b/jmh/src/main/java/com/baeldung/BenchMark.java index 55157848ab..3c5c840db2 100644 --- a/jmh/src/main/java/com/baeldung/BenchMark.java +++ b/jmh/src/main/java/com/baeldung/BenchMark.java @@ -54,7 +54,9 @@ public class BenchMark { @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) @BenchmarkMode(Mode.AverageTime) - public void doNothing() {} + public void doNothing() { + + } @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) From c5267db45296b59072477ad6d2be51a1911baaf7 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Sat, 30 May 2020 13:05:26 +0430 Subject: [PATCH 030/118] Added Elvis Operator --- .../kotlin/com/baeldung/ternary/TernaryOperatorTest.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt b/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt index 21dfdd2ae0..347290de72 100644 --- a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt +++ b/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt @@ -21,4 +21,12 @@ class TernaryOperatorTest { } assertEquals("yes", result) } + + @Test + fun `using elvis`() { + val a: String? = null + val result = a ?: "Default" + + assertEquals("Default", result) + } } \ No newline at end of file From 6b3b45923b0843a857391cc5887065e3fb64ce1e Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Sat, 30 May 2020 21:58:48 +0430 Subject: [PATCH 031/118] Using Retrieve instead of AwaitExchange --- .../controller/ProductControllerCoroutines.kt | 8 +++----- .../nonblockingcoroutines/handlers/ProductsHandler.kt | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/controller/ProductControllerCoroutines.kt b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/controller/ProductControllerCoroutines.kt index 363090abac..464ed2773a 100644 --- a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/controller/ProductControllerCoroutines.kt +++ b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/controller/ProductControllerCoroutines.kt @@ -2,12 +2,11 @@ package com.baeldung.nonblockingcoroutines.controller import com.baeldung.nonblockingcoroutines.model.Product import com.baeldung.nonblockingcoroutines.repository.ProductRepositoryCoroutines +import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Deferred import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType.APPLICATION_JSON @@ -15,7 +14,6 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.awaitBody -import org.springframework.web.reactive.function.client.awaitExchange class ProductControllerCoroutines { @Autowired @@ -38,7 +36,7 @@ class ProductControllerCoroutines { webClient.get() .uri("/stock-service/product/$id/quantity") .accept(APPLICATION_JSON) - .awaitExchange().awaitBody() + .retrieve().awaitBody() } ProductStockView(product.await()!!, quantity.await()) } diff --git a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/handlers/ProductsHandler.kt b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/handlers/ProductsHandler.kt index 41c4510e0d..e05b718e64 100644 --- a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/handlers/ProductsHandler.kt +++ b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/handlers/ProductsHandler.kt @@ -12,7 +12,6 @@ import org.springframework.http.MediaType import org.springframework.stereotype.Component import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.awaitBody -import org.springframework.web.reactive.function.client.awaitExchange import org.springframework.web.reactive.function.server.ServerRequest import org.springframework.web.reactive.function.server.ServerResponse import org.springframework.web.reactive.function.server.bodyAndAwait @@ -37,7 +36,7 @@ class ProductsHandler( webClient.get() .uri("/stock-service/product/$id/quantity") .accept(MediaType.APPLICATION_JSON) - .awaitExchange().awaitBody() + .retrieve().awaitBody() } return ServerResponse.ok().json().bodyAndAwait(ProductStockView(product.await()!!, quantity.await())) } From 75a44b99652b87b3c3c7781a50dd8b6767e24ce7 Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Sun, 31 May 2020 18:39:20 +0530 Subject: [PATCH 032/118] BAEL3889 - Kafka Mock Producer --- libraries-data-2/pom.xml | 7 +++++++ .../main/java/com/baeldung/kafka/EvenOddPartitioner.java | 0 .../src/main/java/com/baeldung/kafka/KafkaProducer.java | 0 .../java/com/baeldung/kafka/KafkaProducerUnitTest.java | 0 4 files changed, 7 insertions(+) rename {libraries-6 => libraries-data-2}/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java (100%) rename {libraries-6 => libraries-data-2}/src/main/java/com/baeldung/kafka/KafkaProducer.java (100%) rename {libraries-6 => libraries-data-2}/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java (100%) diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index bdfb2c5ed6..2d27ec2107 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -153,6 +153,13 @@ renjin-script-engine ${renjin.version} + + org.apache.kafka + kafka-clients + ${kafka.version} + test + test + diff --git a/libraries-6/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java b/libraries-data-2/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java similarity index 100% rename from libraries-6/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java rename to libraries-data-2/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java diff --git a/libraries-6/src/main/java/com/baeldung/kafka/KafkaProducer.java b/libraries-data-2/src/main/java/com/baeldung/kafka/KafkaProducer.java similarity index 100% rename from libraries-6/src/main/java/com/baeldung/kafka/KafkaProducer.java rename to libraries-data-2/src/main/java/com/baeldung/kafka/KafkaProducer.java diff --git a/libraries-6/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java similarity index 100% rename from libraries-6/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java rename to libraries-data-2/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java From e245b2eca3347f02e0ab45011ffc8b1c880f01f3 Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Sun, 31 May 2020 18:59:54 +0530 Subject: [PATCH 033/118] BAEL3889 - Changing the package structure --- .../com/baeldung/kafka/{ => producer}/EvenOddPartitioner.java | 0 .../java/com/baeldung/kafka/{ => producer}/KafkaProducer.java | 0 .../com/baeldung/kafka/{ => producer}/KafkaProducerUnitTest.java | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename libraries-data-2/src/main/java/com/baeldung/kafka/{ => producer}/EvenOddPartitioner.java (100%) rename libraries-data-2/src/main/java/com/baeldung/kafka/{ => producer}/KafkaProducer.java (100%) rename libraries-data-2/src/test/java/com/baeldung/kafka/{ => producer}/KafkaProducerUnitTest.java (100%) diff --git a/libraries-data-2/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java similarity index 100% rename from libraries-data-2/src/main/java/com/baeldung/kafka/EvenOddPartitioner.java rename to libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java diff --git a/libraries-data-2/src/main/java/com/baeldung/kafka/KafkaProducer.java b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java similarity index 100% rename from libraries-data-2/src/main/java/com/baeldung/kafka/KafkaProducer.java rename to libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java diff --git a/libraries-data-2/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java similarity index 100% rename from libraries-data-2/src/test/java/com/baeldung/kafka/KafkaProducerUnitTest.java rename to libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java From 5e0be5450473949a78b2d4b110f30d44124698aa Mon Sep 17 00:00:00 2001 From: "alex.peptan" Date: Sun, 31 May 2020 21:55:46 +0300 Subject: [PATCH 034/118] BAEL-3896: OpenAPI JSON Objects in Query Params - swagger definitions files changed to yaml --- .../{openapi-2.json => openapi-2.yaml} | 0 .../{openapi-3.json => openapi-3.yaml} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename spring-rest-http/src/main/resources/openapi-queryparam-definitions/{openapi-2.json => openapi-2.yaml} (100%) rename spring-rest-http/src/main/resources/openapi-queryparam-definitions/{openapi-3.json => openapi-3.yaml} (100%) diff --git a/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.yaml similarity index 100% rename from spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.json rename to spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-2.yaml diff --git a/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json b/spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.yaml similarity index 100% rename from spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.json rename to spring-rest-http/src/main/resources/openapi-queryparam-definitions/openapi-3.yaml From 00b67725ea441900eb1810d7e1717c3a45f3762b Mon Sep 17 00:00:00 2001 From: dupirefr Date: Sat, 30 May 2020 17:27:37 +0200 Subject: [PATCH 035/118] [JAVA-1659] Upgraded Maven Surefire Plugin and JUnit versions * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * Imported JUnit BOM before Spring Boot Dependencies BOM (as explained [here](https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/maven-plugin/reference/html/#using)) --- ddd/pom.xml | 54 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/ddd/pom.xml b/ddd/pom.xml index 1253f2ac48..422f9ccd15 100644 --- a/ddd/pom.xml +++ b/ddd/pom.xml @@ -17,6 +17,35 @@ ../parent-boot-2 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + org.springframework.boot @@ -26,24 +55,6 @@ org.springframework.boot spring-boot-starter-data-cassandra - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - org.junit.platform - junit-platform-launcher - ${junit-platform.version} - test - org.joda joda-money @@ -95,7 +106,10 @@ - 1.0.1 - + 2.22.2 + 1.0.1 + + 5.6.2 + From 8477fd927913b5fceabdba4e367e54def66c4fae Mon Sep 17 00:00:00 2001 From: Michele Guarnaccia Date: Mon, 1 Jun 2020 11:09:35 +0200 Subject: [PATCH 036/118] Renamed test methods --- .../com/baeldung/partialupdate/PartialUpdateUnitTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java index 7eea3a87e9..874e18c4ad 100644 --- a/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java +++ b/persistence-modules/spring-data-jpa-5/src/test/java/com/baeldung/partialupdate/PartialUpdateUnitTest.java @@ -22,14 +22,14 @@ public class PartialUpdateUnitTest { CustomerService service; @Test - public void loadAndSave_whenUpdate_thenSuccess() { + public void givenCustomer_whenUpdate_thenSuccess() { Customer myCustomer = service.addCustomer("John"); myCustomer = service.updateCustomer(myCustomer.id, "+00"); assertEquals("+00", myCustomer.phone); } @Test - public void customQuery_whenUpdate_thenSuccess() { + public void givenCustomer_whenUpdateWithQuery_thenSuccess() { Customer myCustomer = service.addCustomer("John"); service.updateCustomerWithCustomQuery(myCustomer.id, "+88"); myCustomer = service.getCustomer(myCustomer.id); @@ -37,7 +37,7 @@ public class PartialUpdateUnitTest { } @Test - public void loadAndSaveWithMapper_whenUpdate_thenSuccess() { + public void givenCustomerDto_whenUpdateWithMapper_thenSuccess() { CustomerDto dto = new CustomerDto(new Customer()); dto.name = "Johnny"; Customer entity = service.addCustomer(dto); @@ -50,7 +50,7 @@ public class PartialUpdateUnitTest { } @Test - public void loadAndSaveStructuredEntity_whenUpdate_thenSuccess() { + public void givenCustomerStructured_whenUpdateCustomerPhone_thenSuccess() { CustomerStructured myCustomer = service.addCustomerStructured("John"); assertEquals(null, myCustomer.contactPhones); From 3086da7d127b92c19b51d9a829c08055bccefd54 Mon Sep 17 00:00:00 2001 From: dupirefr Date: Mon, 1 Jun 2020 11:11:12 +0200 Subject: [PATCH 037/118] [JAVA-1659] Upgraded Maven Surefire Plugin and JUnit versions * Fixed sub-modules parent poms names * Added relative paths to sub-modules poms * Configured Maven Surefire Plugin so that it works with the dummy test * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 --- ddd-modules/infrastructure/pom.xml | 3 ++- ddd-modules/mainapp/pom.xml | 3 ++- ddd-modules/ordercontext/pom.xml | 3 ++- ddd-modules/pom.xml | 34 ++++++++++++++++++++++++----- ddd-modules/sharedkernel/pom.xml | 3 ++- ddd-modules/shippingcontext/pom.xml | 3 ++- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/ddd-modules/infrastructure/pom.xml b/ddd-modules/infrastructure/pom.xml index c301eaa92a..abf90935c3 100644 --- a/ddd-modules/infrastructure/pom.xml +++ b/ddd-modules/infrastructure/pom.xml @@ -12,8 +12,9 @@ com.baeldung.dddmodules - dddmodules + ddd-modules 1.0 + ../ diff --git a/ddd-modules/mainapp/pom.xml b/ddd-modules/mainapp/pom.xml index a048263d37..59d2ad7d3a 100644 --- a/ddd-modules/mainapp/pom.xml +++ b/ddd-modules/mainapp/pom.xml @@ -11,8 +11,9 @@ com.baeldung.dddmodules - dddmodules + ddd-modules 1.0 + ../ diff --git a/ddd-modules/ordercontext/pom.xml b/ddd-modules/ordercontext/pom.xml index abd166fb69..8dee3a5148 100644 --- a/ddd-modules/ordercontext/pom.xml +++ b/ddd-modules/ordercontext/pom.xml @@ -11,8 +11,9 @@ com.baeldung.dddmodules - dddmodules + ddd-modules 1.0 + ../ diff --git a/ddd-modules/pom.xml b/ddd-modules/pom.xml index c6dd6e1f25..6ab1829198 100644 --- a/ddd-modules/pom.xml +++ b/ddd-modules/pom.xml @@ -28,9 +28,15 @@ - junit - junit - ${junit.version} + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} test @@ -56,15 +62,31 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + 0 + + + - 3.8.1 + UTF-8 + 9 9 - UTF-8 - 3.12.2 + + 3.8.1 + 2.22.2 + 1.0 + + 5.6.2 + 3.12.2 diff --git a/ddd-modules/sharedkernel/pom.xml b/ddd-modules/sharedkernel/pom.xml index a61f03a494..1afddf1e22 100644 --- a/ddd-modules/sharedkernel/pom.xml +++ b/ddd-modules/sharedkernel/pom.xml @@ -11,8 +11,9 @@ com.baeldung.dddmodules - dddmodules + ddd-modules 1.0 + ../ diff --git a/ddd-modules/shippingcontext/pom.xml b/ddd-modules/shippingcontext/pom.xml index 2096923f90..25b5882ef1 100644 --- a/ddd-modules/shippingcontext/pom.xml +++ b/ddd-modules/shippingcontext/pom.xml @@ -11,8 +11,9 @@ com.baeldung.dddmodules - dddmodules + ddd-modules 1.0 + ../ From 88a899a283a15b022ba93915ff95e6c8d660e682 Mon Sep 17 00:00:00 2001 From: Cristian Rosu Date: Mon, 1 Jun 2020 23:32:38 +0300 Subject: [PATCH 038/118] BAEL-4070: Injecting List or Arrays from a Spring properties file --- .../lists/ListsPropertiesIntegrationTest.java | 88 +++++++++++++++++++ .../SpringListPropertiesApplication.java | 10 +++ .../src/test/resources/lists.properties | 6 ++ 3 files changed, 104 insertions(+) create mode 100644 spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java create mode 100644 spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java new file mode 100644 index 0000000000..4047e1ea95 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java @@ -0,0 +1,88 @@ +package com.baeldung.properties.lists; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {SpringListPropertiesApplication.class}) +public class ListsPropertiesIntegrationTest { + + @Value("${arrayOfStrings}") + private String[] arrayOfStrings; + + @Value("${arrayOfStrings}") + private List unexpectedListOfStrings; + + @Value("#{'${arrayOfStrings}'.split(',')}") + private List listOfStrings; + + @Value("#{${listOfStrings}}") + private List listOfStringsV2; + + @Value("#{'${listOfStringsWithCustomDelimiter}'.split(';')}") + private List listOfStringsWithCustomDelimiter; + + @Value("#{'${listOfBooleans}'.split(',')}") + private List listOfBooleans; + + @Value("#{'${listOfIntegers}'.split(',')}") + private List listOfIntegers; + + @Value("#{'${listOfCharacters}'.split(',')}") + private List listOfCharacters; + + @Autowired + private Environment environment; + + @Test + public void givenContextIsInitialized_ThenInjectedArrayContainsExpectedValues() { + assertEquals(arrayOfStrings, new String[] {"Baeldung", "dot", "com"}); + } + + @Test + public void givenContextIsInitialized_ThenInjectedListContainsUnexpectedValues() { + assertEquals(unexpectedListOfStrings, Collections.singletonList("Baeldung,dot,com")); + } + + @Test + public void givenContextIsInitialized_ThenInjectedListContainsExpectedValues() { + assertEquals(listOfStrings, Arrays.asList("Baeldung", "dot", "com")); + } + + @Test + public void givenContextIsInitialized_ThenInjectedListV2ContainsExpectedValues() { + assertEquals(listOfStringsV2, Arrays.asList("Baeldung", "dot", "com")); + } + + @Test + public void givenContextIsInitialized_ThenInjectedListWithCustomDelimiterContainsExpectedValues() { + assertEquals(listOfStringsWithCustomDelimiter, Arrays.asList("Baeldung", "dot", "com")); + } + + @Test + public void givenContextIsInitialized_ThenInjectedListOfBasicTypesContainsExpectedValues() { + assertEquals(listOfBooleans, Arrays.asList(false, false, true)); + assertEquals(listOfIntegers, Arrays.asList(1, 2, 3, 4)); + assertEquals(listOfCharacters, Arrays.asList('a', 'b', 'c')); + } + + @Test + public void givenContextIsInitialized_WhenReadingFromEnvironment_ThenPropertiesHaveExpectedValues() { + String[] arrayOfStrings = environment.getProperty("arrayOfStrings", String[].class); + List listOfStrings = (List)environment.getProperty("arrayOfStrings", List.class); + + assertEquals(arrayOfStrings, new String[] {"Baeldung", "dot", "com"}); + assertEquals(listOfStrings, Arrays.asList("Baeldung", "dot", "com")); + } +} diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java new file mode 100644 index 0000000000..8a66079201 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java @@ -0,0 +1,10 @@ +package com.baeldung.properties.lists; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "lists.properties") +public class SpringListPropertiesApplication { + +} diff --git a/spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties b/spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties new file mode 100644 index 0000000000..cc54d699a7 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties @@ -0,0 +1,6 @@ +arrayOfStrings=Baeldung,dot,com +listOfStrings={'Baeldung','dot','com'} +listOfStringsWithCustomDelimiter=Baeldung;dot;com +listOfBooleans=false,false,true +listOfIntegers=1,2,3,4 +listOfCharacters=a,b,c \ No newline at end of file From 6d1ecdd735456d58c32fb67b5d0a88454c4fc616 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Tue, 2 Jun 2020 10:07:54 +0300 Subject: [PATCH 039/118] BAEL-4049 - view bytecode of a class file in java --- core-java-modules/core-java-jvm/pom.xml | 25 ++++++++ .../bytecode/ViewBytecodeUnitTest.java | 58 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index f3e5470a61..f35efaa26b 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -51,6 +51,31 @@ system ${java.home}/../lib/tools.jar + + org.ow2.asm + asm + 8.0.1 + + + org.ow2.asm + asm-util + 8.0.1 + + + org.apache.bcel + bcel + 6.4.1 + + + cglib + cglib + 3.3.0 + + + org.javassist + javassist + 3.27.0-GA + diff --git a/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java new file mode 100644 index 0000000000..37ea6894c6 --- /dev/null +++ b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.bytecode; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.JavaClass; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.util.TraceClassVisitor; +import javassist.ClassPool; +import javassist.NotFoundException; +import javassist.bytecode.ClassFile; +import net.sf.cglib.reflect.FastClass; + +public class ViewBytecodeUnitTest { + + @Test + public void whenUsingASM_thenReadBytecode() throws IOException { + ClassReader reader = new ClassReader("java.lang.Object"); + StringWriter sw = new StringWriter(); + TraceClassVisitor tcv = new TraceClassVisitor(new PrintWriter(sw)); + reader.accept(tcv, 0); + + assertTrue(sw.toString().contains("public class java/lang/Object")); + } + + @Test + public void whenUsingBCEL_thenReadBytecode() throws ClassNotFoundException { + JavaClass objectClazz = Repository.lookupClass("java.lang.Object"); + + assertEquals(objectClazz.getClassName(), "java.lang.Object"); + assertEquals(objectClazz.getMethods().length, 14); + assertTrue(objectClazz.toString().contains("public class java.lang.Object")); + } + + @Test + public void whenUsingCglib_thenReadBytecode() { + FastClass fastClass = FastClass.create(java.lang.Object.class); + Class clazz = fastClass.getJavaClass(); + + assertEquals(clazz.toString(), "class java.lang.Object"); + } + + @Test + public void whenUsingJavassist_thenReadBytecode() throws NotFoundException { + ClassPool cp = ClassPool.getDefault(); + ClassFile cf = cp.get("java.lang.Object").getClassFile(); + + assertEquals(cf.getName(), "java.lang.Object"); + assertEquals(cf.getMethods().size(), 14); + } + +} + + From 41a09bbf23c7bf1a7677dfc69bd51faf42df68a0 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 2 Jun 2020 15:46:57 +0530 Subject: [PATCH 040/118] JAVA-937: Migrate spring-cloud-bus to parent-boot-2 --- spring-cloud-bus/pom.xml | 6 +++--- spring-cloud-bus/spring-cloud-config-client/pom.xml | 5 +++++ .../src/main/resources/application.yml | 12 +++++++++++- .../src/main/resources/application.properties | 9 +++------ .../src/main/resources/bootstrap.properties | 4 ++++ 5 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 spring-cloud-bus/spring-cloud-config-server/src/main/resources/bootstrap.properties diff --git a/spring-cloud-bus/pom.xml b/spring-cloud-bus/pom.xml index 513c8bade6..ec56e23ac7 100644 --- a/spring-cloud-bus/pom.xml +++ b/spring-cloud-bus/pom.xml @@ -11,9 +11,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-1 + ../parent-boot-2 @@ -34,7 +34,7 @@ - Brixton.SR7 + Hoxton.SR4 diff --git a/spring-cloud-bus/spring-cloud-config-client/pom.xml b/spring-cloud-bus/spring-cloud-config-client/pom.xml index 7e1185415b..cc1c237646 100644 --- a/spring-cloud-bus/spring-cloud-config-client/pom.xml +++ b/spring-cloud-bus/spring-cloud-config-client/pom.xml @@ -33,6 +33,11 @@ org.springframework.boot spring-boot-actuator + + + org.springframework.boot + spring-boot-actuator-autoconfigure + org.springframework.cloud diff --git a/spring-cloud-bus/spring-cloud-config-client/src/main/resources/application.yml b/spring-cloud-bus/spring-cloud-config-client/src/main/resources/application.yml index 547e0284f3..fbbc6d138f 100644 --- a/spring-cloud-bus/spring-cloud-config-client/src/main/resources/application.yml +++ b/spring-cloud-bus/spring-cloud-config-client/src/main/resources/application.yml @@ -4,4 +4,14 @@ spring: host: localhost port: 5672 username: guest - password: guest \ No newline at end of file + password: guest + cloud: + bus: + enabled: true + refresh: + enabled: true +management: + endpoints: + web: + exposure: + include: "*" \ No newline at end of file diff --git a/spring-cloud-bus/spring-cloud-config-server/src/main/resources/application.properties b/spring-cloud-bus/spring-cloud-config-server/src/main/resources/application.properties index 4c18c192c0..6d7a945612 100644 --- a/spring-cloud-bus/spring-cloud-config-server/src/main/resources/application.properties +++ b/spring-cloud-bus/spring-cloud-config-server/src/main/resources/application.properties @@ -1,11 +1,8 @@ server.port=8888 spring.cloud.config.server.git.uri= -security.user.name=root -security.user.password=s3cr3t -encrypt.key-store.location=classpath:/config-server.jks -encrypt.key-store.password=my-s70r3-s3cr3t -encrypt.key-store.alias=config-server-key -encrypt.key-store.secret=my-k34-s3cr3t +spring.cloud.bus.enabled=true +spring.security.user.name=root +spring.security.user.password=s3cr3t spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest diff --git a/spring-cloud-bus/spring-cloud-config-server/src/main/resources/bootstrap.properties b/spring-cloud-bus/spring-cloud-config-server/src/main/resources/bootstrap.properties new file mode 100644 index 0000000000..b0c35c72a6 --- /dev/null +++ b/spring-cloud-bus/spring-cloud-config-server/src/main/resources/bootstrap.properties @@ -0,0 +1,4 @@ +encrypt.key-store.location=classpath:/config-server.jks +encrypt.key-store.password=my-s70r3-s3cr3t +encrypt.key-store.alias=config-server-key +encrypt.key-store.secret=my-k34-s3cr3t \ No newline at end of file From 4998662d45be50bbf79f84b6f14c52b638039bdc Mon Sep 17 00:00:00 2001 From: musibs Date: Tue, 2 Jun 2020 17:58:52 +0530 Subject: [PATCH 041/118] Moved the testcase to core-java-jvm module --- .../error/oom/ExecutorServiceUnitTest.java} | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) rename core-java-modules/{core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java => core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java} (62%) diff --git a/core-java-modules/core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java similarity index 62% rename from core-java-modules/core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java rename to core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java index d51faa055d..4e7dea370e 100644 --- a/core-java-modules/core-java-lang-2/src/test/java/com/baeldung/error/oom/TestExecutorService.java +++ b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java @@ -12,12 +12,12 @@ import java.util.stream.IntStream; import org.junit.jupiter.api.Test; -public class TestExecutorService { +public class ExecutorServiceUnitTest { @Test public void givenAnExecutorService_WhenMoreTasksSubmitted_ThenAdditionalTasksWait() { - //Given + // Given int noOfThreads = 5; ExecutorService executorService = Executors.newFixedThreadPool(noOfThreads); @@ -29,11 +29,27 @@ public class TestExecutorService { } }; - //When + // When IntStream.rangeClosed(1, 10) .forEach(i -> executorService.submit(runnableTask)); - - //Then - assertThat(((ThreadPoolExecutor )executorService).getQueue().size(), is(equalTo(5))); + + // Then + assertThat(((ThreadPoolExecutor) executorService).getQueue() + .size(), is(equalTo(5))); + } + + @Test + public void givenAnExecutorService() throws Exception { + + while (true) { + TimeUnit.SECONDS.sleep(5); + new Thread(() -> { + try { + TimeUnit.HOURS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + } } } From 6c6dbd6e96eacfeee56176bf2ad45ad5ad350b20 Mon Sep 17 00:00:00 2001 From: musibs Date: Tue, 2 Jun 2020 18:13:56 +0530 Subject: [PATCH 042/118] Removed the long running test case --- .../error/oom/ExecutorServiceUnitTest.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java index 4e7dea370e..47bb668727 100644 --- a/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java +++ b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/error/oom/ExecutorServiceUnitTest.java @@ -37,19 +37,4 @@ public class ExecutorServiceUnitTest { assertThat(((ThreadPoolExecutor) executorService).getQueue() .size(), is(equalTo(5))); } - - @Test - public void givenAnExecutorService() throws Exception { - - while (true) { - TimeUnit.SECONDS.sleep(5); - new Thread(() -> { - try { - TimeUnit.HOURS.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }).start(); - } - } } From 5b7dde1ae8c592c12161429037f81254748ddf0b Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Sun, 31 May 2020 23:20:10 +0430 Subject: [PATCH 043/118] Adapting the VarHandle Code to Best Practices --- .../varhandles/VariableHandlesUnitTest.java | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java index 56e34f06a0..78a1ae3162 100644 --- a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java +++ b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java @@ -6,8 +6,9 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.*; -public class VariableHandlesUnitTest { +public class VariableHandlesTest { public int publicTestVariable = 1; private int privateTestVariable = 1; @@ -18,25 +19,23 @@ public class VariableHandlesUnitTest { @Test public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle PUBLIC_TEST_VARIABLE = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class); - - assertThat(publicIntHandle.coordinateTypes().size() == 1); - assertThat(publicIntHandle.coordinateTypes().get(0) == VariableHandlesUnitTest.class); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class); + assertEquals(1, PUBLIC_TEST_VARIABLE.coordinateTypes().size()); + assertEquals(VariableHandlesTest.class, PUBLIC_TEST_VARIABLE.coordinateTypes().get(0)); } @Test public void whenVariableHandleForPrivateVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException { - VarHandle privateIntHandle = MethodHandles - .privateLookupIn(VariableHandlesUnitTest.class, MethodHandles.lookup()) - .findVarHandle(VariableHandlesUnitTest.class, "privateTestVariable", int.class); - - assertThat(privateIntHandle.coordinateTypes().size() == 1); - assertThat(privateIntHandle.coordinateTypes().get(0) == VariableHandlesUnitTest.class); + VarHandle PRIVATE_TEST_VARIABLE = MethodHandles + .privateLookupIn(VariableHandlesTest.class, MethodHandles.lookup()) + .findVarHandle(VariableHandlesTest.class, "privateTestVariable", int.class); + assertEquals(1, PRIVATE_TEST_VARIABLE.coordinateTypes().size()); + assertEquals(VariableHandlesTest.class, PRIVATE_TEST_VARIABLE.coordinateTypes().get(0)); } @Test @@ -44,63 +43,64 @@ public class VariableHandlesUnitTest { VarHandle arrayVarHandle = MethodHandles .arrayElementVarHandle(int[].class); - assertThat(arrayVarHandle.coordinateTypes().size() == 2); - assertThat(arrayVarHandle.coordinateTypes().get(0) == int[].class); + assertEquals(2, arrayVarHandle.coordinateTypes().size()); + assertEquals(int[].class, arrayVarHandle.coordinateTypes().get(0)); } @Test public void givenVarHandle_whenGetIsInvoked_ThenValueOfVariableIsReturned() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle PUBLIC_TEST_VARIABLE = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class); - assertThat((int) publicIntHandle.get(this) == 1); + assertEquals(1, (int) PUBLIC_TEST_VARIABLE.get(this)); } @Test public void givenVarHandle_whenSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle VARIABLE_TO_SET = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "variableToSet", int.class); - publicIntHandle.set(this, 15); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "variableToSet", int.class); - assertThat((int) publicIntHandle.get(this) == 15); + VARIABLE_TO_SET.set(this, 15); + assertEquals(15, (int) VARIABLE_TO_SET.get(this)); } @Test public void givenVarHandle_whenCompareAndSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle VARIABLE_TO_COMPARE_AND_SET = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "variableToCompareAndSet", int.class); - publicIntHandle.compareAndSet(this, 1, 100); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "variableToCompareAndSet", int.class); - assertThat((int) publicIntHandle.get(this) == 100); + VARIABLE_TO_COMPARE_AND_SET.compareAndSet(this, 1, 100); + assertEquals(100, (int) VARIABLE_TO_COMPARE_AND_SET.get(this)); } @Test public void givenVarHandle_whenGetAndAddIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle VARIABLE_TO_GET_AND_ADD = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "variableToGetAndAdd", int.class); - int before = (int) publicIntHandle.getAndAdd(this, 200); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "variableToGetAndAdd", int.class); - assertThat(before == 0); - assertThat((int) publicIntHandle.get(this) == 200); + int before = (int) VARIABLE_TO_GET_AND_ADD.getAndAdd(this, 200); + + assertEquals(0, before); + assertEquals(200, (int) VARIABLE_TO_GET_AND_ADD.get(this)); } @Test public void givenVarHandle_whenGetAndBitwiseOrIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { - VarHandle publicIntHandle = MethodHandles + VarHandle VARIABLE_TO_BITWISE_OR = MethodHandles .lookup() - .in(VariableHandlesUnitTest.class) - .findVarHandle(VariableHandlesUnitTest.class, "variableToBitwiseOr", byte.class); - byte before = (byte) publicIntHandle.getAndBitwiseOr(this, (byte) 127); + .in(VariableHandlesTest.class) + .findVarHandle(VariableHandlesTest.class, "variableToBitwiseOr", byte.class); + byte before = (byte) VARIABLE_TO_BITWISE_OR.getAndBitwiseOr(this, (byte) 127); - assertThat(before == 0); - assertThat(variableToBitwiseOr == 127); + assertEquals(0, before); + assertEquals(127, (byte) VARIABLE_TO_BITWISE_OR.get(this)); } } From 756f70b29f1de78ce0f8af5761a1b7819b18d6bf Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Tue, 2 Jun 2020 21:07:48 +0430 Subject: [PATCH 044/118] Rename the Class --- .../varhandles/VariableHandlesUnitTest.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java index 78a1ae3162..a7263f0bb2 100644 --- a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java +++ b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/varhandles/VariableHandlesUnitTest.java @@ -5,10 +5,9 @@ import org.junit.Test; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; -public class VariableHandlesTest { +public class VariableHandlesUnitTest { public int publicTestVariable = 1; private int privateTestVariable = 1; @@ -21,21 +20,21 @@ public class VariableHandlesTest { public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException { VarHandle PUBLIC_TEST_VARIABLE = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class); assertEquals(1, PUBLIC_TEST_VARIABLE.coordinateTypes().size()); - assertEquals(VariableHandlesTest.class, PUBLIC_TEST_VARIABLE.coordinateTypes().get(0)); + assertEquals(VariableHandlesUnitTest.class, PUBLIC_TEST_VARIABLE.coordinateTypes().get(0)); } @Test public void whenVariableHandleForPrivateVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException { VarHandle PRIVATE_TEST_VARIABLE = MethodHandles - .privateLookupIn(VariableHandlesTest.class, MethodHandles.lookup()) - .findVarHandle(VariableHandlesTest.class, "privateTestVariable", int.class); + .privateLookupIn(VariableHandlesUnitTest.class, MethodHandles.lookup()) + .findVarHandle(VariableHandlesUnitTest.class, "privateTestVariable", int.class); assertEquals(1, PRIVATE_TEST_VARIABLE.coordinateTypes().size()); - assertEquals(VariableHandlesTest.class, PRIVATE_TEST_VARIABLE.coordinateTypes().get(0)); + assertEquals(VariableHandlesUnitTest.class, PRIVATE_TEST_VARIABLE.coordinateTypes().get(0)); } @Test @@ -51,8 +50,8 @@ public class VariableHandlesTest { public void givenVarHandle_whenGetIsInvoked_ThenValueOfVariableIsReturned() throws NoSuchFieldException, IllegalAccessException { VarHandle PUBLIC_TEST_VARIABLE = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class); assertEquals(1, (int) PUBLIC_TEST_VARIABLE.get(this)); } @@ -61,8 +60,8 @@ public class VariableHandlesTest { public void givenVarHandle_whenSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { VarHandle VARIABLE_TO_SET = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "variableToSet", int.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "variableToSet", int.class); VARIABLE_TO_SET.set(this, 15); assertEquals(15, (int) VARIABLE_TO_SET.get(this)); @@ -72,8 +71,8 @@ public class VariableHandlesTest { public void givenVarHandle_whenCompareAndSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { VarHandle VARIABLE_TO_COMPARE_AND_SET = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "variableToCompareAndSet", int.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "variableToCompareAndSet", int.class); VARIABLE_TO_COMPARE_AND_SET.compareAndSet(this, 1, 100); assertEquals(100, (int) VARIABLE_TO_COMPARE_AND_SET.get(this)); @@ -83,8 +82,8 @@ public class VariableHandlesTest { public void givenVarHandle_whenGetAndAddIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { VarHandle VARIABLE_TO_GET_AND_ADD = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "variableToGetAndAdd", int.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "variableToGetAndAdd", int.class); int before = (int) VARIABLE_TO_GET_AND_ADD.getAndAdd(this, 200); @@ -96,8 +95,8 @@ public class VariableHandlesTest { public void givenVarHandle_whenGetAndBitwiseOrIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException { VarHandle VARIABLE_TO_BITWISE_OR = MethodHandles .lookup() - .in(VariableHandlesTest.class) - .findVarHandle(VariableHandlesTest.class, "variableToBitwiseOr", byte.class); + .in(VariableHandlesUnitTest.class) + .findVarHandle(VariableHandlesUnitTest.class, "variableToBitwiseOr", byte.class); byte before = (byte) VARIABLE_TO_BITWISE_OR.getAndBitwiseOr(this, (byte) 127); assertEquals(0, before); From be292ec3f22c4ca82e7154718d89595c9cd1c9c6 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Tue, 2 Jun 2020 21:32:45 +0430 Subject: [PATCH 045/118] Avoid Using newInstance on Class --- .../reflection/java/reflection/ReflectionUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/java/reflection/ReflectionUnitTest.java b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/java/reflection/ReflectionUnitTest.java index 0c090901e7..a791d64874 100644 --- a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/java/reflection/ReflectionUnitTest.java +++ b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/java/reflection/ReflectionUnitTest.java @@ -200,7 +200,7 @@ public class ReflectionUnitTest { @Test public void givenClassField_whenSetsAndGetsValue_thenCorrect() throws Exception { final Class birdClass = Class.forName("com.baeldung.java.reflection.Bird"); - final Bird bird = (Bird) birdClass.newInstance(); + final Bird bird = (Bird) birdClass.getConstructor().newInstance(); final Field field = birdClass.getDeclaredField("walks"); field.setAccessible(true); @@ -266,7 +266,7 @@ public class ReflectionUnitTest { @Test public void givenMethod_whenInvokes_thenCorrect() throws Exception { final Class birdClass = Class.forName("com.baeldung.java.reflection.Bird"); - final Bird bird = (Bird) birdClass.newInstance(); + final Bird bird = (Bird) birdClass.getConstructor().newInstance(); final Method setWalksMethod = birdClass.getDeclaredMethod("setWalks", boolean.class); final Method walksMethod = birdClass.getDeclaredMethod("walks"); final boolean walks = (boolean) walksMethod.invoke(bird); From 6dbd0c1d6cd61d81bf10413a09af83270eca69f2 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 2 Jun 2020 22:41:01 +0530 Subject: [PATCH 046/118] JAVA-932: Migrate spring-cloud-kubernetes to parent-boot-2 --- .../kubernetes-selfhealing/liveness-example/pom.xml | 9 ++++----- .../kubernetes-selfhealing/readiness-example/pom.xml | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/liveness-example/pom.xml b/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/liveness-example/pom.xml index 66d8f096ce..f0d34d2231 100644 --- a/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/liveness-example/pom.xml +++ b/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/liveness-example/pom.xml @@ -8,10 +8,10 @@ 1.0-SNAPSHOT - com.baeldung - parent-boot-1 - 0.0.1-SNAPSHOT - ../../../../parent-boot-1 + com.baeldung.spring.cloud + spring-cloud-kubernetes + 1.0-SNAPSHOT + ../../../spring-cloud-kubernetes @@ -44,7 +44,6 @@ UTF-8 UTF-8 - 1.5.17.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/readiness-example/pom.xml b/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/readiness-example/pom.xml index fbb9e09d07..8bfd4d305d 100644 --- a/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/readiness-example/pom.xml +++ b/spring-cloud/spring-cloud-kubernetes/kubernetes-selfhealing/readiness-example/pom.xml @@ -8,10 +8,10 @@ 1.0-SNAPSHOT - com.baeldung - parent-boot-1 - 0.0.1-SNAPSHOT - ../../../../parent-boot-1 + com.baeldung.spring.cloud + spring-cloud-kubernetes + 1.0-SNAPSHOT + ../../../spring-cloud-kubernetes @@ -44,7 +44,6 @@ UTF-8 UTF-8 - 1.5.17.RELEASE \ No newline at end of file From 89ea700e24631a695118e02ecf1e4ef831a00a08 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 2 Jun 2020 22:55:10 +0530 Subject: [PATCH 047/118] JAVA-39: Removed module spring-security-kerberos --- .../spring-security-kerberos/README.md | 13 --- .../spring-security-kerberos/pom.xml | 69 --------------- .../main/java/com/baeldung/Application.java | 13 --- .../baeldung/config/WebSecurityConfig.java | 87 ------------------- .../security/DummyUserDetailsService.java | 16 ---- 5 files changed, 198 deletions(-) delete mode 100644 spring-security-modules/spring-security-kerberos/README.md delete mode 100644 spring-security-modules/spring-security-kerberos/pom.xml delete mode 100644 spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/Application.java delete mode 100644 spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/config/WebSecurityConfig.java delete mode 100644 spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/security/DummyUserDetailsService.java diff --git a/spring-security-modules/spring-security-kerberos/README.md b/spring-security-modules/spring-security-kerberos/README.md deleted file mode 100644 index a868fb86b7..0000000000 --- a/spring-security-modules/spring-security-kerberos/README.md +++ /dev/null @@ -1,13 +0,0 @@ -## Spring Security Kerberos - -This module contains articles about Spring Security Kerberos - -### Relevant Articles: - -- [Introduction to SPNEGO/Kerberos Authentication in Spring](https://www.baeldung.com/spring-security-kerberos) - -### @PreFilter and @PostFilter annotations - -### Build the Project ### - -`mvn clean install` \ No newline at end of file diff --git a/spring-security-modules/spring-security-kerberos/pom.xml b/spring-security-modules/spring-security-kerberos/pom.xml deleted file mode 100644 index 51a48a78c6..0000000000 --- a/spring-security-modules/spring-security-kerberos/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - 4.0.0 - spring-security-kerberos - 0.1-SNAPSHOT - spring-security-kerberos - war - - - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-security - - - - org.springframework.security.kerberos - spring-security-kerberos-core - ${spring-security-kerberos.version} - - - org.springframework.security.kerberos - spring-security-kerberos-web - ${spring-security-kerberos.version} - - - org.springframework.security.kerberos - spring-security-kerberos-client - ${spring-security-kerberos.version} - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - - - - - org.apache.maven.plugins - maven-war-plugin - - - - - - 1.0.1.RELEASE - - - diff --git a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/Application.java b/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/Application.java deleted file mode 100644 index 37dbe7dab8..0000000000 --- a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/Application.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/config/WebSecurityConfig.java b/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/config/WebSecurityConfig.java deleted file mode 100644 index c1c206e5c9..0000000000 --- a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/config/WebSecurityConfig.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.baeldung.config; - -import com.baeldung.security.DummyUserDetailsService; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.FileSystemResource; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; -import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; -import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; -import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; -import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter; -import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; - -@Configuration -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests() - .anyRequest() - .authenticated() - .and() - .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class); - } - - @Override - @Bean - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.authenticationProvider(kerberosAuthenticationProvider()) - .authenticationProvider(kerberosServiceAuthenticationProvider()); - } - - @Bean - public KerberosAuthenticationProvider kerberosAuthenticationProvider() { - KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); - SunJaasKerberosClient client = new SunJaasKerberosClient(); - client.setDebug(true); - provider.setKerberosClient(client); - provider.setUserDetailsService(dummyUserDetailsService()); - return provider; - } - - @Bean - public SpnegoEntryPoint spnegoEntryPoint() { - return new SpnegoEntryPoint("/login"); - } - - @Bean - public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(AuthenticationManager authenticationManager) { - SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); - filter.setAuthenticationManager(authenticationManager); - return filter; - } - - @Bean - public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { - KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); - provider.setTicketValidator(sunJaasKerberosTicketValidator()); - provider.setUserDetailsService(dummyUserDetailsService()); - return provider; - } - - @Bean - public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { - SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); - ticketValidator.setServicePrincipal("HTTP/demo.kerberos.bealdung.com@baeldung.com"); - ticketValidator.setKeyTabLocation(new FileSystemResource("baeldung.keytab")); - ticketValidator.setDebug(true); - return ticketValidator; - } - - @Bean - public DummyUserDetailsService dummyUserDetailsService() { - return new DummyUserDetailsService(); - } - -} \ No newline at end of file diff --git a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/security/DummyUserDetailsService.java b/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/security/DummyUserDetailsService.java deleted file mode 100644 index 6ddd6c8969..0000000000 --- a/spring-security-modules/spring-security-kerberos/src/main/java/com/baeldung/security/DummyUserDetailsService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.security; - -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -public class DummyUserDetailsService implements UserDetailsService { - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return new User(username, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER")); - } - -} \ No newline at end of file From 97fa800bbdb54d81923fc224cac4c312ad808f88 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 2 Jun 2020 22:56:31 +0530 Subject: [PATCH 048/118] JAVA-39: Moved article from spring-security kerberos module to spring-security-sso/spring-security-sso-kerberos --- .../spring-security-sso-kerberos/README.md | 1 + .../java/com/baeldung/intro/Application.java | 13 +++ .../intro/config/WebSecurityConfig.java | 88 +++++++++++++++++++ .../security/DummyUserDetailsService.java | 16 ++++ 4 files changed, 118 insertions(+) create mode 100644 spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/Application.java create mode 100644 spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/config/WebSecurityConfig.java create mode 100644 spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/security/DummyUserDetailsService.java diff --git a/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/README.md b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/README.md index 3aa092edb8..4bb0eea16c 100644 --- a/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/README.md +++ b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/README.md @@ -1,3 +1,4 @@ ## Relevant articles: - [Spring Security Kerberos Integration](https://www.baeldung.com/spring-security-kerberos-integration) +- [Introduction to SPNEGO/Kerberos Authentication in Spring](https://www.baeldung.com/spring-security-kerberos) diff --git a/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/Application.java b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/Application.java new file mode 100644 index 0000000000..2cddbf0f22 --- /dev/null +++ b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.intro; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/config/WebSecurityConfig.java b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/config/WebSecurityConfig.java new file mode 100644 index 0000000000..cc694a3b83 --- /dev/null +++ b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/config/WebSecurityConfig.java @@ -0,0 +1,88 @@ +package com.baeldung.intro.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; +import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; +import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter; +import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import com.baeldung.intro.security.DummyUserDetailsService; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .anyRequest() + .authenticated() + .and() + .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class); + } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(kerberosAuthenticationProvider()) + .authenticationProvider(kerberosServiceAuthenticationProvider()); + } + + @Bean + public KerberosAuthenticationProvider kerberosAuthenticationProvider() { + KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); + SunJaasKerberosClient client = new SunJaasKerberosClient(); + client.setDebug(true); + provider.setKerberosClient(client); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SpnegoEntryPoint spnegoEntryPoint() { + return new SpnegoEntryPoint("/login"); + } + + @Bean + public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(AuthenticationManager authenticationManager) { + SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } + + @Bean + public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { + KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); + provider.setTicketValidator(sunJaasKerberosTicketValidator()); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { + SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); + ticketValidator.setServicePrincipal("HTTP/demo.kerberos.bealdung.com@baeldung.com"); + ticketValidator.setKeyTabLocation(new FileSystemResource("baeldung.keytab")); + ticketValidator.setDebug(true); + return ticketValidator; + } + + @Bean + public DummyUserDetailsService dummyUserDetailsService() { + return new DummyUserDetailsService(); + } + +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/security/DummyUserDetailsService.java b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/security/DummyUserDetailsService.java new file mode 100644 index 0000000000..f564c9f756 --- /dev/null +++ b/spring-security-modules/spring-security-sso/spring-security-sso-kerberos/src/main/java/com/baeldung/intro/security/DummyUserDetailsService.java @@ -0,0 +1,16 @@ +package com.baeldung.intro.security; + +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class DummyUserDetailsService implements UserDetailsService { + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return new User(username, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER")); + } + +} \ No newline at end of file From d214da3cb1deeba6a17d48973605cf25da8392d2 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 2 Jun 2020 22:57:22 +0530 Subject: [PATCH 049/118] JAVA-39: Updated parent module pom to remove deleted module --- spring-security-modules/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 60a662781f..954b9335e4 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -20,7 +20,6 @@ spring-security-cache-control spring-security-core spring-security-cors - spring-security-kerberos spring-security-mvc spring-security-mvc-boot-1 spring-security-mvc-boot-2 From b07bcce7efcdf939dd336b2dceabbb88449b89b9 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Tue, 2 Jun 2020 22:03:54 +0430 Subject: [PATCH 050/118] Introducing Integer Cache --- .../stringtoint/StringToIntOrIntegerUnitTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core-java-modules/core-java-string-conversions/src/test/java/com/baeldung/stringtoint/StringToIntOrIntegerUnitTest.java b/core-java-modules/core-java-string-conversions/src/test/java/com/baeldung/stringtoint/StringToIntOrIntegerUnitTest.java index 106f1fc974..336b2ac324 100644 --- a/core-java-modules/core-java-string-conversions/src/test/java/com/baeldung/stringtoint/StringToIntOrIntegerUnitTest.java +++ b/core-java-modules/core-java-string-conversions/src/test/java/com/baeldung/stringtoint/StringToIntOrIntegerUnitTest.java @@ -26,6 +26,17 @@ public class StringToIntOrIntegerUnitTest { assertThat(result).isEqualTo(new Integer(42)); } + @Test + public void givenString_whenCallingValueOf_shouldCacheSomeValues() { + for (int i = -128; i <= 127; i++) { + String value = i + ""; + Integer first = Integer.valueOf(value); + Integer second = Integer.valueOf(value); + + assertThat(first).isSameAs(second); + } + } + @Test public void givenString_whenCallingIntegerConstructor_shouldConvertToInt() { String givenString = "42"; From 2af1e30a8f70394d6914a4a2b43aa9b0b68ca78b Mon Sep 17 00:00:00 2001 From: Mona Mohamadinia Date: Tue, 2 Jun 2020 23:01:56 +0430 Subject: [PATCH 051/118] KTLN-141: Not-Null Assertion (!!) Operator in Kotlin (#9371) * Added the Test Samples * Renamed the Class --- .../nullassertion/NotNullAssertionUnitTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt b/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt new file mode 100644 index 0000000000..434f177927 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt @@ -0,0 +1,20 @@ +package com.baeldung.nullassertion + +import org.junit.Test +import kotlin.test.assertEquals + +class NotNullAssertionUnitTest { + + @Test + fun givenNullableValue_WhenNotNull_ShouldExtractTheValue() { + val answer: String? = "42" + + assertEquals(42, answer!!.toInt()) + } + + @Test(expected = KotlinNullPointerException::class) + fun givenNullableValue_WhenIsNull_ThenShouldThrow() { + val noAnswer: String? = null + noAnswer!! + } +} From d59d2e3793d951853fea5b7e5ae67cd8c1f3f695 Mon Sep 17 00:00:00 2001 From: kwoyke Date: Tue, 2 Jun 2020 21:04:09 +0200 Subject: [PATCH 052/118] BAEL-4171: Add SecurityAdviceTrait to the ExceptionTranslator (#9418) --- .../jhipster/gateway/web/rest/errors/ExceptionTranslator.java | 3 ++- .../jhipster/quotes/web/rest/errors/ExceptionTranslator.java | 3 ++- .../jhipster/uaa/web/rest/errors/ExceptionTranslator.java | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/jhipster/jhipster-uaa/gateway/src/main/java/com/baeldung/jhipster/gateway/web/rest/errors/ExceptionTranslator.java b/jhipster/jhipster-uaa/gateway/src/main/java/com/baeldung/jhipster/gateway/web/rest/errors/ExceptionTranslator.java index d5c9e577a6..fd6e04dadc 100644 --- a/jhipster/jhipster-uaa/gateway/src/main/java/com/baeldung/jhipster/gateway/web/rest/errors/ExceptionTranslator.java +++ b/jhipster/jhipster-uaa/gateway/src/main/java/com/baeldung/jhipster/gateway/web/rest/errors/ExceptionTranslator.java @@ -14,6 +14,7 @@ import org.zalando.problem.Problem; import org.zalando.problem.ProblemBuilder; import org.zalando.problem.Status; import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait; import org.zalando.problem.violations.ConstraintViolationProblem; import javax.annotation.Nonnull; @@ -28,7 +29,7 @@ import java.util.stream.Collectors; * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) */ @ControllerAdvice -public class ExceptionTranslator implements ProblemHandling { +public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait { /** * Post-process the Problem payload to add the message key for the front-end if needed diff --git a/jhipster/jhipster-uaa/quotes/src/main/java/com/baeldung/jhipster/quotes/web/rest/errors/ExceptionTranslator.java b/jhipster/jhipster-uaa/quotes/src/main/java/com/baeldung/jhipster/quotes/web/rest/errors/ExceptionTranslator.java index 18baa42736..3bf4995405 100644 --- a/jhipster/jhipster-uaa/quotes/src/main/java/com/baeldung/jhipster/quotes/web/rest/errors/ExceptionTranslator.java +++ b/jhipster/jhipster-uaa/quotes/src/main/java/com/baeldung/jhipster/quotes/web/rest/errors/ExceptionTranslator.java @@ -14,6 +14,7 @@ import org.zalando.problem.Problem; import org.zalando.problem.ProblemBuilder; import org.zalando.problem.Status; import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait; import org.zalando.problem.violations.ConstraintViolationProblem; import javax.annotation.Nonnull; @@ -28,7 +29,7 @@ import java.util.stream.Collectors; * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) */ @ControllerAdvice -public class ExceptionTranslator implements ProblemHandling { +public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait { /** * Post-process the Problem payload to add the message key for the front-end if needed diff --git a/jhipster/jhipster-uaa/uaa/src/main/java/com/baeldung/jhipster/uaa/web/rest/errors/ExceptionTranslator.java b/jhipster/jhipster-uaa/uaa/src/main/java/com/baeldung/jhipster/uaa/web/rest/errors/ExceptionTranslator.java index 320636c51d..6af9fd126c 100644 --- a/jhipster/jhipster-uaa/uaa/src/main/java/com/baeldung/jhipster/uaa/web/rest/errors/ExceptionTranslator.java +++ b/jhipster/jhipster-uaa/uaa/src/main/java/com/baeldung/jhipster/uaa/web/rest/errors/ExceptionTranslator.java @@ -14,6 +14,7 @@ import org.zalando.problem.Problem; import org.zalando.problem.ProblemBuilder; import org.zalando.problem.Status; import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait; import org.zalando.problem.violations.ConstraintViolationProblem; import javax.annotation.Nonnull; @@ -28,7 +29,7 @@ import java.util.stream.Collectors; * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) */ @ControllerAdvice -public class ExceptionTranslator implements ProblemHandling { +public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait { /** * Post-process the Problem payload to add the message key for the front-end if needed From 9d4a0b1f516dbe591c1d62c7f404826c72ef7a4c Mon Sep 17 00:00:00 2001 From: kwoyke Date: Tue, 2 Jun 2020 21:15:49 +0200 Subject: [PATCH 053/118] BAEL-4100: Move HTTP/2 in Jetty to the new libraries-server-2 module (#9394) --- libraries-server-2/.gitignore | 9 ++ libraries-server-2/README.md | 8 ++ libraries-server-2/pom.xml | 77 ++++++++++++++++++ .../src/main/config/jetty.xml | 0 .../jetty/http2/Http2JettyServlet.java | 0 .../src/main/resources/keystore.jks | Bin .../src/main/resources/logback.xml | 13 +++ .../src/main/resources/truststore.jks | Bin .../src/main/webapp/WEB-INF/web.xml | 0 .../src/main/webapp/http2.html | 0 .../images/homepage-latest_articles.jpg | Bin .../images/homepage-rest_with_spring.jpg | Bin .../webapp/images/homepage-weekly_reviews.jpg | Bin .../src/main/webapp/index.html | 0 libraries-server/README.md | 2 +- libraries-server/pom.xml | 40 --------- pom.xml | 2 + 17 files changed, 110 insertions(+), 41 deletions(-) create mode 100644 libraries-server-2/.gitignore create mode 100644 libraries-server-2/README.md create mode 100644 libraries-server-2/pom.xml rename {libraries-server => libraries-server-2}/src/main/config/jetty.xml (100%) rename {libraries-server => libraries-server-2}/src/main/java/com/baeldung/jetty/http2/Http2JettyServlet.java (100%) rename {libraries-server => libraries-server-2}/src/main/resources/keystore.jks (100%) create mode 100644 libraries-server-2/src/main/resources/logback.xml rename {libraries-server => libraries-server-2}/src/main/resources/truststore.jks (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/WEB-INF/web.xml (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/http2.html (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/images/homepage-latest_articles.jpg (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/images/homepage-rest_with_spring.jpg (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/images/homepage-weekly_reviews.jpg (100%) rename {libraries-server => libraries-server-2}/src/main/webapp/index.html (100%) diff --git a/libraries-server-2/.gitignore b/libraries-server-2/.gitignore new file mode 100644 index 0000000000..e594daf27a --- /dev/null +++ b/libraries-server-2/.gitignore @@ -0,0 +1,9 @@ +*.class + +# Folders # +/gensrc +/target + +# Packaged files # +*.jar +/bin/ diff --git a/libraries-server-2/README.md b/libraries-server-2/README.md new file mode 100644 index 0000000000..38166bcd77 --- /dev/null +++ b/libraries-server-2/README.md @@ -0,0 +1,8 @@ +## Server + +This module contains articles about server libraries. + +### Relevant Articles: + +- [HTTP/2 in Jetty](https://www.baeldung.com/jetty-http-2) +- More articles: [[<-- prev]](../libraries-server) diff --git a/libraries-server-2/pom.xml b/libraries-server-2/pom.xml new file mode 100644 index 0000000000..5f500a7ced --- /dev/null +++ b/libraries-server-2/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + libraries-server-2 + 0.0.1-SNAPSHOT + libraries-server-2 + war + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + org.eclipse.jetty + jetty-webapp + ${jetty.version} + + + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + 8888 + quit + + -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar + + ${basedir}/src/main/config/jetty.xml + + / + + + + + org.eclipse.jetty.http2 + http2-server + ${jetty.version} + + + org.eclipse.jetty + jetty-alpn-openjdk8-server + ${jetty.version} + + + org.eclipse.jetty + jetty-servlets + ${jetty.version} + + + + + + + + 9.4.27.v20200227 + 8.1.11.v20170118 + + + \ No newline at end of file diff --git a/libraries-server/src/main/config/jetty.xml b/libraries-server-2/src/main/config/jetty.xml similarity index 100% rename from libraries-server/src/main/config/jetty.xml rename to libraries-server-2/src/main/config/jetty.xml diff --git a/libraries-server/src/main/java/com/baeldung/jetty/http2/Http2JettyServlet.java b/libraries-server-2/src/main/java/com/baeldung/jetty/http2/Http2JettyServlet.java similarity index 100% rename from libraries-server/src/main/java/com/baeldung/jetty/http2/Http2JettyServlet.java rename to libraries-server-2/src/main/java/com/baeldung/jetty/http2/Http2JettyServlet.java diff --git a/libraries-server/src/main/resources/keystore.jks b/libraries-server-2/src/main/resources/keystore.jks similarity index 100% rename from libraries-server/src/main/resources/keystore.jks rename to libraries-server-2/src/main/resources/keystore.jks diff --git a/libraries-server-2/src/main/resources/logback.xml b/libraries-server-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/libraries-server-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/libraries-server/src/main/resources/truststore.jks b/libraries-server-2/src/main/resources/truststore.jks similarity index 100% rename from libraries-server/src/main/resources/truststore.jks rename to libraries-server-2/src/main/resources/truststore.jks diff --git a/libraries-server/src/main/webapp/WEB-INF/web.xml b/libraries-server-2/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from libraries-server/src/main/webapp/WEB-INF/web.xml rename to libraries-server-2/src/main/webapp/WEB-INF/web.xml diff --git a/libraries-server/src/main/webapp/http2.html b/libraries-server-2/src/main/webapp/http2.html similarity index 100% rename from libraries-server/src/main/webapp/http2.html rename to libraries-server-2/src/main/webapp/http2.html diff --git a/libraries-server/src/main/webapp/images/homepage-latest_articles.jpg b/libraries-server-2/src/main/webapp/images/homepage-latest_articles.jpg similarity index 100% rename from libraries-server/src/main/webapp/images/homepage-latest_articles.jpg rename to libraries-server-2/src/main/webapp/images/homepage-latest_articles.jpg diff --git a/libraries-server/src/main/webapp/images/homepage-rest_with_spring.jpg b/libraries-server-2/src/main/webapp/images/homepage-rest_with_spring.jpg similarity index 100% rename from libraries-server/src/main/webapp/images/homepage-rest_with_spring.jpg rename to libraries-server-2/src/main/webapp/images/homepage-rest_with_spring.jpg diff --git a/libraries-server/src/main/webapp/images/homepage-weekly_reviews.jpg b/libraries-server-2/src/main/webapp/images/homepage-weekly_reviews.jpg similarity index 100% rename from libraries-server/src/main/webapp/images/homepage-weekly_reviews.jpg rename to libraries-server-2/src/main/webapp/images/homepage-weekly_reviews.jpg diff --git a/libraries-server/src/main/webapp/index.html b/libraries-server-2/src/main/webapp/index.html similarity index 100% rename from libraries-server/src/main/webapp/index.html rename to libraries-server-2/src/main/webapp/index.html diff --git a/libraries-server/README.md b/libraries-server/README.md index 7e41f33a0c..570806611f 100644 --- a/libraries-server/README.md +++ b/libraries-server/README.md @@ -13,4 +13,4 @@ This module contains articles about server libraries. - [MQTT Client in Java](https://www.baeldung.com/java-mqtt-client) - [Guide to XMPP Smack Client](https://www.baeldung.com/xmpp-smack-chat-client) - [A Guide to NanoHTTPD](https://www.baeldung.com/nanohttpd) -- [HTTP/2 in Jetty](https://www.baeldung.com/jetty-http-2) +- More articles: [[more -->]](../libraries-server-2) \ No newline at end of file diff --git a/libraries-server/pom.xml b/libraries-server/pom.xml index eb9cb61e56..d9546f1678 100644 --- a/libraries-server/pom.xml +++ b/libraries-server/pom.xml @@ -5,7 +5,6 @@ libraries-server 0.0.1-SNAPSHOT libraries-server - war com.baeldung @@ -107,50 +106,11 @@ - - - - org.eclipse.jetty - jetty-maven-plugin - ${jetty.version} - - 8888 - quit - - -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar - - ${basedir}/src/main/config/jetty.xml - - / - - - - - org.eclipse.jetty.http2 - http2-server - ${jetty.version} - - - org.eclipse.jetty - jetty-alpn-openjdk8-server - ${jetty.version} - - - org.eclipse.jetty - jetty-servlets - ${jetty.version} - - - - - - 3.6.2 4.5.3 9.4.27.v20200227 4.1.20.Final - 8.1.11.v20170118 8.5.24 4.3.1 1.2.0 diff --git a/pom.xml b/pom.xml index 2efea40c91..f797f1bbce 100644 --- a/pom.xml +++ b/pom.xml @@ -513,6 +513,7 @@ libraries-rpc libraries-security libraries-server + libraries-server-2 libraries-testing linkrest logging-modules @@ -1032,6 +1033,7 @@ libraries-primitive libraries-security libraries-server + libraries-server-2 libraries-testing linkrest logging-modules From dd5e1190fa445295e61b46d35f9fdf5f9b8e56ce Mon Sep 17 00:00:00 2001 From: Cristian Rosu Date: Tue, 2 Jun 2020 22:53:54 +0300 Subject: [PATCH 054/118] BAEL-4070: updated test names to match Baeldung's guidelines + makred test as Unit Test instead of Integration Test --- ...ionTest.java => ListsPropertiesUnitTest.java} | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) rename spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/{ListsPropertiesIntegrationTest.java => ListsPropertiesUnitTest.java} (79%) diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java similarity index 79% rename from spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java rename to spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java index 4047e1ea95..8c1835a0a9 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java @@ -16,7 +16,7 @@ import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringListPropertiesApplication.class}) -public class ListsPropertiesIntegrationTest { +public class ListsPropertiesUnitTest { @Value("${arrayOfStrings}") private String[] arrayOfStrings; @@ -46,39 +46,39 @@ public class ListsPropertiesIntegrationTest { private Environment environment; @Test - public void givenContextIsInitialized_ThenInjectedArrayContainsExpectedValues() { + public void whenContextIsInitialized_ThenInjectedArrayContainsExpectedValues() { assertEquals(arrayOfStrings, new String[] {"Baeldung", "dot", "com"}); } @Test - public void givenContextIsInitialized_ThenInjectedListContainsUnexpectedValues() { + public void whenContextIsInitialized_ThenInjectedListContainsUnexpectedValues() { assertEquals(unexpectedListOfStrings, Collections.singletonList("Baeldung,dot,com")); } @Test - public void givenContextIsInitialized_ThenInjectedListContainsExpectedValues() { + public void whenContextIsInitialized_ThenInjectedListContainsExpectedValues() { assertEquals(listOfStrings, Arrays.asList("Baeldung", "dot", "com")); } @Test - public void givenContextIsInitialized_ThenInjectedListV2ContainsExpectedValues() { + public void whenContextIsInitialized_ThenInjectedListV2ContainsExpectedValues() { assertEquals(listOfStringsV2, Arrays.asList("Baeldung", "dot", "com")); } @Test - public void givenContextIsInitialized_ThenInjectedListWithCustomDelimiterContainsExpectedValues() { + public void whenContextIsInitialized_ThenInjectedListWithCustomDelimiterContainsExpectedValues() { assertEquals(listOfStringsWithCustomDelimiter, Arrays.asList("Baeldung", "dot", "com")); } @Test - public void givenContextIsInitialized_ThenInjectedListOfBasicTypesContainsExpectedValues() { + public void whenContextIsInitialized_ThenInjectedListOfBasicTypesContainsExpectedValues() { assertEquals(listOfBooleans, Arrays.asList(false, false, true)); assertEquals(listOfIntegers, Arrays.asList(1, 2, 3, 4)); assertEquals(listOfCharacters, Arrays.asList('a', 'b', 'c')); } @Test - public void givenContextIsInitialized_WhenReadingFromEnvironment_ThenPropertiesHaveExpectedValues() { + public void WhenReadingFromSpringEnvironment_ThenPropertiesHaveExpectedValues() { String[] arrayOfStrings = environment.getProperty("arrayOfStrings", String[].class); List listOfStrings = (List)environment.getProperty("arrayOfStrings", List.class); From f0befa0f8b9d263dfc167b1eac30389c7ca04898 Mon Sep 17 00:00:00 2001 From: Krzysztof Woyke Date: Wed, 3 Jun 2020 09:00:03 +0200 Subject: [PATCH 055/118] JAVA-1644: Remove overriden spring-boot.version property --- persistence-modules/spring-boot-persistence/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/persistence-modules/spring-boot-persistence/pom.xml b/persistence-modules/spring-boot-persistence/pom.xml index c58e8dbf86..cc26ff58d5 100644 --- a/persistence-modules/spring-boot-persistence/pom.xml +++ b/persistence-modules/spring-boot-persistence/pom.xml @@ -77,7 +77,6 @@ UTF-8 2.23.0 2.0.1.Final - 2.1.7.RELEASE From 8623df615bd3b3cc9e660297d5f2018318aaedaf Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Wed, 3 Jun 2020 12:36:24 +0300 Subject: [PATCH 056/118] BAEL-4049 - removed cglib --- core-java-modules/core-java-jvm/pom.xml | 5 ----- .../com/baeldung/bytecode/ViewBytecodeUnitTest.java | 11 ++--------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index f35efaa26b..0d6cc5c454 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -66,11 +66,6 @@ bcel 6.4.1 - - cglib - cglib - 3.3.0 - org.javassist javassist diff --git a/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java index 37ea6894c6..5b0fdf26d4 100644 --- a/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java +++ b/core-java-modules/core-java-jvm/src/test/java/com/baeldung/bytecode/ViewBytecodeUnitTest.java @@ -2,9 +2,11 @@ package com.baeldung.bytecode; import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; + import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; + import org.apache.bcel.Repository; import org.apache.bcel.classfile.JavaClass; import org.junit.Test; @@ -13,7 +15,6 @@ import org.objectweb.asm.util.TraceClassVisitor; import javassist.ClassPool; import javassist.NotFoundException; import javassist.bytecode.ClassFile; -import net.sf.cglib.reflect.FastClass; public class ViewBytecodeUnitTest { @@ -36,14 +37,6 @@ public class ViewBytecodeUnitTest { assertTrue(objectClazz.toString().contains("public class java.lang.Object")); } - @Test - public void whenUsingCglib_thenReadBytecode() { - FastClass fastClass = FastClass.create(java.lang.Object.class); - Class clazz = fastClass.getJavaClass(); - - assertEquals(clazz.toString(), "class java.lang.Object"); - } - @Test public void whenUsingJavassist_thenReadBytecode() throws NotFoundException { ClassPool cp = ClassPool.getDefault(); From a2b1be69fea729630b42fe77a329db1f87e39ca6 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Wed, 3 Jun 2020 12:40:32 +0300 Subject: [PATCH 057/118] BAEL-4049 - indentation fix --- core-java-modules/core-java-jvm/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index 0d6cc5c454..6663671579 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -52,9 +52,9 @@ ${java.home}/../lib/tools.jar - org.ow2.asm - asm - 8.0.1 + org.ow2.asm + asm + 8.0.1 org.ow2.asm @@ -67,9 +67,9 @@ 6.4.1 - org.javassist - javassist - 3.27.0-GA + org.javassist + javassist + 3.27.0-GA From 829140d488d33795b1c5b674cc4865f116391ba4 Mon Sep 17 00:00:00 2001 From: Ali Dehghani Date: Wed, 3 Jun 2020 14:10:58 +0430 Subject: [PATCH 058/118] Polluting the Heap --- .../varargs/HeapPollutionUnitTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/varargs/HeapPollutionUnitTest.java diff --git a/core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/varargs/HeapPollutionUnitTest.java b/core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/varargs/HeapPollutionUnitTest.java new file mode 100644 index 0000000000..ced2c00bea --- /dev/null +++ b/core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/varargs/HeapPollutionUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.varargs; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class HeapPollutionUnitTest { + + @Test(expected = ClassCastException.class) + public void givenGenericVararg_whenUsedUnsafe_shouldThrowClassCastException() { + String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList()); + + assertEquals("one", one); + } + + @Test(expected = ClassCastException.class) + public void givenGenericVararg_whenRefEscapes_mayCauseSubtleBugs() { + String[] args = returnAsIs("One", "Two"); + } + + private static String firstOfFirst(List... strings) { + List ints = Collections.singletonList(42); + Object[] objects = strings; + objects[0] = ints; + + return strings[0].get(0); + } + + private static T[] toArray(T... arguments) { + return arguments; + } + + private static T[] returnAsIs(T a, T b) { + return toArray(a, b); + } +} From b9105d78911c9bf1a8c308d12e994b42a5f3e703 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Wed, 3 Jun 2020 12:44:22 +0300 Subject: [PATCH 059/118] BAEL-4049 - indentation fix --- core-java-modules/core-java-jvm/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index 6663671579..55290bd292 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -55,9 +55,9 @@ org.ow2.asm asm 8.0.1 - - - org.ow2.asm + + + org.ow2.asm asm-util 8.0.1 From bc40ab12d750c967060001e8a35302940209a3e8 Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Wed, 3 Jun 2020 12:46:28 +0300 Subject: [PATCH 060/118] BAEL-4049 - indentation --- core-java-modules/core-java-jvm/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index 55290bd292..a2c35c154c 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -58,9 +58,9 @@ org.ow2.asm - asm-util - 8.0.1 - + asm-util + 8.0.1 + org.apache.bcel bcel From 078481781f3a45c175a5024bebd9e5705cd294ce Mon Sep 17 00:00:00 2001 From: Yavuz Tas <12643010+yavuztas@users.noreply.github.com> Date: Wed, 3 Jun 2020 14:59:42 +0200 Subject: [PATCH 061/118] Module for BAEL-3280 (#9329) * Module for BAEL-3280 * update comment to make it more clear * remove .gitignore file * remove name tag * fix typo * change module name to a generic one * add module to parent --- spring-boot-modules/pom.xml | 1 + .../.mvn/wrapper/maven-wrapper.properties | 1 + spring-boot-modules/spring-boot-1/README.md | 6 + spring-boot-modules/spring-boot-1/mvnw | 234 ++++++++++++++++++ spring-boot-modules/spring-boot-1/mvnw.cmd | 143 +++++++++++ spring-boot-modules/spring-boot-1/pom.xml | 45 ++++ .../com/baeldung/actuator/CustomEndpoint.java | 35 +++ .../com/baeldung/actuator/HealthCheck.java | 23 ++ .../baeldung/actuator/LoginServiceImpl.java | 28 +++ .../com/baeldung/actuator/SpringBoot.java | 13 + .../src/main/resources/application.properties | 19 ++ .../CustomEndpointIntegrationTest.java | 46 ++++ .../actuator/HealthCheckIntegrationTest.java | 49 ++++ .../actuator/HealthCheckUnitTest.java | 35 +++ .../actuator/LoginServiceIntegrationTest.java | 61 +++++ .../actuator/LoginServiceUnitTest.java | 41 +++ 16 files changed, 780 insertions(+) create mode 100644 spring-boot-modules/spring-boot-1/.mvn/wrapper/maven-wrapper.properties create mode 100644 spring-boot-modules/spring-boot-1/README.md create mode 100755 spring-boot-modules/spring-boot-1/mvnw create mode 100644 spring-boot-modules/spring-boot-1/mvnw.cmd create mode 100644 spring-boot-modules/spring-boot-1/pom.xml create mode 100644 spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/CustomEndpoint.java create mode 100644 spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/HealthCheck.java create mode 100644 spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/LoginServiceImpl.java create mode 100644 spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/SpringBoot.java create mode 100644 spring-boot-modules/spring-boot-1/src/main/resources/application.properties create mode 100644 spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/CustomEndpointIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckUnitTest.java create mode 100644 spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceUnitTest.java diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 6caa93158a..7992c0ce12 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -15,6 +15,7 @@ spring-boot + spring-boot-1 spring-boot-admin spring-boot-angular spring-boot-annotations diff --git a/spring-boot-modules/spring-boot-1/.mvn/wrapper/maven-wrapper.properties b/spring-boot-modules/spring-boot-1/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..9dda3b659b --- /dev/null +++ b/spring-boot-modules/spring-boot-1/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip diff --git a/spring-boot-modules/spring-boot-1/README.md b/spring-boot-modules/spring-boot-1/README.md new file mode 100644 index 0000000000..a818f60fb5 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/README.md @@ -0,0 +1,6 @@ +## Spring Boot 1.x Actuator + +This module contains articles about Spring Boot Actuator in Spring Boot version 1.x. + +## Relevant articles: +- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators) diff --git a/spring-boot-modules/spring-boot-1/mvnw b/spring-boot-modules/spring-boot-1/mvnw new file mode 100755 index 0000000000..b74391fdf4 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/mvnw @@ -0,0 +1,234 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ]; then + + if [ -f /etc/mavenrc ]; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ]; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false +darwin=false +mingw=false +case "$(uname)" in +CYGWIN*) cygwin=true ;; +MINGW*) mingw=true ;; +Darwin*) + darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="$(/usr/libexec/java_home)" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ]; then + if [ -r /etc/gentoo-release ]; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +if [ -z "$M2_HOME" ]; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ]; do + ls=$(ls -ld "$PRG") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' >/dev/null; then + PRG="$link" + else + PRG="$(dirname "$PRG")/$link" + fi + done + + saveddir=$(pwd) + + M2_HOME=$(dirname "$PRG")/.. + + # make it fully qualified + M2_HOME=$(cd "$M2_HOME" && pwd) + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=$(cygpath --unix "$M2_HOME") + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw; then + [ -n "$M2_HOME" ] && + M2_HOME="$( ( + cd "$M2_HOME" + pwd + ))" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="$( ( + cd "$JAVA_HOME" + pwd + ))" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then + if $darwin; then + javaHome="$(dirname \"$javaExecutable\")" + javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac" + else + javaExecutable="$(readlink -f \"$javaExecutable\")" + fi + javaHome="$(dirname \"$javaExecutable\")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ]; then + if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(which java)" + fi +fi + +if [ ! -x "$JAVACMD" ]; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ]; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ]; then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ]; do + if [ -d "$wdir"/.mvn ]; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$( + cd "$wdir/.." + pwd + ) + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' <"$1")" + fi +} + +BASE_DIR=$(find_maven_basedir "$(pwd)") +if [ -z "$BASE_DIR" ]; then + exit 1 +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=$(cygpath --path --windows "$M2_HOME") + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/spring-boot-modules/spring-boot-1/mvnw.cmd b/spring-boot-modules/spring-boot-1/mvnw.cmd new file mode 100644 index 0000000000..019bd74d76 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/spring-boot-modules/spring-boot-1/pom.xml b/spring-boot-modules/spring-boot-1/pom.xml new file mode 100644 index 0000000000..145bb221e0 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + spring-boot-1 + jar + Module for Spring Boot version 1.x + + + com.baeldung + parent-boot-1 + 0.0.1-SNAPSHOT + ../../parent-boot-1 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/CustomEndpoint.java b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/CustomEndpoint.java new file mode 100644 index 0000000000..f48fc87640 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/CustomEndpoint.java @@ -0,0 +1,35 @@ +package com.baeldung.actuator; + +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class CustomEndpoint implements Endpoint> { + + @Override + public String getId() { + return "customEndpoint"; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean isSensitive() { + return true; + } + + @Override + public List invoke() { + // Custom logic to build the output + List messages = new ArrayList<>(); + messages.add("This is message 1"); + messages.add("This is message 2"); + return messages; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/HealthCheck.java b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/HealthCheck.java new file mode 100644 index 0000000000..45db408465 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/HealthCheck.java @@ -0,0 +1,23 @@ +package com.baeldung.actuator; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +@Component("myHealthCheck") +public class HealthCheck implements HealthIndicator { + + @Override + public Health health() { + int errorCode = check(); // perform some specific health check + if (errorCode != 0) { + return Health.down().withDetail("Error Code", errorCode).build(); + } + return Health.up().build(); + } + + public int check() { + // Our logic to check health + return 0; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/LoginServiceImpl.java b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/LoginServiceImpl.java new file mode 100644 index 0000000000..925ce69a39 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/LoginServiceImpl.java @@ -0,0 +1,28 @@ +package com.baeldung.actuator; + +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +@Service +public class LoginServiceImpl { + + private final CounterService counterService; + + public LoginServiceImpl(CounterService counterService) { + this.counterService = counterService; + } + + public boolean login(String userName, char[] password) { + boolean success; + if (userName.equals("admin") && Arrays.equals("secret".toCharArray(), password)) { + counterService.increment("counter.login.success"); + success = true; + } else { + counterService.increment("counter.login.failure"); + success = false; + } + return success; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/SpringBoot.java b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/SpringBoot.java new file mode 100644 index 0000000000..bdf28e49cb --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/main/java/com/baeldung/actuator/SpringBoot.java @@ -0,0 +1,13 @@ +package com.baeldung.actuator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBoot { + + public static void main(String[] args) { + SpringApplication.run(SpringBoot.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-1/src/main/resources/application.properties b/spring-boot-modules/spring-boot-1/src/main/resources/application.properties new file mode 100644 index 0000000000..ac095e1cab --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/main/resources/application.properties @@ -0,0 +1,19 @@ +### server port +server.port=8080 +#port used to expose actuator +management.port=8081 +#CIDR allowed to hit actuator +management.address=127.0.0.1 +# Actuator Configuration +# customize /beans endpoint +endpoints.beans.id=springbeans +endpoints.beans.sensitive=false +endpoints.beans.enabled=true +# for the Spring Boot version 1.5.0 and above, we have to disable security to expose the health endpoint fully for unauthorized access. +# see: https://docs.spring.io/spring-boot/docs/1.5.x/reference/html/production-ready-monitoring.html +management.security.enabled=false +endpoints.health.sensitive=false +# customize /info endpoint +info.app.name=Spring Sample Application +info.app.description=This is my first spring boot application +info.app.version=1.0.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/CustomEndpointIntegrationTest.java b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/CustomEndpointIntegrationTest.java new file mode 100644 index 0000000000..663e6055c7 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/CustomEndpointIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.actuator; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.LocalManagementPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "management.port=0") +public class CustomEndpointIntegrationTest { + + @LocalManagementPort + private int port; + + private RestTemplate restTemplate = new RestTemplate(); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void whenSpringContextIsBootstrapped_thenActuatorCustomEndpointWorks() throws IOException { + ResponseEntity entity = restTemplate.getForEntity("http://localhost:" + port + "/customEndpoint", String.class); + + assertThat(entity.getStatusCode(), is(HttpStatus.OK)); + + List response = objectMapper.readValue(entity.getBody(), new TypeReference>() { + }); + + assertThat(response, hasItems("This is message 1", "This is message 2")); + } +} diff --git a/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckIntegrationTest.java b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckIntegrationTest.java new file mode 100644 index 0000000000..f80e2745a0 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckIntegrationTest.java @@ -0,0 +1,49 @@ +package com.baeldung.actuator; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.LocalManagementPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsMapContaining.hasEntry; +import static org.hamcrest.collection.IsMapContaining.hasKey; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "management.port=0") +public class HealthCheckIntegrationTest { + + @LocalManagementPort + private int port; + + private RestTemplate restTemplate = new RestTemplate(); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void whenSpringContextIsBootstrapped_thenActuatorHealthEndpointWorks() throws IOException { + ResponseEntity entity = restTemplate.getForEntity("http://localhost:" + port + "/health", String.class); + + assertThat(entity.getStatusCode(), is(HttpStatus.OK)); + + Map response = objectMapper.readValue(entity.getBody(), new TypeReference>() { + }); + + assertThat(response, hasEntry("status", "UP")); + assertThat(response, hasKey("myHealthCheck")); + assertThat(response, hasKey("diskSpace")); + } +} diff --git a/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckUnitTest.java b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckUnitTest.java new file mode 100644 index 0000000000..a464e51b1f --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/HealthCheckUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.actuator; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class HealthCheckUnitTest { + + @Test + public void whenCheckMethodReturnsZero_thenHealthMethodReturnsStatusUP() { + HealthCheck healthCheck = Mockito.spy(new HealthCheck()); + when(healthCheck.check()).thenReturn(0); + Health health = healthCheck.health(); + + assertThat(health.getStatus(), is(Status.UP)); + } + + @Test + public void whenCheckMethodReturnsOtherThanZero_thenHealthMethodReturnsStatusDOWN() { + HealthCheck healthCheck = Mockito.spy(new HealthCheck()); + when(healthCheck.check()).thenReturn(-1); + Health health = healthCheck.health(); + + assertThat(health.getStatus(), is(Status.DOWN)); + } + +} diff --git a/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceIntegrationTest.java b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceIntegrationTest.java new file mode 100644 index 0000000000..851de81d7f --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceIntegrationTest.java @@ -0,0 +1,61 @@ +package com.baeldung.actuator; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.LocalManagementPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasEntry; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "management.port=0") +public class LoginServiceIntegrationTest { + + @LocalManagementPort + private int port; + + @Autowired + private LoginServiceImpl loginService; + + private RestTemplate restTemplate = new RestTemplate(); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void whenLoginIsAdmin_thenSuccessCounterIsIncremented() throws IOException { + boolean success = loginService.login("admin", "secret".toCharArray()); + ResponseEntity entity = restTemplate.getForEntity("http://localhost:" + port + "/metrics", String.class); + Map response = objectMapper.readValue(entity.getBody(), new TypeReference>() { + }); + + assertThat(success, is(true)); + assertThat(entity.getStatusCode(), is(HttpStatus.OK)); + assertThat(response, hasEntry("counter.login.success", 1)); + } + + @Test + public void whenLoginIsNotAdmin_thenFailureCounterIsIncremented() throws IOException { + boolean success = loginService.login("user", "notsecret".toCharArray()); + ResponseEntity entity = restTemplate.getForEntity("http://localhost:" + port + "/metrics", String.class); + Map response = objectMapper.readValue(entity.getBody(), new TypeReference>() { + }); + + assertThat(success, is(false)); + assertThat(entity.getStatusCode(), is(HttpStatus.OK)); + assertThat(response, hasEntry("counter.login.failure", 1)); + } +} diff --git a/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceUnitTest.java b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceUnitTest.java new file mode 100644 index 0000000000..489d005782 --- /dev/null +++ b/spring-boot-modules/spring-boot-1/src/test/java/com/baeldung/actuator/LoginServiceUnitTest.java @@ -0,0 +1,41 @@ +package com.baeldung.actuator; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = LoginServiceImpl.class) +public class LoginServiceUnitTest { + + @MockBean + CounterService counterService; + + @Autowired + LoginServiceImpl loginService; + + @Test + public void whenLoginUserIsAdmin_thenSuccessCounterIsIncremented() { + boolean loginResult = loginService.login("admin", "secret".toCharArray()); + assertThat(loginResult, is(true)); + verify(counterService, times(1)).increment("counter.login.success"); + } + + @Test + public void whenLoginUserIsNotAdmin_thenFailureCounterIsIncremented() { + boolean loginResult = loginService.login("user", "notsecret".toCharArray()); + assertThat(loginResult, is(false)); + verify(counterService, times(1)).increment("counter.login.failure"); + } + +} From 6df3b2b6fb708428537f54d72baa9eba9543bcb8 Mon Sep 17 00:00:00 2001 From: Eduard Ardeleanu Date: Wed, 3 Jun 2020 16:04:45 +0300 Subject: [PATCH 062/118] BAEL-4026: Spring Cloud Open Service Broker (#9365) * BAEL-4026: Spring Cloud Open Service Broker * add unit tests * fix review comments --- spring-cloud/pom.xml | 1 + .../README.md | 1 + .../spring-cloud-open-service-broker/pom.xml | 41 ++++ .../ServiceBrokerApplication.java | 13 ++ .../config/CatalogConfiguration.java | 34 +++ .../mail/MailController.java | 19 ++ .../openservicebroker/mail/MailService.java | 95 +++++++++ .../mail/MailServiceBinding.java | 22 ++ .../mail/MailServiceInstance.java | 32 +++ .../MailServiceInstanceBindingService.java | 77 +++++++ .../services/MailServiceInstanceService.java | 72 +++++++ .../src/main/resources/application.yml | 10 + ...ServiceInstanceBindingServiceUnitTest.java | 201 ++++++++++++++++++ .../MailServiceInstanceServiceUnitTest.java | 166 +++++++++++++++ 14 files changed, 784 insertions(+) create mode 100644 spring-cloud/spring-cloud-open-service-broker/README.md create mode 100644 spring-cloud/spring-cloud-open-service-broker/pom.xml create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java create mode 100644 spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index c4e606e190..3de527c33b 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -32,6 +32,7 @@ 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 diff --git a/spring-cloud/spring-cloud-open-service-broker/README.md b/spring-cloud/spring-cloud-open-service-broker/README.md new file mode 100644 index 0000000000..f09469076b --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/README.md @@ -0,0 +1 @@ +### Relevant Articles: diff --git a/spring-cloud/spring-cloud-open-service-broker/pom.xml b/spring-cloud/spring-cloud-open-service-broker/pom.xml new file mode 100644 index 0000000000..7acd302dc1 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + com.baeldung + spring-cloud-open-service-broker + jar + + + com.baeldung.spring.cloud + spring-cloud + 1.0.0-SNAPSHOT + + + + 3.1.1.RELEASE + 2.2.7.RELEASE + 3.3.5.RELEASE + + + + + org.springframework.cloud + spring-cloud-starter-open-service-broker + ${spring-cloud-starter-open-service-broker.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot-starter-web.version} + + + io.projectreactor + reactor-test + ${reactor-test.version} + test + + + + diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java new file mode 100644 index 0000000000..2dbb4bc546 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.cloud.openservicebroker; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ServiceBrokerApplication { + + public static void main(String[] args) { + SpringApplication.run(ServiceBrokerApplication.class, args); + } + +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java new file mode 100644 index 0000000000..e9e9452785 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.cloud.openservicebroker.config; + +import org.springframework.cloud.servicebroker.model.catalog.Catalog; +import org.springframework.cloud.servicebroker.model.catalog.Plan; +import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CatalogConfiguration { + + @Bean + public Catalog catalog() { + Plan mailFreePlan = Plan.builder() + .id("fd81196c-a414-43e5-bd81-1dbb082a3c55") + .name("mail-free-plan") + .description("Mail Service Free Plan") + .free(true) + .build(); + + ServiceDefinition serviceDefinition = ServiceDefinition.builder() + .id("b92c0ca7-c162-4029-b567-0d92978c0a97") + .name("mail-service") + .description("Mail Service") + .bindable(true) + .tags("mail", "service") + .plans(mailFreePlan) + .build(); + + return Catalog.builder() + .serviceDefinitions(serviceDefinition) + .build(); + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java new file mode 100644 index 0000000000..e0c0b36428 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.cloud.openservicebroker.mail; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MailController { + + @GetMapping("/mail-dashboard/{mailSystemId}") + public String dashboard(@PathVariable("mailSystemId") String mailSystemId) { + return "Mail Dashboard - " + mailSystemId; + } + + @GetMapping("/mail-system/{mailSystemId}") + public String mailSystem(@PathVariable("mailSystemId") String mailSystemId) { + return "Mail System - " + mailSystemId; + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java new file mode 100644 index 0000000000..07b7ad9a38 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java @@ -0,0 +1,95 @@ +package com.baeldung.spring.cloud.openservicebroker.mail; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Service +public class MailService { + + public static final String URI_KEY = "uri"; + public static final String USERNAME_KEY = "username"; + public static final String PASSWORD_KEY = "password"; + + private final String mailDashboardBaseURL; + private final String mailSystemBaseURL; + + private Map mailServices = new HashMap<>(); + + private Map mailServiceBindings = new HashMap<>(); + + public MailService(@Value("${mail.system.dashboard.base-url}") String mailDashboardBaseURL, + @Value("${mail.system.base-url}") String mailSystemBaseURL) { + this.mailDashboardBaseURL = mailDashboardBaseURL; + this.mailSystemBaseURL = mailSystemBaseURL; + } + + public Mono createServiceInstance(String instanceId, String serviceDefinitionId, String planId) { + MailServiceInstance mailServiceInstance = new MailServiceInstance( + instanceId, serviceDefinitionId, planId, mailDashboardBaseURL + instanceId); + mailServices.put(instanceId, mailServiceInstance); + return Mono.just(mailServiceInstance); + } + + public Mono serviceInstanceExists(String instanceId) { + return Mono.just(mailServices.containsKey(instanceId)); + } + + public Mono getServiceInstance(String instanceId) { + if (mailServices.containsKey(instanceId)) { + return Mono.just(mailServices.get(instanceId)); + } + return Mono.empty(); + } + + public Mono deleteServiceInstance(String instanceId) { + mailServices.remove(instanceId); + mailServiceBindings.remove(instanceId); + return Mono.empty(); + } + + public Mono createServiceBinding(String instanceId, String bindingId) { + return this.serviceInstanceExists(instanceId) + .flatMap(exists -> { + if (exists) { + MailServiceBinding mailServiceBinding = + new MailServiceBinding(bindingId, buildCredentials(instanceId, bindingId)); + mailServiceBindings.put(instanceId, mailServiceBinding); + return Mono.just(mailServiceBinding); + } else { + return Mono.empty(); + } + }); + } + + public Mono serviceBindingExists(String instanceId, String bindingId) { + return Mono.just(mailServiceBindings.containsKey(instanceId) && + mailServiceBindings.get(instanceId).getBindingId().equalsIgnoreCase(bindingId)); + } + + public Mono getServiceBinding(String instanceId, String bindingId) { + if (mailServiceBindings.containsKey(instanceId) && + mailServiceBindings.get(instanceId).getBindingId().equalsIgnoreCase(bindingId)) { + return Mono.just(mailServiceBindings.get(instanceId)); + } + return Mono.empty(); + } + + public Mono deleteServiceBinding(String instanceId) { + mailServiceBindings.remove(instanceId); + return Mono.empty(); + } + + private Map buildCredentials(String instanceId, String bindingId) { + Map credentials = new HashMap<>(); + credentials.put(URI_KEY, mailSystemBaseURL + instanceId); + credentials.put(USERNAME_KEY, bindingId); + credentials.put(PASSWORD_KEY, UUID.randomUUID().toString()); + return credentials; + } + +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java new file mode 100644 index 0000000000..a72d4f7372 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java @@ -0,0 +1,22 @@ +package com.baeldung.spring.cloud.openservicebroker.mail; + +import java.util.Map; + +public class MailServiceBinding { + + private String bindingId; + private Map credentials; + + public MailServiceBinding(String bindingId, Map credentials) { + this.bindingId = bindingId; + this.credentials = credentials; + } + + public String getBindingId() { + return bindingId; + } + + public Map getCredentials() { + return credentials; + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java new file mode 100644 index 0000000000..d4dbbe5657 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.cloud.openservicebroker.mail; + +public class MailServiceInstance { + + private String instanceId; + private String serviceDefinitionId; + private String planId; + private String dashboardUrl; + + public MailServiceInstance(String instanceId, String serviceDefinitionId, String planId, String dashboardUrl) { + this.instanceId = instanceId; + this.serviceDefinitionId = serviceDefinitionId; + this.planId = planId; + this.dashboardUrl = dashboardUrl; + } + + public String getInstanceId() { + return instanceId; + } + + public String getServiceDefinitionId() { + return serviceDefinitionId; + } + + public String getPlanId() { + return planId; + } + + public String getDashboardUrl() { + return dashboardUrl; + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java new file mode 100644 index 0000000000..847b309f2c --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java @@ -0,0 +1,77 @@ +package com.baeldung.spring.cloud.openservicebroker.services; + +import com.baeldung.spring.cloud.openservicebroker.mail.MailService; +import org.springframework.cloud.servicebroker.exception.ServiceInstanceBindingDoesNotExistException; +import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException; +import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest; +import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest; +import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceAppBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingRequest; +import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingResponse; +import org.springframework.cloud.servicebroker.service.ServiceInstanceBindingService; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class MailServiceInstanceBindingService implements ServiceInstanceBindingService { + + private final MailService mailService; + + public MailServiceInstanceBindingService(MailService mailService) { + this.mailService = mailService; + } + + @Override + public Mono createServiceInstanceBinding( + CreateServiceInstanceBindingRequest request) { + return Mono.just(CreateServiceInstanceAppBindingResponse.builder()) + .flatMap(responseBuilder -> mailService.serviceBindingExists( + request.getServiceInstanceId(), request.getBindingId()) + .flatMap(exists -> { + if (exists) { + return mailService.getServiceBinding( + request.getServiceInstanceId(), request.getBindingId()) + .flatMap(serviceBinding -> Mono.just(responseBuilder + .bindingExisted(true) + .credentials(serviceBinding.getCredentials()) + .build())); + } else { + return mailService.createServiceBinding( + request.getServiceInstanceId(), request.getBindingId()) + .switchIfEmpty(Mono.error( + new ServiceInstanceDoesNotExistException( + request.getServiceInstanceId()))) + .flatMap(mailServiceBinding -> Mono.just(responseBuilder + .bindingExisted(false) + .credentials(mailServiceBinding.getCredentials()) + .build())); + } + })); + } + + @Override + public Mono getServiceInstanceBinding(GetServiceInstanceBindingRequest request) { + return mailService.getServiceBinding(request.getServiceInstanceId(), request.getBindingId()) + .switchIfEmpty(Mono.error(new ServiceInstanceBindingDoesNotExistException(request.getBindingId()))) + .flatMap(mailServiceBinding -> Mono.just(GetServiceInstanceAppBindingResponse.builder() + .credentials(mailServiceBinding.getCredentials()) + .build())); + } + + @Override + public Mono deleteServiceInstanceBinding( + DeleteServiceInstanceBindingRequest request) { + return mailService.serviceBindingExists(request.getServiceInstanceId(), request.getBindingId()) + .flatMap(exists -> { + if (exists) { + return mailService.deleteServiceBinding(request.getServiceInstanceId()) + .thenReturn(DeleteServiceInstanceBindingResponse.builder().build()); + } else { + return Mono.error(new ServiceInstanceBindingDoesNotExistException(request.getBindingId())); + } + }); + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java new file mode 100644 index 0000000000..8c757c3f25 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java @@ -0,0 +1,72 @@ +package com.baeldung.spring.cloud.openservicebroker.services; + +import com.baeldung.spring.cloud.openservicebroker.mail.MailService; +import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException; +import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest; +import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse; +import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest; +import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse; +import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest; +import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceResponse; +import org.springframework.cloud.servicebroker.service.ServiceInstanceService; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class MailServiceInstanceService implements ServiceInstanceService { + + private final MailService mailService; + + public MailServiceInstanceService(MailService mailService) { + this.mailService = mailService; + } + + @Override + public Mono createServiceInstance(CreateServiceInstanceRequest request) { + return Mono.just(request.getServiceInstanceId()) + .flatMap(instanceId -> Mono.just(CreateServiceInstanceResponse.builder()) + .flatMap(responseBuilder -> mailService.serviceInstanceExists(instanceId) + .flatMap(exists -> { + if (exists) { + return mailService.getServiceInstance(instanceId) + .flatMap(mailServiceInstance -> Mono.just(responseBuilder + .instanceExisted(true) + .dashboardUrl(mailServiceInstance.getDashboardUrl()) + .build())); + } else { + return mailService.createServiceInstance( + instanceId, request.getServiceDefinitionId(), request.getPlanId()) + .flatMap(mailServiceInstance -> Mono.just(responseBuilder + .instanceExisted(false) + .dashboardUrl(mailServiceInstance.getDashboardUrl()) + .build())); + } + }))); + } + + @Override + public Mono deleteServiceInstance(DeleteServiceInstanceRequest request) { + return Mono.just(request.getServiceInstanceId()) + .flatMap(instanceId -> mailService.serviceInstanceExists(instanceId) + .flatMap(exists -> { + if (exists) { + return mailService.deleteServiceInstance(instanceId) + .thenReturn(DeleteServiceInstanceResponse.builder().build()); + } else { + return Mono.error(new ServiceInstanceDoesNotExistException(instanceId)); + } + })); + } + + @Override + public Mono getServiceInstance(GetServiceInstanceRequest request) { + return Mono.just(request.getServiceInstanceId()) + .flatMap(instanceId -> mailService.getServiceInstance(instanceId) + .switchIfEmpty(Mono.error(new ServiceInstanceDoesNotExistException(instanceId))) + .flatMap(serviceInstance -> Mono.just(GetServiceInstanceResponse.builder() + .serviceDefinitionId(serviceInstance.getServiceDefinitionId()) + .planId(serviceInstance.getPlanId()) + .dashboardUrl(serviceInstance.getDashboardUrl()) + .build()))); + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml b/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml new file mode 100644 index 0000000000..d863b513b0 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + cloud: + openservicebroker: + base-path: /broker + +mail: + system: + base-url: http://localhost:8080/mail-system/ + dashboard: + base-url: http://localhost:8080/mail-dashboard/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java new file mode 100644 index 0000000000..5b50d44600 --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java @@ -0,0 +1,201 @@ +package com.baeldung.spring.cloud.openservicebroker.services; + +import com.baeldung.spring.cloud.openservicebroker.mail.MailService; +import com.baeldung.spring.cloud.openservicebroker.mail.MailServiceBinding; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.cloud.servicebroker.exception.ServiceInstanceBindingDoesNotExistException; +import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest; +import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest; +import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceAppBindingResponse; +import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingRequest; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.HashMap; +import java.util.Map; + +import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.PASSWORD_KEY; +import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.URI_KEY; +import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.USERNAME_KEY; +import static java.util.UUID.randomUUID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +public class MailServiceInstanceBindingServiceUnitTest { + + private static final String MAIL_SERVICE_INSTANCE_ID = "test@baeldung.com"; + private static final String MAIL_SERVICE_BINDING_ID = "test"; + private static final String MAIL_SYSTEM_URL = "http://localhost:8080/mail-system/test@baeldung.com"; + + @Mock + private MailService mailService; + + private MailServiceInstanceBindingService mailServiceInstanceBindingService; + + @BeforeEach + public void setUp() { + initMocks(this); + + this.mailServiceInstanceBindingService = new MailServiceInstanceBindingService(mailService); + } + + @Test + public void givenServiceBindingDoesNotExist_whenCreateServiceBinding_thenNewBindingIsCreated() { + // given service binding does not exist + when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(false)); + + Map credentials = generateCredentials(); + MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials); + when(mailService.createServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)) + .thenReturn(Mono.just(serviceBinding)); + + // when create service binding + CreateServiceInstanceBindingRequest request = CreateServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then a new service binding is provisioned + StepVerifier.create(mailServiceInstanceBindingService.createServiceInstanceBinding(request)) + .consumeNextWith(response -> { + assertTrue(response instanceof CreateServiceInstanceAppBindingResponse); + CreateServiceInstanceAppBindingResponse bindingResponse = (CreateServiceInstanceAppBindingResponse) response; + assertFalse(bindingResponse.isBindingExisted()); + validateBindingCredentials(bindingResponse.getCredentials()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceBindingExists_whenCreateServiceBinding_thenExistingBindingIsRetrieved() { + // given service binding exists + when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(true)); + + Map credentials = generateCredentials(); + MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials); + when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)) + .thenReturn(Mono.just(serviceBinding)); + + // when create service binding + CreateServiceInstanceBindingRequest request = CreateServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then a new service binding is provisioned + StepVerifier.create(mailServiceInstanceBindingService.createServiceInstanceBinding(request)) + .consumeNextWith(response -> { + assertTrue(response instanceof CreateServiceInstanceAppBindingResponse); + CreateServiceInstanceAppBindingResponse bindingResponse = (CreateServiceInstanceAppBindingResponse) response; + assertTrue(bindingResponse.isBindingExisted()); + validateBindingCredentials(bindingResponse.getCredentials()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceBindingDoesNotExist_whenGetServiceBinding_thenException() { + // given service binding does not exist + when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.empty()); + + // when get service binding + GetServiceInstanceBindingRequest request = GetServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then ServiceInstanceBindingDoesNotExistException is thrown + StepVerifier.create(mailServiceInstanceBindingService.getServiceInstanceBinding(request)) + .expectErrorMatches(ex -> ex instanceof ServiceInstanceBindingDoesNotExistException) + .verify(); + } + + @Test + public void givenServiceBindingExists_whenGetServiceBinding_thenExistingBindingIsRetrieved() { + // given service binding exists + Map credentials = generateCredentials(); + MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials); + when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)) + .thenReturn(Mono.just(serviceBinding)); + + // when get service binding + GetServiceInstanceBindingRequest request = GetServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then the existing service binding is retrieved + StepVerifier.create(mailServiceInstanceBindingService.getServiceInstanceBinding(request)) + .consumeNextWith(response -> { + assertTrue(response instanceof GetServiceInstanceAppBindingResponse); + GetServiceInstanceAppBindingResponse bindingResponse = (GetServiceInstanceAppBindingResponse) response; + validateBindingCredentials(bindingResponse.getCredentials()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceBindingDoesNotExist_whenDeleteServiceBinding_thenException() { + // given service binding does not exist + when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(false)); + + // when delete service binding + DeleteServiceInstanceBindingRequest request = DeleteServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then ServiceInstanceBindingDoesNotExistException is thrown + StepVerifier.create(mailServiceInstanceBindingService.deleteServiceInstanceBinding(request)) + .expectErrorMatches(ex -> ex instanceof ServiceInstanceBindingDoesNotExistException) + .verify(); + } + + @Test + public void givenServiceBindingExists_whenDeleteServiceBinding_thenExistingBindingIsDeleted() { + // given service binding exists + when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(true)); + when(mailService.deleteServiceBinding(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty()); + + // when delete service binding + DeleteServiceInstanceBindingRequest request = DeleteServiceInstanceBindingRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .bindingId(MAIL_SERVICE_BINDING_ID) + .build(); + + // then the existing service binding is retrieved + StepVerifier.create(mailServiceInstanceBindingService.deleteServiceInstanceBinding(request)) + .consumeNextWith(response -> { + assertFalse(response.isAsync()); + assertNull(response.getOperation()); + }) + .verifyComplete(); + } + + private void validateBindingCredentials(Map bindingCredentials) { + assertNotNull(bindingCredentials); + assertEquals(3, bindingCredentials.size()); + assertTrue(bindingCredentials.containsKey(URI_KEY)); + assertTrue(bindingCredentials.containsKey(USERNAME_KEY)); + assertTrue(bindingCredentials.containsKey(PASSWORD_KEY)); + assertEquals(MAIL_SYSTEM_URL, bindingCredentials.get(URI_KEY)); + assertEquals(MAIL_SERVICE_BINDING_ID, bindingCredentials.get(USERNAME_KEY)); + assertNotNull(bindingCredentials.get(PASSWORD_KEY)); + } + + private Map generateCredentials() { + Map credentials = new HashMap<>(); + credentials.put(URI_KEY, MAIL_SYSTEM_URL); + credentials.put(USERNAME_KEY, MAIL_SERVICE_BINDING_ID); + credentials.put(PASSWORD_KEY, randomUUID().toString()); + return credentials; + } +} diff --git a/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java new file mode 100644 index 0000000000..1302cad42e --- /dev/null +++ b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java @@ -0,0 +1,166 @@ +package com.baeldung.spring.cloud.openservicebroker.services; + +import com.baeldung.spring.cloud.openservicebroker.mail.MailService; +import com.baeldung.spring.cloud.openservicebroker.mail.MailServiceInstance; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException; +import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest; +import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest; +import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +public class MailServiceInstanceServiceUnitTest { + + private static final String MAIL_SERVICE_INSTANCE_ID = "test@baeldung.com"; + private static final String MAIL_SERVICE_DEFINITION_ID = "mock-service-definition-id"; + private static final String MAIL_SERVICE_PLAN_ID = "mock-service-plan-id"; + private static final String MAIL_DASHBOARD_URL = "http://localhost:8080/mail-dashboard/test@baeldung.com"; + + @Mock + private MailService mailService; + + private MailServiceInstanceService mailServiceInstanceService; + + @BeforeEach + public void setUp() { + initMocks(this); + + this.mailServiceInstanceService = new MailServiceInstanceService(mailService); + } + + @Test + public void givenServiceInstanceDoesNotExist_whenCreateServiceInstance_thenProvisionNewService() { + // given service instance does not exist + when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(false)); + + MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID, + MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL); + when(mailService.createServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID, MAIL_SERVICE_PLAN_ID)) + .thenReturn(Mono.just(serviceInstance)); + + // when create service instance + CreateServiceInstanceRequest request = CreateServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .serviceDefinitionId(MAIL_SERVICE_DEFINITION_ID) + .planId(MAIL_SERVICE_PLAN_ID) + .build(); + + // then a new service instance is provisioned + StepVerifier.create(mailServiceInstanceService.createServiceInstance(request)) + .consumeNextWith(response -> { + assertFalse(response.isInstanceExisted()); + assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceInstanceExists_whenCreateServiceInstance_thenExistingServiceInstanceIsRetrieved() { + // given service instance exists + when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(true)); + + MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID, + MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL); + when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(serviceInstance)); + + // when create service instance + CreateServiceInstanceRequest request = CreateServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .serviceDefinitionId(MAIL_SERVICE_DEFINITION_ID) + .planId(MAIL_SERVICE_PLAN_ID) + .build(); + + // then the existing one is retrieved + StepVerifier.create(mailServiceInstanceService.createServiceInstance(request)) + .consumeNextWith(response -> { + assertTrue(response.isInstanceExisted()); + assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceInstanceDoesNotExist_whenDeleteServiceInstance_thenException() { + // given service instance does not exist + when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(false)); + + // when delete service instance + DeleteServiceInstanceRequest request = DeleteServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .build(); + + // then ServiceInstanceDoesNotExistException is thrown + StepVerifier.create(mailServiceInstanceService.deleteServiceInstance(request)) + .expectErrorMatches(ex -> ex instanceof ServiceInstanceDoesNotExistException) + .verify(); + } + + @Test + public void givenServiceInstanceExists_whenDeleteServiceInstance_thenSuccess() { + // given service instance exists + when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(true)); + + // when delete service instance + when(mailService.deleteServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty()); + + DeleteServiceInstanceRequest request = DeleteServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .build(); + + // then success + StepVerifier.create(mailServiceInstanceService.deleteServiceInstance(request)) + .consumeNextWith(response -> { + assertFalse(response.isAsync()); + assertNull(response.getOperation()); + }) + .verifyComplete(); + } + + @Test + public void givenServiceInstanceDoesNotExist_whenGetServiceInstance_thenException() { + // given service instance does not exist + when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty()); + + // when get service instance + GetServiceInstanceRequest request = GetServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .build(); + + // then ServiceInstanceDoesNotExistException is thrown + StepVerifier.create(mailServiceInstanceService.getServiceInstance(request)) + .expectErrorMatches(ex -> ex instanceof ServiceInstanceDoesNotExistException) + .verify(); + } + + @Test + public void givenServiceInstanceExists_whenGetServiceInstance_thenExistingServiceInstanceIsRetrieved() { + // given service instance exists + MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID, + MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL); + when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(serviceInstance)); + + // when get service instance + GetServiceInstanceRequest request = GetServiceInstanceRequest.builder() + .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID) + .build(); + + // then the existing service instance is retrieved + StepVerifier.create(mailServiceInstanceService.getServiceInstance(request)) + .consumeNextWith(response -> { + assertEquals(MAIL_SERVICE_DEFINITION_ID, response.getServiceDefinitionId()); + assertEquals(MAIL_SERVICE_PLAN_ID, response.getPlanId()); + assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl()); + }) + .verifyComplete(); + } +} From 0d2076f299bf28c919e5640e15c8359d3d134e75 Mon Sep 17 00:00:00 2001 From: Roque Santos Date: Wed, 3 Jun 2020 19:51:49 -0300 Subject: [PATCH 063/118] BAEL-3844 - Suggested adjustements --- ...estFactoryLiveTest.java => RequestFactoryUnitTest.java} | 7 +++++-- ...erLiveTest.java => RestTemplateCustomizerUnitTest.java} | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) rename spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/{RequestFactoryLiveTest.java => RequestFactoryUnitTest.java} (85%) rename spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/{RestTemplateCustomizerLiveTest.java => RestTemplateCustomizerUnitTest.java} (89%) diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java similarity index 85% rename from spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java rename to spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java index f9ca66f14d..6959aa8d47 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java @@ -15,13 +15,16 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -public class RequestFactoryLiveTest { +public class RequestFactoryUnitTest { + + private static final String PROXY_SERVER_HOST = "127.0.0.1"; + private static final int PROXY_SERVER_PORT = 8080; RestTemplate restTemplate; @Before public void setUp() { - Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("201.91.82.155", 3128)); + Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(PROXY_SERVER_HOST, PROXY_SERVER_PORT)); SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setProxy(proxy); diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java similarity index 89% rename from spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java rename to spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java index 8f318b758b..b35283bdcf 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java @@ -20,7 +20,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -public class RestTemplateCustomizerLiveTest { +public class RestTemplateCustomizerUnitTest { + + private static final String PROXY_SERVER_HOST = "127.0.0.1"; + private static final int PROXY_SERVER_PORT = 8080; RestTemplate restTemplate; @@ -40,7 +43,7 @@ public class RestTemplateCustomizerLiveTest { @Override public void customize(RestTemplate restTemplate) { - HttpHost proxy = new HttpHost("201.91.82.155", 3128); + HttpHost proxy = new HttpHost(PROXY_SERVER_HOST, PROXY_SERVER_PORT); HttpClient httpClient = HttpClientBuilder.create() .setRoutePlanner(new DefaultProxyRoutePlanner(proxy) { @Override From 6e9f4d80a5ab19fd6572c4dda3ce78675fd9110e Mon Sep 17 00:00:00 2001 From: Roque Santos Date: Wed, 3 Jun 2020 19:58:40 -0300 Subject: [PATCH 064/118] BAEL-3844 : Back to LiveTest to bypass te CI build since the proxy address is dynamic --- ...{RequestFactoryUnitTest.java => RequestFactoryLiveTest.java} | 2 +- ...tomizerUnitTest.java => RestTemplateCustomizerLiveTest.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/{RequestFactoryUnitTest.java => RequestFactoryLiveTest.java} (97%) rename spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/{RestTemplateCustomizerUnitTest.java => RestTemplateCustomizerLiveTest.java} (98%) diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java similarity index 97% rename from spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java rename to spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java index 6959aa8d47..8c13bef05f 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryUnitTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java @@ -15,7 +15,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -public class RequestFactoryUnitTest { +public class RequestFactoryLiveTest { private static final String PROXY_SERVER_HOST = "127.0.0.1"; private static final int PROXY_SERVER_PORT = 8080; diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java similarity index 98% rename from spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java rename to spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java index b35283bdcf..547428ec9f 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerUnitTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java @@ -20,7 +20,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -public class RestTemplateCustomizerUnitTest { +public class RestTemplateCustomizerLiveTest { private static final String PROXY_SERVER_HOST = "127.0.0.1"; private static final int PROXY_SERVER_PORT = 8080; From ee146f5a136ec1b3e0e4a469d671bfcd7faf5f7e Mon Sep 17 00:00:00 2001 From: Sampada <46674082+sampada07@users.noreply.github.com> Date: Thu, 4 Jun 2020 08:18:57 +0530 Subject: [PATCH 065/118] BAEL-4061: Implementing a Simple HTTP Server with Netty (#9416) * BAEL-4061: Implementing a Simple HTTP Server with Netty * BAEL-4061: Added live test * BAEL-4061: moved helper class from test to main folder * BAEL-4061: updated tests to follow BDD --- .../http/server/CustomHttpServerHandler.java | 116 +++++++++++ .../com/baeldung/http/server/HttpServer.java | 64 +++++++ .../baeldung/http/server/ResponseBuilder.java | 120 ++++++++++++ .../http/server/HttpServerLiveTest.java | 180 ++++++++++++++++++ .../http/server/ResponseAggregator.java | 52 +++++ 5 files changed, 532 insertions(+) create mode 100644 netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java create mode 100644 netty/src/main/java/com/baeldung/http/server/HttpServer.java create mode 100644 netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java create mode 100644 netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java create mode 100644 netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java diff --git a/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java b/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java new file mode 100644 index 0000000000..038f559329 --- /dev/null +++ b/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java @@ -0,0 +1,116 @@ +package com.baeldung.http.server; + +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; +import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; + +import java.util.Set; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpObject; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpUtil; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.cookie.Cookie; +import io.netty.handler.codec.http.cookie.ServerCookieDecoder; +import io.netty.handler.codec.http.cookie.ServerCookieEncoder; +import io.netty.util.CharsetUtil; + +public class CustomHttpServerHandler extends SimpleChannelInboundHandler { + + private HttpRequest request; + StringBuilder responseData = new StringBuilder(); + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof HttpRequest) { + HttpRequest request = this.request = (HttpRequest) msg; + + if (HttpUtil.is100ContinueExpected(request)) { + writeResponse(ctx); + } + + responseData.setLength(0); + responseData.append(ResponseBuilder.addRequestAttributes(request)); + responseData.append(ResponseBuilder.addHeaders(request)); + responseData.append(ResponseBuilder.addParams(request)); + } + + responseData.append(ResponseBuilder.addDecoderResult(request)); + + if (msg instanceof HttpContent) { + HttpContent httpContent = (HttpContent) msg; + + responseData.append(ResponseBuilder.addBody(httpContent)); + responseData.append(ResponseBuilder.addDecoderResult(request)); + + if (msg instanceof LastHttpContent) { + LastHttpContent trailer = (LastHttpContent) msg; + responseData.append(ResponseBuilder.addLastResponse(request, trailer)); + writeResponse(ctx, trailer, responseData); + } + } + } + + private void writeResponse(ChannelHandlerContext ctx) { + FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER); + ctx.write(response); + } + + private void writeResponse(ChannelHandlerContext ctx, LastHttpContent trailer, StringBuilder responseData) { + boolean keepAlive = HttpUtil.isKeepAlive(request); + + FullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, ((HttpObject) trailer).decoderResult() + .isSuccess() ? OK : BAD_REQUEST, Unpooled.copiedBuffer(responseData.toString(), CharsetUtil.UTF_8)); + + httpResponse.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); + + if (keepAlive) { + httpResponse.headers() + .setInt(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content() + .readableBytes()); + httpResponse.headers() + .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + } + + String cookieString = request.headers() + .get(HttpHeaderNames.COOKIE); + if (cookieString != null) { + Set cookies = ServerCookieDecoder.STRICT.decode(cookieString); + if (!cookies.isEmpty()) { + for (Cookie cookie : cookies) { + httpResponse.headers() + .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie)); + } + } + } + + ctx.write(httpResponse); + + if (!keepAlive) { + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) + .addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} diff --git a/netty/src/main/java/com/baeldung/http/server/HttpServer.java b/netty/src/main/java/com/baeldung/http/server/HttpServer.java new file mode 100644 index 0000000000..529d14f0fd --- /dev/null +++ b/netty/src/main/java/com/baeldung/http/server/HttpServer.java @@ -0,0 +1,64 @@ +package com.baeldung.http.server; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; + +public class HttpServer { + + private int port; + static Logger logger = LoggerFactory.getLogger(HttpServer.class); + + public HttpServer(int port) { + this.port = port; + } + + public static void main(String[] args) throws Exception { + + int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080; + + new HttpServer(port).run(); + } + + public void run() throws Exception { + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline p = ch.pipeline(); + p.addLast(new HttpRequestDecoder()); + p.addLast(new HttpResponseEncoder()); + p.addLast(new CustomHttpServerHandler()); + } + }); + + ChannelFuture f = b.bind(port) + .sync(); + f.channel() + .closeFuture() + .sync(); + + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } +} diff --git a/netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java b/netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java new file mode 100644 index 0000000000..6d4e7845da --- /dev/null +++ b/netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java @@ -0,0 +1,120 @@ +package com.baeldung.http.server; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.DecoderResult; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpObject; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.util.CharsetUtil; + +class ResponseBuilder { + + static StringBuilder addRequestAttributes(HttpRequest request) { + StringBuilder responseData = new StringBuilder(); + responseData.append("Version: ") + .append(request.protocolVersion()) + .append("\r\n"); + responseData.append("Host: ") + .append(request.headers() + .get(HttpHeaderNames.HOST, "unknown")) + .append("\r\n"); + responseData.append("URI: ") + .append(request.uri()) + .append("\r\n\r\n"); + return responseData; + } + + static StringBuilder addParams(HttpRequest request) { + StringBuilder responseData = new StringBuilder(); + QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri()); + Map> params = queryStringDecoder.parameters(); + if (!params.isEmpty()) { + for (Entry> p : params.entrySet()) { + String key = p.getKey(); + List vals = p.getValue(); + for (String val : vals) { + responseData.append("Parameter: ") + .append(key) + .append(" = ") + .append(val) + .append("\r\n"); + } + } + responseData.append("\r\n"); + } + return responseData; + } + + static StringBuilder addHeaders(HttpRequest request) { + StringBuilder responseData = new StringBuilder(); + HttpHeaders headers = request.headers(); + if (!headers.isEmpty()) { + for (Map.Entry header : headers) { + CharSequence key = header.getKey(); + CharSequence value = header.getValue(); + responseData.append(key) + .append(" = ") + .append(value) + .append("\r\n"); + } + responseData.append("\r\n"); + } + return responseData; + } + + static StringBuilder addBody(HttpContent httpContent) { + StringBuilder responseData = new StringBuilder(); + ByteBuf content = httpContent.content(); + if (content.isReadable()) { + responseData.append(content.toString(CharsetUtil.UTF_8) + .toUpperCase()); + responseData.append("\r\n"); + } + return responseData; + } + + static StringBuilder addDecoderResult(HttpObject o) { + StringBuilder responseData = new StringBuilder(); + DecoderResult result = o.decoderResult(); + + if (!result.isSuccess()) { + responseData.append("..Decoder Failure: "); + responseData.append(result.cause()); + responseData.append("\r\n"); + } + + return responseData; + } + + static StringBuilder addLastResponse(HttpRequest request, LastHttpContent trailer) { + StringBuilder responseData = new StringBuilder(); + responseData.append("Good Bye!\r\n"); + + if (!trailer.trailingHeaders() + .isEmpty()) { + responseData.append("\r\n"); + for (CharSequence name : trailer.trailingHeaders() + .names()) { + for (CharSequence value : trailer.trailingHeaders() + .getAll(name)) { + responseData.append("P.S. Trailing Header: "); + responseData.append(name) + .append(" = ") + .append(value) + .append("\r\n"); + } + } + responseData.append("\r\n"); + } + return responseData; + } + +} diff --git a/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java b/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java new file mode 100644 index 0000000000..7a0f884724 --- /dev/null +++ b/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java @@ -0,0 +1,180 @@ +package com.baeldung.http.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpContentDecompressor; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpObject; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpUtil; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.cookie.ClientCookieEncoder; +import io.netty.handler.codec.http.cookie.DefaultCookie; +import io.netty.util.CharsetUtil; + +//Ensure the server class - HttpServer.java is already started before running this test +public class HttpServerLiveTest { + + private static final String HOST = "127.0.0.1"; + private static final int PORT = 8080; + private Channel channel; + private EventLoopGroup group = new NioEventLoopGroup(); + ResponseAggregator response = new ResponseAggregator(); + + @Before + public void setup() throws Exception { + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline p = ch.pipeline(); + p.addLast(new HttpClientCodec()); + p.addLast(new HttpContentDecompressor()); + p.addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { + response = prepareResponse(ctx, msg, response); + } + }); + } + }); + + channel = b.connect(HOST, PORT) + .sync() + .channel(); + } + + @Test + public void whenPostSent_thenContentReceivedInUppercase() throws Exception { + String body = "Hello World!"; + + DefaultFullHttpRequest request = createRequest(body); + + channel.writeAndFlush(request); + Thread.sleep(200); + + assertEquals(200, response.getStatus()); + assertEquals("HTTP/1.1", response.getVersion()); + + assertTrue(response.getContent() + .contains(body.toUpperCase())); + } + + @Test + public void whenGetSent_thenCookieReceivedInResponse() throws Exception { + DefaultFullHttpRequest request = createRequest(null); + + channel.writeAndFlush(request); + Thread.sleep(200); + + assertEquals(200, response.getStatus()); + assertEquals("HTTP/1.1", response.getVersion()); + + Map headers = response.getHeaders(); + String cookies = headers.get("set-cookie"); + assertTrue(cookies.contains("my-cookie")); + } + + @After + public void cleanup() throws InterruptedException { + channel.closeFuture() + .sync(); + group.shutdownGracefully(); + } + + private static DefaultFullHttpRequest createRequest(final CharSequence body) throws Exception { + DefaultFullHttpRequest request; + if (body != null) { + request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/"); + request.content() + .writeBytes(body.toString() + .getBytes(CharsetUtil.UTF_8.name())); + request.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "application/json"); + request.headers() + .set(HttpHeaderNames.CONTENT_LENGTH, request.content() + .readableBytes()); + } else { + request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/", Unpooled.EMPTY_BUFFER); + request.headers() + .set(HttpHeaderNames.COOKIE, ClientCookieEncoder.STRICT.encode(new DefaultCookie("my-cookie", "foo"))); + } + + request.headers() + .set(HttpHeaderNames.HOST, HOST); + request.headers() + .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + + return request; + } + + private static ResponseAggregator prepareResponse(ChannelHandlerContext ctx, HttpObject msg, ResponseAggregator responseAgg) { + + if (msg instanceof HttpResponse) { + HttpResponse response = (HttpResponse) msg; + + responseAgg.setStatus(response.status() + .code()); + + responseAgg.setVersion(response.protocolVersion() + .text()); + + if (!response.headers() + .isEmpty()) { + Map headers = new HashMap(); + for (CharSequence name : response.headers() + .names()) { + for (CharSequence value : response.headers() + .getAll(name)) { + headers.put(name.toString(), value.toString()); + } + } + responseAgg.setHeaders(headers); + } + if (HttpUtil.isTransferEncodingChunked(response)) { + responseAgg.setChunked(true); + } else { + responseAgg.setChunked(false); + } + } + if (msg instanceof HttpContent) { + HttpContent content = (HttpContent) msg; + String responseData = content.content() + .toString(CharsetUtil.UTF_8); + + if (content instanceof LastHttpContent) { + responseAgg.setContent(responseData + "} End Of Content"); + ctx.close(); + } + } + return responseAgg; + } +} diff --git a/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java b/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java new file mode 100644 index 0000000000..9f6e5e9823 --- /dev/null +++ b/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java @@ -0,0 +1,52 @@ +package com.baeldung.http.server; + +import java.util.Map; + +public class ResponseAggregator { + int status; + String version; + Map headers; + boolean isChunked; + String content; + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public boolean isChunked() { + return isChunked; + } + + public void setChunked(boolean isChunked) { + this.isChunked = isChunked; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + +} From c122add13e331e0c9cf9e01f264baa52f378ffa1 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 3 Jun 2020 22:20:43 -0500 Subject: [PATCH 066/118] Bael 4026 (#9433) * BAEL-3336 BAEL-3058 add links * BAEL-3319: add link * BAEL-3284: add link * BAEL-3198: add link to article * BAEL-3479: add link to article * BAEL-3485: add article link * SCALA-38: move to new package and add link back to article * SCALA-38: add imports back into unit test * BAEL-3908: add link back to article * BAEL-2893 BAEL-3927 add link back to article * BAEL-4026: update README.md --- spring-cloud/spring-cloud-open-service-broker/README.md | 2 ++ testing-modules/mockito-2/README.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-cloud/spring-cloud-open-service-broker/README.md b/spring-cloud/spring-cloud-open-service-broker/README.md index f09469076b..4084e8ebb2 100644 --- a/spring-cloud/spring-cloud-open-service-broker/README.md +++ b/spring-cloud/spring-cloud-open-service-broker/README.md @@ -1 +1,3 @@ ### Relevant Articles: + +- [Quick Guide to Spring Cloud Open Service Broker](https://www.baeldung.com/spring-cloud-open-service-broker) diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md index 329228186f..1a013f5de3 100644 --- a/testing-modules/mockito-2/README.md +++ b/testing-modules/mockito-2/README.md @@ -5,4 +5,4 @@ - [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) +- [Introduction to Mockito’s AdditionalAnswers](https://www.baeldung.com/mockito-additionalanswers) \ No newline at end of file From e4d59f4874bfd432a894f6e98fc70dd847cf3f79 Mon Sep 17 00:00:00 2001 From: Roque Santos Date: Thu, 4 Jun 2020 02:23:10 -0300 Subject: [PATCH 067/118] BAEL-3844 : Documenting the LiveTests using JavaDoc. --- .../resttemplate/proxy/RequestFactoryLiveTest.java | 9 +++++++++ .../proxy/RestTemplateCustomizerLiveTest.java | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java index 8c13bef05f..93949e52a3 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RequestFactoryLiveTest.java @@ -15,6 +15,15 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +/** + * This class is used to test a request using {@link RestTemplate} with {@link Proxy} + * using a {@link SimpleClientHttpRequestFactory} as configuration. + *
+ *
+ * + * Before running the test we should change the PROXY_SERVER_HOST + * and PROXY_SERVER_PORT constants in our class to match our preferred proxy configuration. + */ public class RequestFactoryLiveTest { private static final String PROXY_SERVER_HOST = "127.0.0.1"; diff --git a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java index 547428ec9f..faeb49537a 100644 --- a/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java +++ b/spring-resttemplate/src/test/java/com/baeldung/resttemplate/proxy/RestTemplateCustomizerLiveTest.java @@ -4,6 +4,8 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import java.net.Proxy; + import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; @@ -20,6 +22,15 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +/** + * This class is used to test a request using {@link RestTemplate} with {@link Proxy} + * using a {@link RestTemplateCustomizer} as configuration. + *
+ *
+ * + * Before running the test we should change the PROXY_SERVER_HOST + * and PROXY_SERVER_PORT constants in our class to match our preferred proxy configuration. + */ public class RestTemplateCustomizerLiveTest { private static final String PROXY_SERVER_HOST = "127.0.0.1"; From bc2c23ae9e229be2ba0c05d2784a6a86aea50c52 Mon Sep 17 00:00:00 2001 From: Cristian Rosu Date: Thu, 4 Jun 2020 12:18:03 +0300 Subject: [PATCH 068/118] BAEL-4070: removed unnecessary curly brace, fixed test name --- .../baeldung/properties/lists/ListsPropertiesUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java index 8c1835a0a9..80cb8e9ea0 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java @@ -15,7 +15,7 @@ import java.util.List; import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = {SpringListPropertiesApplication.class}) +@ContextConfiguration(classes = SpringListPropertiesApplication.class) public class ListsPropertiesUnitTest { @Value("${arrayOfStrings}") @@ -78,7 +78,7 @@ public class ListsPropertiesUnitTest { } @Test - public void WhenReadingFromSpringEnvironment_ThenPropertiesHaveExpectedValues() { + public void whenReadingFromSpringEnvironment_ThenPropertiesHaveExpectedValues() { String[] arrayOfStrings = environment.getProperty("arrayOfStrings", String[].class); List listOfStrings = (List)environment.getProperty("arrayOfStrings", List.class); From 3078464b95757ebb304abb35f9b13f982572b9be Mon Sep 17 00:00:00 2001 From: bragilev Date: Thu, 4 Jun 2020 16:58:48 +0200 Subject: [PATCH 069/118] Bael-3386 (#9231) * bragilev * Delete ShoppingListApplication.java * BAEL-3386 * Revert "bragilev" This reverts commit dbf2a21ba4fe2a60c518beecda7ab33746977252. * Revert "Delete ShoppingListApplication.java" This reverts commit 640bb544e6cd8eda6d1fe6a38607323871ddb957. * Revert "Revert "Delete ShoppingListApplication.java"" This reverts commit f56864e46db92c4f981bdc38f78fbabade72156c. --- .../hibernate-exceptions/pom.xml | 39 +++++++++ .../lazyinitialization/HibernateUtil.java | 42 +++++++++ .../lazyinitialization/entity/Role.java | 45 ++++++++++ .../lazyinitialization/entity/User.java | 55 ++++++++++++ .../HibernateNoSessionUnitTest.java | 85 +++++++++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 persistence-modules/hibernate-exceptions/pom.xml create mode 100644 persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateUtil.java create mode 100644 persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/Role.java create mode 100644 persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/User.java create mode 100644 persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateNoSessionUnitTest.java diff --git a/persistence-modules/hibernate-exceptions/pom.xml b/persistence-modules/hibernate-exceptions/pom.xml new file mode 100644 index 0000000000..e5217e83bd --- /dev/null +++ b/persistence-modules/hibernate-exceptions/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + hibernate-exceptions + 0.0.1-SNAPSHOT + hibernate-exceptions + + + com.baeldung + persistence-modules + 1.0.0-SNAPSHOT + + + + + org.hsqldb + hsqldb + ${hsqldb.version} + + + org.hibernate + hibernate-core + ${hibernate.version} + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + + + 2.4.0 + 2.3.0 + 5.3.7.Final + + + diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateUtil.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateUtil.java new file mode 100644 index 0000000000..b84a512fd4 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateUtil.java @@ -0,0 +1,42 @@ +package com.baeldung.hibernate.exception.lazyinitialization; + +import java.util.Properties; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; + +import com.baeldung.hibernate.exception.lazyinitialization.entity.Role; +import com.baeldung.hibernate.exception.lazyinitialization.entity.User; + +public class HibernateUtil { + private static SessionFactory sessionFactory; + + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + try { + Configuration configuration = new Configuration(); + Properties settings = new Properties(); + settings.put(Environment.DRIVER, "org.hsqldb.jdbcDriver"); + settings.put(Environment.URL, "jdbc:hsqldb:mem:userrole"); + settings.put(Environment.USER, "sa"); + settings.put(Environment.PASS, ""); + settings.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect"); + settings.put(Environment.SHOW_SQL, "true"); + settings.put(Environment.HBM2DDL_AUTO, "update"); + configuration.setProperties(settings); + configuration.addAnnotatedClass(User.class); + configuration.addAnnotatedClass(Role.class); + + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()).build(); + sessionFactory = configuration.buildSessionFactory(serviceRegistry); + } catch (Exception e) { + e.printStackTrace(); + } + } + return sessionFactory; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/Role.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/Role.java new file mode 100644 index 0000000000..c15e674c52 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/Role.java @@ -0,0 +1,45 @@ +package com.baeldung.hibernate.exception.lazyinitialization.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "role") +public class Role { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "role_name") + private String roleName; + + public Role() { + + } + + public Role(String roleName) { + this.roleName = roleName; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + +} diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/User.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/User.java new file mode 100644 index 0000000000..5bd7e00801 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/lazyinitialization/entity/User.java @@ -0,0 +1,55 @@ +package com.baeldung.hibernate.exception.lazyinitialization.entity; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +@Entity +@Table(name = "user") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "first_name") + private String firstName; + + @Column(name = "last_name") + private String lastName; + + @OneToMany + @JoinColumn(name = "user_id") + private Set roles = new HashSet<>(); + + public User() { + + } + + public User(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public int getId() { + return id; + } + + public Set getRoles() { + return roles; + } + + public void addRole(Role role) { + roles.add(role); + } + +} diff --git a/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateNoSessionUnitTest.java b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateNoSessionUnitTest.java new file mode 100644 index 0000000000..672c438c88 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/lazyinitialization/HibernateNoSessionUnitTest.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.exception.lazyinitialization; + +import org.hibernate.LazyInitializationException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.baeldung.hibernate.exception.lazyinitialization.entity.Role; +import com.baeldung.hibernate.exception.lazyinitialization.entity.User; + +public class HibernateNoSessionUnitTest { + + private static SessionFactory sessionFactory; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @BeforeClass + public static void init() { + sessionFactory = HibernateUtil.getSessionFactory(); + } + + @Test + public void whenAccessUserRolesInsideSession_thenSuccess() { + + User detachedUser = createUserWithRoles(); + + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + User persistentUser = session.find(User.class, detachedUser.getId()); + + Assert.assertEquals(2, persistentUser.getRoles().size()); + + session.getTransaction().commit(); + session.close(); + } + + @Test + public void whenAccessUserRolesOutsideSession_thenThrownException() { + + User detachedUser = createUserWithRoles(); + + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + User persistentUser = session.find(User.class, detachedUser.getId()); + + session.getTransaction().commit(); + session.close(); + + thrown.expect(LazyInitializationException.class); + System.out.println(persistentUser.getRoles().size()); + } + + private User createUserWithRoles() { + + Role admin = new Role("Admin"); + Role dba = new Role("DBA"); + + User user = new User("Bob", "Smith"); + + user.addRole(admin); + user.addRole(dba); + + Session session = sessionFactory.openSession(); + session.beginTransaction(); + user.getRoles().forEach(role -> session.save(role)); + session.save(user); + session.getTransaction().commit(); + session.close(); + + return user; + } + + @AfterClass + public static void cleanUp() { + sessionFactory.close(); + } +} From 829b4975c4cd6269fd6744d8b5b800efe7559470 Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 4 Jun 2020 10:06:16 -0600 Subject: [PATCH 070/118] Update README.md Issue BAEL-3896 --- spring-rest-http/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-rest-http/README.md b/spring-rest-http/README.md index 35793cb281..f78f8784b0 100644 --- a/spring-rest-http/README.md +++ b/spring-rest-http/README.md @@ -13,3 +13,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring RequestMapping](https://www.baeldung.com/spring-requestmapping) - [Guide to DeferredResult in Spring](https://www.baeldung.com/spring-deferred-result) - [Using JSON Patch in Spring REST APIs](https://www.baeldung.com/spring-rest-json-patch) +- [Using OpenAPI and JSON Request Parameters](https://www.baeldung.com/openapi-json-query-parameters) From 07751eeea2af16605d98ecf2bed47ed2ac0cf230 Mon Sep 17 00:00:00 2001 From: Krzysztof Woyke Date: Fri, 5 Jun 2020 15:10:58 +0200 Subject: [PATCH 071/118] JAVA-1782: Add byte-buddy to parent-boot-2 --- parent-boot-2/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index c7bb11b1d5..631d8a0581 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -32,6 +32,11 @@ io.rest-assured rest-assured + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + org.springframework.boot spring-boot-starter-test From b8a3dd7a687fb7e8c6a751aa9a214e4f84bbf99f Mon Sep 17 00:00:00 2001 From: Krzysztof Woyke Date: Fri, 5 Jun 2020 15:38:09 +0200 Subject: [PATCH 072/118] JAVA-1782: Remove byte-buddy dep from parent-boot-2's children --- persistence-modules/spring-boot-persistence-h2/pom.xml | 5 ----- spring-5-mvc/pom.xml | 5 ----- spring-boot-groovy/pom.xml | 5 ----- spring-boot-modules/spring-boot-keycloak/pom.xml | 4 ---- spring-boot-rest/pom.xml | 5 ----- spring-jinq/pom.xml | 7 ------- spring-rest-hal-browser/pom.xml | 6 ------ spring-security-modules/spring-security-mvc-boot-1/pom.xml | 4 ---- spring-social-login/pom.xml | 7 ------- 9 files changed, 48 deletions(-) diff --git a/persistence-modules/spring-boot-persistence-h2/pom.xml b/persistence-modules/spring-boot-persistence-h2/pom.xml index 7070b5e674..9e6c780931 100644 --- a/persistence-modules/spring-boot-persistence-h2/pom.xml +++ b/persistence-modules/spring-boot-persistence-h2/pom.xml @@ -40,11 +40,6 @@ db-util ${db-util.version} - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - diff --git a/spring-5-mvc/pom.xml b/spring-5-mvc/pom.xml index 4b42528d0f..945ddef5e1 100644 --- a/spring-5-mvc/pom.xml +++ b/spring-5-mvc/pom.xml @@ -42,11 +42,6 @@ org.slf4j jcl-over-slf4j - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - org.jetbrains.kotlin diff --git a/spring-boot-groovy/pom.xml b/spring-boot-groovy/pom.xml index f61398c5d6..9ea8d7b2a9 100644 --- a/spring-boot-groovy/pom.xml +++ b/spring-boot-groovy/pom.xml @@ -41,11 +41,6 @@ h2 runtime - - net.bytebuddy - byte-buddy-dep - 1.10.9 - diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index 8e917df2b7..68d4ec4b8f 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -41,10 +41,6 @@ org.springframework.boot spring-boot-starter-data-jpa - - net.bytebuddy - byte-buddy - org.springframework.boot diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index a8500d50f2..10dacf99e8 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -79,11 +79,6 @@ modelmapper ${modelmapper.version} - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - diff --git a/spring-jinq/pom.xml b/spring-jinq/pom.xml index 073808823c..647c0907a7 100644 --- a/spring-jinq/pom.xml +++ b/spring-jinq/pom.xml @@ -37,12 +37,6 @@ spring-boot-starter-data-jpa - - net.bytebuddy - byte-buddy-dep - ${bytebuddy.version} - - org.springframework @@ -73,7 +67,6 @@ 1.8.29 - 1.10.10 diff --git a/spring-rest-hal-browser/pom.xml b/spring-rest-hal-browser/pom.xml index 32a0b52875..7b629dba44 100644 --- a/spring-rest-hal-browser/pom.xml +++ b/spring-rest-hal-browser/pom.xml @@ -35,11 +35,6 @@ com.h2database h2 - - net.bytebuddy - byte-buddy-dep - ${bytebuddy.version} - @@ -56,7 +51,6 @@ - 1.10.10 1.8 1.8 diff --git a/spring-security-modules/spring-security-mvc-boot-1/pom.xml b/spring-security-modules/spring-security-mvc-boot-1/pom.xml index b00b7bab32..7ad18376ec 100644 --- a/spring-security-modules/spring-security-mvc-boot-1/pom.xml +++ b/spring-security-modules/spring-security-mvc-boot-1/pom.xml @@ -106,10 +106,6 @@ ${ehcache-core.version} jar - - net.bytebuddy - byte-buddy - diff --git a/spring-social-login/pom.xml b/spring-social-login/pom.xml index 628f439cc0..0de20cd087 100644 --- a/spring-social-login/pom.xml +++ b/spring-social-login/pom.xml @@ -62,12 +62,6 @@ h2 - - net.bytebuddy - byte-buddy-dep - ${bytebuddy.version} - - @@ -102,7 +96,6 @@ - 1.10.9 2.0.3.RELEASE From de8acfd6e02afec5e466823b73865caab01c6f88 Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Sun, 7 Jun 2020 15:29:59 +0530 Subject: [PATCH 073/118] BAEL3889 - Adding braces in EvenOddPartitioner --- .../java/com/baeldung/kafka/producer/EvenOddPartitioner.java | 5 +++-- .../main/java/com/baeldung/kafka/producer/KafkaProducer.java | 2 +- .../com/baeldung/kafka/producer/KafkaProducerUnitTest.java | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java index 12c86828dd..1c77226037 100644 --- a/libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java +++ b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/EvenOddPartitioner.java @@ -1,4 +1,4 @@ -package com.baeldung.kafka; +package com.baeldung.kafka.producer; import org.apache.kafka.clients.producer.internals.DefaultPartitioner; import org.apache.kafka.common.Cluster; @@ -8,8 +8,9 @@ public class EvenOddPartitioner extends DefaultPartitioner { @Override public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { - if (((String)key).length() % 2 == 0) + if (((String) key).length() % 2 == 0) { return 0; + } return 1; } diff --git a/libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java index 8574cd1c40..911c9ed3d7 100644 --- a/libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java +++ b/libraries-data-2/src/main/java/com/baeldung/kafka/producer/KafkaProducer.java @@ -1,4 +1,4 @@ -package com.baeldung.kafka; +package com.baeldung.kafka.producer; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; diff --git a/libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java index ce3803322c..a7156ed886 100644 --- a/libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java +++ b/libraries-data-2/src/test/java/com/baeldung/kafka/producer/KafkaProducerUnitTest.java @@ -1,5 +1,7 @@ -package com.baeldung.kafka; +package com.baeldung.kafka.producer; +import com.baeldung.kafka.producer.EvenOddPartitioner; +import com.baeldung.kafka.producer.KafkaProducer; import org.apache.kafka.clients.producer.MockProducer; import org.apache.kafka.clients.producer.RecordMetadata; import org.apache.kafka.common.Cluster; From 6f21d2eb744f49decc035abd12bf25835b7a2f7e Mon Sep 17 00:00:00 2001 From: mikr Date: Sun, 7 Jun 2020 12:13:32 +0200 Subject: [PATCH 074/118] JAVA-1749 Update UUID article and code --- .../java/com/baeldung/uuid/UUIDGenerator.java | 134 ++++++++++++------ .../baeldung/uuid/UUIDGeneratorUnitTest.java | 64 +++++++++ 2 files changed, 156 insertions(+), 42 deletions(-) create mode 100644 core-java-modules/core-java/src/test/java/com/baeldung/uuid/UUIDGeneratorUnitTest.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java b/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java index 2659b29491..cb43a26929 100644 --- a/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java +++ b/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java @@ -3,30 +3,57 @@ package com.baeldung.uuid; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Random; import java.util.UUID; public class UUIDGenerator { - /** - * These are predefined UUID for name spaces - */ - private static final String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; - private static final String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8"; - private static final String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8"; - private static final String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8"; - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - public static void main(String[] args) { - try { - System.out.println("Type 3 : " + generateType3UUID(NAMESPACE_DNS, "google.com")); - System.out.println("Type 4 : " + generateType4UUID()); - System.out.println("Type 5 : " + generateType5UUID(NAMESPACE_URL, "google.com")); - System.out.println("Unique key : " + generateUniqueKeysWithUUIDAndMessageDigest()); - } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - e.printStackTrace(); - } + /** + * Type 1 UUID Generation + */ + public static UUID generateType1UUID() { + + long most64SigBits = get64MostSignificantBitsForVersion1(); + long least64SigBits = get64LeastSignificantBitsForVersion1(); + + return new UUID(most64SigBits, least64SigBits); + } + + private static long get64LeastSignificantBitsForVersion1() { + Random random = new Random(); + long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL; + long variant3BitFlag = 0x8000000000000000L; + return random63BitLong + variant3BitFlag; + } + + private static long get64MostSignificantBitsForVersion1() { + LocalDateTime start = LocalDateTime.of(1582, 10, 15, 0, 0, 0); + Duration duration = Duration.between(start, LocalDateTime.now()); + long seconds = duration.getSeconds(); + long nanos = duration.getNano(); + long timeForUuidIn100Nanos = seconds * 10000000 + nanos * 100; + long least12SignificatBitOfTime = (timeForUuidIn100Nanos & 0x000000000000FFFFL) >> 4; + long version = 1 << 12; + return (timeForUuidIn100Nanos & 0xFFFFFFFFFFFF0000L) + version + least12SignificatBitOfTime; + } + + /** + * Type 3 UUID Generation + * + * @throws UnsupportedEncodingException + */ + public static UUID generateType3UUID(String namespace, String name) throws UnsupportedEncodingException { + + byte[] nameSpaceBytes = bytesFromUUID(namespace); + byte[] nameBytes = name.getBytes("UTF-8"); + byte[] result = joinBytes(nameSpaceBytes, nameBytes); + + return UUID.nameUUIDFromBytes(result); } /** @@ -37,28 +64,18 @@ public class UUIDGenerator { return uuid; } - /** - * Type 3 UUID Generation - * - * @throws UnsupportedEncodingException - */ - public static UUID generateType3UUID(String namespace, String name) throws UnsupportedEncodingException { - String source = namespace + name; - byte[] bytes = source.getBytes("UTF-8"); - UUID uuid = UUID.nameUUIDFromBytes(bytes); - return uuid; - } - /** * Type 5 UUID Generation - * - * @throws UnsupportedEncodingException + * + * @throws UnsupportedEncodingException */ public static UUID generateType5UUID(String namespace, String name) throws UnsupportedEncodingException { - String source = namespace + name; - byte[] bytes = source.getBytes("UTF-8"); - UUID uuid = type5UUIDFromBytes(bytes); - return uuid; + + byte[] nameSpaceBytes = bytesFromUUID(namespace); + byte[] nameBytes = name.getBytes("UTF-8"); + byte[] result = joinBytes(nameSpaceBytes, nameBytes); + + return type5UUIDFromBytes(result); } public static UUID type5UUIDFromBytes(byte[] name) { @@ -91,20 +108,20 @@ public class UUIDGenerator { /** * Unique Keys Generation Using Message Digest and Type 4 UUID - * - * @throws NoSuchAlgorithmException - * @throws UnsupportedEncodingException + * + * @throws NoSuchAlgorithmException + * @throws UnsupportedEncodingException */ public static String generateUniqueKeysWithUUIDAndMessageDigest() throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest salt = MessageDigest.getInstance("SHA-256"); salt.update(UUID.randomUUID() - .toString() - .getBytes("UTF-8")); + .toString() + .getBytes("UTF-8")); String digest = bytesToHex(salt.digest()); return digest; } - public static String bytesToHex(byte[] bytes) { + private static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; @@ -114,4 +131,37 @@ public class UUIDGenerator { return new String(hexChars); } -} + private static byte[] bytesFromUUID(String uuidHexString) { + String normalizedUUIDHexString = uuidHexString.replace("-",""); + + assert normalizedUUIDHexString.length() == 32; + + byte[] bytes = new byte[16]; + for (int i = 0; i < 16; i++) { + byte b = hexToByte(normalizedUUIDHexString.substring(i*2, i*2+2)); + bytes[i] = b; + } + return bytes; + } + + public static byte hexToByte(String hexString) { + int firstDigit = Character.digit(hexString.charAt(0),16); + int secondDigit = Character.digit(hexString.charAt(1),16); + return (byte) ((firstDigit << 4) + secondDigit); + } + + public static byte[] joinBytes(byte[] byteArray1, byte[] byteArray2) { + int finalLength = byteArray1.length + byteArray2.length; + byte[] result = new byte[finalLength]; + + for(int i = 0; i < byteArray1.length; i++) { + result[i] = byteArray1[i]; + } + + for(int i = 0; i < byteArray2.length; i++) { + result[byteArray1.length+i] = byteArray2[i]; + } + + return result; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/uuid/UUIDGeneratorUnitTest.java b/core-java-modules/core-java/src/test/java/com/baeldung/uuid/UUIDGeneratorUnitTest.java new file mode 100644 index 0000000000..9e08363a63 --- /dev/null +++ b/core-java-modules/core-java/src/test/java/com/baeldung/uuid/UUIDGeneratorUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.uuid; + +import org.junit.jupiter.api.Test; + +import java.io.UnsupportedEncodingException; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class UUIDGeneratorUnitTest { + + private static final String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8"; + private static final String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; + + @Test + public void version_1_UUID_is_generated_with_correct_length_version_and_variant() { + + UUID uuid = UUIDGenerator.generateType1UUID(); + + assertEquals(36, uuid.toString().length()); + assertEquals(1, uuid.version()); + assertEquals(2, uuid.variant()); + } + + @Test + public void version_3_UUID_is_correctly_generated_for_domain_baeldung_com() throws UnsupportedEncodingException { + + UUID uuid = UUIDGenerator.generateType3UUID(NAMESPACE_DNS, "baeldung.com"); + + assertEquals("23785b78-0132-3ac6-aff6-cfd5be162139", uuid.toString()); + assertEquals(3, uuid.version()); + assertEquals(2, uuid.variant()); + } + + @Test + public void version_3_UUID_is_correctly_generated_for_domain_d() throws UnsupportedEncodingException { + + UUID uuid = UUIDGenerator.generateType3UUID(NAMESPACE_DNS, "d"); + + assertEquals("dbd41ecb-f466-33de-b309-1468addfc63b", uuid.toString()); + assertEquals(3, uuid.version()); + assertEquals(2, uuid.variant()); + } + + @Test + public void version_4_UUID_is_generated_with_correct_length_version_and_variant() { + + UUID uuid = UUIDGenerator.generateType4UUID(); + + assertEquals(36, uuid.toString().length()); + assertEquals(4, uuid.version()); + assertEquals(2, uuid.variant()); + } + + @Test + public void version_5_UUID_is_correctly_generated_for_domain_baeldung_com() throws UnsupportedEncodingException { + + UUID uuid = UUIDGenerator.generateType5UUID(NAMESPACE_URL, "baeldung.com"); + + assertEquals("aeff44a5-8a61-52b6-bcbe-c8e5bd7d0300", uuid.toString()); + assertEquals(5, uuid.version()); + assertEquals(2, uuid.variant()); + } +} \ No newline at end of file From 46ebcba3a04c72b526fabdf90801319c87c9016c Mon Sep 17 00:00:00 2001 From: mikr Date: Sun, 7 Jun 2020 13:22:16 +0200 Subject: [PATCH 075/118] JAVA-1749 Move modules language interop and console --- core-java-modules/core-java-console/README.md | 5 + core-java-modules/core-java-console/pom.xml | 142 ++++++++++++++++++ .../java/com/baeldung/asciiart/AsciiArt.java | 0 .../baeldung/console/ConsoleConsoleClass.java | 0 .../baeldung/console/ConsoleScannerClass.java | 0 .../com/baeldung/printf/PrintfExamples.java | 0 .../asciiart/AsciiArtIntegrationTest.java | 7 +- core-java-modules/core-java/README.md | 60 ++++++++ language-interop/README.md | 1 + .../src/main/resources/js/bind.js | 0 .../src/main/resources/js/locations.js | 0 .../src/main/resources/js/math_module.js | 0 .../src/main/resources/js/no_such.js | 0 .../src/main/resources/js/script.js | 0 .../src/main/resources/js/trim.js | 0 .../src/main/resources/js/typed_arrays.js | 0 .../interop/javascript}/NashornUnitTest.java | 8 +- 17 files changed, 214 insertions(+), 9 deletions(-) create mode 100644 core-java-modules/core-java-console/README.md create mode 100644 core-java-modules/core-java-console/pom.xml rename core-java-modules/{core-java => core-java-console}/src/main/java/com/baeldung/asciiart/AsciiArt.java (100%) rename core-java-modules/{core-java => core-java-console}/src/main/java/com/baeldung/console/ConsoleConsoleClass.java (100%) rename core-java-modules/{core-java => core-java-console}/src/main/java/com/baeldung/console/ConsoleScannerClass.java (100%) rename core-java-modules/{core-java => core-java-console}/src/main/java/com/baeldung/printf/PrintfExamples.java (100%) rename core-java-modules/{core-java => core-java-console}/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java (89%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/bind.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/locations.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/math_module.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/no_such.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/script.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/trim.js (100%) rename {core-java-modules/core-java => language-interop}/src/main/resources/js/typed_arrays.js (100%) rename {core-java-modules/core-java/src/test/java/com/baeldung/scripting => language-interop/src/test/java/com/baeldung/language/interop/javascript}/NashornUnitTest.java (94%) diff --git a/core-java-modules/core-java-console/README.md b/core-java-modules/core-java-console/README.md new file mode 100644 index 0000000000..725e2482bb --- /dev/null +++ b/core-java-modules/core-java-console/README.md @@ -0,0 +1,5 @@ +#Core Java Console + +[Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output) +[Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) +[ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) \ No newline at end of file diff --git a/core-java-modules/core-java-console/pom.xml b/core-java-modules/core-java-console/pom.xml new file mode 100644 index 0000000000..1d58d8c253 --- /dev/null +++ b/core-java-modules/core-java-console/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + core-java-console + 0.1.0-SNAPSHOT + core-java-console + jar + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + ../ + + + + core-java-console + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/libs + + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + java + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed + + -Xmx300m + -XX:+UseParallelGC + -classpath + + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + ${source.version} + ${target.version} + + + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*ManualTest.java + + + **/*IntegrationTest.java + **/*IntTest.java + + + + + + + json + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + + run-benchmarks + + none + + exec + + + test + java + + -classpath + + org.openjdk.jmh.Main + .* + + + + + + + + + + + + 3.0.0-M1 + 1.6.0 + 1.8 + 1.8 + + + diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/asciiart/AsciiArt.java b/core-java-modules/core-java-console/src/main/java/com/baeldung/asciiart/AsciiArt.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/asciiart/AsciiArt.java rename to core-java-modules/core-java-console/src/main/java/com/baeldung/asciiart/AsciiArt.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/console/ConsoleConsoleClass.java b/core-java-modules/core-java-console/src/main/java/com/baeldung/console/ConsoleConsoleClass.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/console/ConsoleConsoleClass.java rename to core-java-modules/core-java-console/src/main/java/com/baeldung/console/ConsoleConsoleClass.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/console/ConsoleScannerClass.java b/core-java-modules/core-java-console/src/main/java/com/baeldung/console/ConsoleScannerClass.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/console/ConsoleScannerClass.java rename to core-java-modules/core-java-console/src/main/java/com/baeldung/console/ConsoleScannerClass.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/printf/PrintfExamples.java b/core-java-modules/core-java-console/src/main/java/com/baeldung/printf/PrintfExamples.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/printf/PrintfExamples.java rename to core-java-modules/core-java-console/src/main/java/com/baeldung/printf/PrintfExamples.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java similarity index 89% rename from core-java-modules/core-java/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java rename to core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java index 8ab1695395..4bfcbe5a36 100644 --- a/core-java-modules/core-java/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java +++ b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java @@ -1,10 +1,9 @@ package com.baeldung.asciiart; -import java.awt.Font; - +import com.baeldung.asciiart.AsciiArt.Settings; import org.junit.Test; -import com.baeldung.asciiart.AsciiArt.Settings; +import java.awt.*; public class AsciiArtIntegrationTest { @@ -15,6 +14,8 @@ public class AsciiArtIntegrationTest { Settings settings = asciiArt.new Settings(new Font("SansSerif", Font.BOLD, 24), text.length() * 30, 30); // 30 pixel width per character asciiArt.drawString(text, "*", settings); + + throw new NullPointerException(); } } diff --git a/core-java-modules/core-java/README.md b/core-java-modules/core-java/README.md index bffb88cafb..2123a61499 100644 --- a/core-java-modules/core-java/README.md +++ b/core-java-modules/core-java/README.md @@ -33,3 +33,63 @@ - [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) - [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) - [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) + + +#New module structure +########################### + +#Leave in core-java: +[Getting Started with Java Properties](http://www.baeldung.com/java-properties) +[Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) +[Introduction to Java Serialization](http://www.baeldung.com/java-serialization) +[Guide to UUID in Java](http://www.baeldung.com/java-uuid) +[Compiling Java *.class Files with javac](http://www.baeldung.com/javac) +[Introduction to Javadoc](http://www.baeldung.com/javadoc) +[Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) +[What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) +[A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) +[Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) + +#Move to language interop (Done) +[Introduction to Nashorn](http://www.baeldung.com/java-nashorn) + +#Move to new new package: core-java-console (Done) +[Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output) +[Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) +[ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) + +#Move to core-java-string-operations-2 +[Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) +[Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) #remove additional readme file + +#Move to core-javadatetime-operations-2 +[Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) + +#Move to core-java-time-measurements +[Java Timer](http://www.baeldung.com/java-timer-and-timertask) + +#Move to core-java-reflection +[How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method) + +#Move to core-java-streams +[How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null) + +#Move to core-java-jvm +[How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) + +#Move to data-structures module +[Graphs in Java](https://www.baeldung.com/java-graphs) + +#Move to core-java-collections-3 +[Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) + +#These are already in another module +[Using Curl in Java](https://www.baeldung.com/java-curl) #Core Java Networking (Part 2) +[Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) # Core Java Sun +[Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) #Core Java Exceptions +[Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) #Core Java Exceptions +[How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) #Core Java Exceptions +[JVM Log Forging](http://www.baeldung.com/jvm-log-forging) #Core Java JVM +[Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) #Core Java Networking (Part 2) +[Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) #Core Java Exceptions +[Retrieve Fields from a Java Class Using Reflection](https://www.baeldung.com/java-reflection-class-fields) #Core Java Reflection \ No newline at end of file diff --git a/language-interop/README.md b/language-interop/README.md index 458f34a119..f4f2fc0816 100644 --- a/language-interop/README.md +++ b/language-interop/README.md @@ -5,3 +5,4 @@ This module contains articles about Java interop with other language integration ### Relevant Articles: - [How to Call Python From Java](https://www.baeldung.com/java-working-with-python) +- [Introduction to Nashorn](http://www.baeldung.com/java-nashorn) diff --git a/core-java-modules/core-java/src/main/resources/js/bind.js b/language-interop/src/main/resources/js/bind.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/bind.js rename to language-interop/src/main/resources/js/bind.js diff --git a/core-java-modules/core-java/src/main/resources/js/locations.js b/language-interop/src/main/resources/js/locations.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/locations.js rename to language-interop/src/main/resources/js/locations.js diff --git a/core-java-modules/core-java/src/main/resources/js/math_module.js b/language-interop/src/main/resources/js/math_module.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/math_module.js rename to language-interop/src/main/resources/js/math_module.js diff --git a/core-java-modules/core-java/src/main/resources/js/no_such.js b/language-interop/src/main/resources/js/no_such.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/no_such.js rename to language-interop/src/main/resources/js/no_such.js diff --git a/core-java-modules/core-java/src/main/resources/js/script.js b/language-interop/src/main/resources/js/script.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/script.js rename to language-interop/src/main/resources/js/script.js diff --git a/core-java-modules/core-java/src/main/resources/js/trim.js b/language-interop/src/main/resources/js/trim.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/trim.js rename to language-interop/src/main/resources/js/trim.js diff --git a/core-java-modules/core-java/src/main/resources/js/typed_arrays.js b/language-interop/src/main/resources/js/typed_arrays.js similarity index 100% rename from core-java-modules/core-java/src/main/resources/js/typed_arrays.js rename to language-interop/src/main/resources/js/typed_arrays.js diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/scripting/NashornUnitTest.java b/language-interop/src/test/java/com/baeldung/language/interop/javascript/NashornUnitTest.java similarity index 94% rename from core-java-modules/core-java/src/test/java/com/baeldung/scripting/NashornUnitTest.java rename to language-interop/src/test/java/com/baeldung/language/interop/javascript/NashornUnitTest.java index 9abe8a927c..a9e4243f9d 100644 --- a/core-java-modules/core-java/src/test/java/com/baeldung/scripting/NashornUnitTest.java +++ b/language-interop/src/test/java/com/baeldung/language/interop/javascript/NashornUnitTest.java @@ -1,14 +1,10 @@ -package com.baeldung.scripting; +package com.baeldung.language.interop.javascript; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import javax.script.Bindings; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; +import javax.script.*; import java.io.InputStreamReader; import java.util.List; import java.util.Map; From 978a32d0a21d6b53264327b634063e4caab721be Mon Sep 17 00:00:00 2001 From: Ricardo Caldas Date: Sun, 7 Jun 2020 10:00:48 -0300 Subject: [PATCH 076/118] [BAEL-4136] What is this: [Ljava.lang.Object;? Code article --- .../JavaArraysToStringUnitTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java new file mode 100644 index 0000000000..2c81b1358b --- /dev/null +++ b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.arraystostring; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class JavaArraysToStringUnitTest { + + @Test public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() { + Object[] arrayOfObjects = { "John", 2, true }; + assertTrue(arrayOfObjects.toString().startsWith("[Ljava.lang.Object;")); + } + + @Test public void givenInstanceOfArray_useArraysToStringToConvert_thenValueOfObjectsAreShown() { + Object[] arrayOfObjects = { "John", 2, true }; + assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]"); + } + + @Test public void givenInstanceOfDeepArray_userArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() { + Object[] innerArray = { "We", "Are", "Inside" }; + Object[] arrayOfObjects = { "John", 2, innerArray }; + assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]"); + } + + @Test public void givenInstanceOfDeepArray_useStreamsToConvert_thenValueOfObjectsAreShown() { + Object[] arrayOfObjects = { "John", 2, true }; + List listOfString = Stream.of(arrayOfObjects).map(Object::toString).collect(Collectors.toList()); + assertEquals(listOfString.toString(), "[John, 2, true]"); + } +} From 5a753ba3842c44462d49ec546979ad57bf8f16c0 Mon Sep 17 00:00:00 2001 From: mikr Date: Sun, 7 Jun 2020 16:52:25 +0200 Subject: [PATCH 077/118] JAVA-1522 Split core-java-modules/core-java module --- .../core-java-collections-3/README.md | 1 + .../collections}/stack/StackUnitTest.java | 0 .../asciiart/AsciiArtIntegrationTest.java | 3 - .../core-java-date-operations-2/README.md | 1 + .../baeldung/leapyear/LeapYearUnitTest.java | 0 core-java-modules/core-java-jvm/README.md | 1 + .../objectsize/InstrumentationAgent.java | 0 .../objectsize/InstrumentationExample.java | 0 .../java/com/baeldung/objectsize/MANIFEST.MF | 0 .../core-java-reflection/README.MD | 2 + ...CurrentlyExecutedMethodFinderUnitTest.java | 0 .../core-java-string-operations-2/README.md | 2 + .../encoding/CharacterEncodingExamples.java | 0 .../hexToAscii/HexToAsciiUnitTest.java | 0 .../java/com/baeldung/hexToAscii/README.md | 0 .../src/test/resources/output.pdf | Bin 0 -> 142786 bytes .../core-java-time-measurements/README.md | 1 + .../baeldung/timer/DatabaseMigrationTask.java | 0 .../com/baeldung/timer/NewsletterTask.java | 0 .../{java => }/clock/ClockUnitTest.java | 2 +- .../timer/DatabaseMigrationTaskUnitTest.java | 0 .../timer/JavaTimerLongRunningUnitTest.java | 0 .../timer/NewsletterTaskUnitTest.java | 0 core-java-modules/core-java/README.md | 82 ------------------ data-structures/README.md | 1 + .../main/java/com/baeldung/graph/Graph.java | 0 .../com/baeldung/graph/GraphTraversal.java | 0 .../com/baeldung/graph/GraphUnitTest.java | 0 28 files changed, 10 insertions(+), 86 deletions(-) rename core-java-modules/{core-java/src/test/java/com/baeldung => core-java-collections-3/src/test/java/com/baeldung/collections}/stack/StackUnitTest.java (100%) rename core-java-modules/{core-java => core-java-date-operations-2}/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java (100%) rename core-java-modules/{core-java => core-java-jvm}/src/main/java/com/baeldung/objectsize/InstrumentationAgent.java (100%) rename core-java-modules/{core-java => core-java-jvm}/src/main/java/com/baeldung/objectsize/InstrumentationExample.java (100%) rename core-java-modules/{core-java => core-java-jvm}/src/main/java/com/baeldung/objectsize/MANIFEST.MF (100%) rename core-java-modules/{core-java/src/test/java/com/baeldung/java => core-java-reflection/src/test/java/com/baeldung}/currentmethod/CurrentlyExecutedMethodFinderUnitTest.java (100%) rename core-java-modules/{core-java => core-java-string-operations-2}/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java (100%) rename core-java-modules/{core-java => core-java-string-operations-2}/src/test/java/com/baeldung/hexToAscii/HexToAsciiUnitTest.java (100%) rename core-java-modules/{core-java => core-java-string-operations-2}/src/test/java/com/baeldung/hexToAscii/README.md (100%) create mode 100644 core-java-modules/core-java-string-operations-2/src/test/resources/output.pdf rename core-java-modules/{core-java => core-java-time-measurements}/src/main/java/com/baeldung/timer/DatabaseMigrationTask.java (100%) rename core-java-modules/{core-java => core-java-time-measurements}/src/main/java/com/baeldung/timer/NewsletterTask.java (100%) rename core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/{java => }/clock/ClockUnitTest.java (99%) rename core-java-modules/{core-java => core-java-time-measurements}/src/test/java/com/baeldung/timer/DatabaseMigrationTaskUnitTest.java (100%) rename core-java-modules/{core-java => core-java-time-measurements}/src/test/java/com/baeldung/timer/JavaTimerLongRunningUnitTest.java (100%) rename core-java-modules/{core-java => core-java-time-measurements}/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java (100%) rename {core-java-modules/core-java => data-structures}/src/main/java/com/baeldung/graph/Graph.java (100%) rename {core-java-modules/core-java => data-structures}/src/main/java/com/baeldung/graph/GraphTraversal.java (100%) rename {core-java-modules/core-java => data-structures}/src/test/java/com/baeldung/graph/GraphUnitTest.java (100%) diff --git a/core-java-modules/core-java-collections-3/README.md b/core-java-modules/core-java-collections-3/README.md index 9218384640..fb983d9abc 100644 --- a/core-java-modules/core-java-collections-3/README.md +++ b/core-java-modules/core-java-collections-3/README.md @@ -9,3 +9,4 @@ - [Differences Between Collection.clear() and Collection.removeAll()](https://www.baeldung.com/java-collection-clear-vs-removeall) - [Performance of contains() in a HashSet vs ArrayList](https://www.baeldung.com/java-hashset-arraylist-contains-performance) - [Fail-Safe Iterator vs Fail-Fast Iterator](https://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator) +- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/stack/StackUnitTest.java b/core-java-modules/core-java-collections-3/src/test/java/com/baeldung/collections/stack/StackUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/stack/StackUnitTest.java rename to core-java-modules/core-java-collections-3/src/test/java/com/baeldung/collections/stack/StackUnitTest.java diff --git a/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java index 4bfcbe5a36..a8c42fbeb1 100644 --- a/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java +++ b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java @@ -14,8 +14,5 @@ public class AsciiArtIntegrationTest { Settings settings = asciiArt.new Settings(new Font("SansSerif", Font.BOLD, 24), text.length() * 30, 30); // 30 pixel width per character asciiArt.drawString(text, "*", settings); - - throw new NullPointerException(); } - } diff --git a/core-java-modules/core-java-date-operations-2/README.md b/core-java-modules/core-java-date-operations-2/README.md index 19c7b98d30..6dc1302d99 100644 --- a/core-java-modules/core-java-date-operations-2/README.md +++ b/core-java-modules/core-java-date-operations-2/README.md @@ -8,4 +8,5 @@ This module contains articles about date operations in Java. - [Converting Java Date to OffsetDateTime](https://www.baeldung.com/java-convert-date-to-offsetdatetime) - [How to Set the JVM Time Zone](https://www.baeldung.com/java-jvm-time-zone) - [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week) +- [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) - [[<-- Prev]](/core-java-modules/core-java-date-operations-1) diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java b/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java rename to core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java diff --git a/core-java-modules/core-java-jvm/README.md b/core-java-modules/core-java-jvm/README.md index 2f80ea7372..0dae790ec0 100644 --- a/core-java-modules/core-java-jvm/README.md +++ b/core-java-modules/core-java-jvm/README.md @@ -12,3 +12,4 @@ This module contains articles about working with the Java Virtual Machine (JVM). - [Guide to System.gc()](https://www.baeldung.com/java-system-gc) - [Runtime.getRuntime().halt() vs System.exit() in Java](https://www.baeldung.com/java-runtime-halt-vs-system-exit) - [Adding Shutdown Hooks for JVM Applications](https://www.baeldung.com/jvm-shutdown-hooks) +- [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectsize/InstrumentationAgent.java b/core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/InstrumentationAgent.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/objectsize/InstrumentationAgent.java rename to core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/InstrumentationAgent.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectsize/InstrumentationExample.java b/core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/InstrumentationExample.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/objectsize/InstrumentationExample.java rename to core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/InstrumentationExample.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectsize/MANIFEST.MF b/core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/MANIFEST.MF similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/objectsize/MANIFEST.MF rename to core-java-modules/core-java-jvm/src/main/java/com/baeldung/objectsize/MANIFEST.MF diff --git a/core-java-modules/core-java-reflection/README.MD b/core-java-modules/core-java-reflection/README.MD index 5aed62b378..d6b3a02e6a 100644 --- a/core-java-modules/core-java-reflection/README.MD +++ b/core-java-modules/core-java-reflection/README.MD @@ -8,3 +8,5 @@ - [Changing Annotation Parameters At Runtime](http://www.baeldung.com/java-reflection-change-annotation-params) - [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies) - [What Causes java.lang.reflect.InvocationTargetException?](https://www.baeldung.com/java-lang-reflect-invocationtargetexception) +- [How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null) +- [How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method) diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/java/currentmethod/CurrentlyExecutedMethodFinderUnitTest.java b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/currentmethod/CurrentlyExecutedMethodFinderUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/java/currentmethod/CurrentlyExecutedMethodFinderUnitTest.java rename to core-java-modules/core-java-reflection/src/test/java/com/baeldung/currentmethod/CurrentlyExecutedMethodFinderUnitTest.java diff --git a/core-java-modules/core-java-string-operations-2/README.md b/core-java-modules/core-java-string-operations-2/README.md index 2f54aa9467..cafb3b9017 100644 --- a/core-java-modules/core-java-string-operations-2/README.md +++ b/core-java-modules/core-java-string-operations-2/README.md @@ -12,4 +12,6 @@ This module contains articles about string operations. - [L-Trim and R-Trim Alternatives in Java](https://www.baeldung.com/java-trim-alternatives) - [Java Convert PDF to Base64](https://www.baeldung.com/java-convert-pdf-to-base64) - [Encode a String to UTF-8 in Java](https://www.baeldung.com/java-string-encode-utf-8) +- [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) +- [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) #remove additional readme file - More articles: [[<-- prev]](../core-java-string-operations) diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java b/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java rename to core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/hexToAscii/HexToAsciiUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/hexToAscii/HexToAsciiUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/hexToAscii/HexToAsciiUnitTest.java rename to core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/hexToAscii/HexToAsciiUnitTest.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/hexToAscii/README.md b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/hexToAscii/README.md similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/hexToAscii/README.md rename to core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/hexToAscii/README.md diff --git a/core-java-modules/core-java-string-operations-2/src/test/resources/output.pdf b/core-java-modules/core-java-string-operations-2/src/test/resources/output.pdf new file mode 100644 index 0000000000000000000000000000000000000000..94d947797464aa493ba9634f4e5f38ad2ca4717a GIT binary patch literal 142786 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 literal 0 HcmV?d00001 diff --git a/core-java-modules/core-java-time-measurements/README.md b/core-java-modules/core-java-time-measurements/README.md index 1bd277b6b1..a3e8b71ae8 100644 --- a/core-java-modules/core-java-time-measurements/README.md +++ b/core-java-modules/core-java-time-measurements/README.md @@ -6,3 +6,4 @@ This module contains articles about the measurement of time in Java. - [Guide to the Java Clock Class](http://www.baeldung.com/java-clock) - [Measure Elapsed Time in Java](http://www.baeldung.com/java-measure-elapsed-time) - [Overriding System Time for Testing in Java](https://www.baeldung.com/java-override-system-time) +- [Java Timer](http://www.baeldung.com/java-timer-and-timertask) diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/timer/DatabaseMigrationTask.java b/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/DatabaseMigrationTask.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/timer/DatabaseMigrationTask.java rename to core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/DatabaseMigrationTask.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/timer/NewsletterTask.java b/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/timer/NewsletterTask.java rename to core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java diff --git a/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/java/clock/ClockUnitTest.java b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/clock/ClockUnitTest.java similarity index 99% rename from core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/java/clock/ClockUnitTest.java rename to core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/clock/ClockUnitTest.java index e83ba7afc8..4e34271214 100644 --- a/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/java/clock/ClockUnitTest.java +++ b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/clock/ClockUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.java.clock; +package com.baeldung.clock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/timer/DatabaseMigrationTaskUnitTest.java b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/DatabaseMigrationTaskUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/timer/DatabaseMigrationTaskUnitTest.java rename to core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/DatabaseMigrationTaskUnitTest.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/timer/JavaTimerLongRunningUnitTest.java b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/JavaTimerLongRunningUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/timer/JavaTimerLongRunningUnitTest.java rename to core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/JavaTimerLongRunningUnitTest.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java rename to core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java diff --git a/core-java-modules/core-java/README.md b/core-java-modules/core-java/README.md index 2123a61499..7781382ae5 100644 --- a/core-java-modules/core-java/README.md +++ b/core-java-modules/core-java/README.md @@ -1,44 +1,6 @@ ## Core Java Cookbooks and Examples ### Relevant Articles: -- [Java Timer](http://www.baeldung.com/java-timer-and-timertask) -- [Getting Started with Java Properties](http://www.baeldung.com/java-properties) -- [Introduction to Nashorn](http://www.baeldung.com/java-nashorn) -- [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) -- [JVM Log Forging](http://www.baeldung.com/jvm-log-forging) -- [How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null) -- [How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method) -- [Introduction to Java Serialization](http://www.baeldung.com/java-serialization) -- [Guide to UUID in Java](http://www.baeldung.com/java-uuid) -- [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) -- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) -- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) -- [Introduction to Javadoc](http://www.baeldung.com/javadoc) -- [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) -- [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) -- [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) -- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) -- [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) -- [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) -- [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) -- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) -- [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) -- [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) -- [Graphs in Java](https://www.baeldung.com/java-graphs) -- [Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output) -- [Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) -- [Retrieve Fields from a Java Class Using Reflection](https://www.baeldung.com/java-reflection-class-fields) -- [Using Curl in Java](https://www.baeldung.com/java-curl) -- [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) -- [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) -- [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) -- [Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) - - -#New module structure -########################### - -#Leave in core-java: [Getting Started with Java Properties](http://www.baeldung.com/java-properties) [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) [Introduction to Java Serialization](http://www.baeldung.com/java-serialization) @@ -49,47 +11,3 @@ [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) - -#Move to language interop (Done) -[Introduction to Nashorn](http://www.baeldung.com/java-nashorn) - -#Move to new new package: core-java-console (Done) -[Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output) -[Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) -[ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) - -#Move to core-java-string-operations-2 -[Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) -[Convert Hex to ASCII in Java](https://www.baeldung.com/java-convert-hex-to-ascii) #remove additional readme file - -#Move to core-javadatetime-operations-2 -[Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) - -#Move to core-java-time-measurements -[Java Timer](http://www.baeldung.com/java-timer-and-timertask) - -#Move to core-java-reflection -[How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method) - -#Move to core-java-streams -[How to Find all Getters Returning Null](http://www.baeldung.com/java-getters-returning-null) - -#Move to core-java-jvm -[How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) - -#Move to data-structures module -[Graphs in Java](https://www.baeldung.com/java-graphs) - -#Move to core-java-collections-3 -[Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) - -#These are already in another module -[Using Curl in Java](https://www.baeldung.com/java-curl) #Core Java Networking (Part 2) -[Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) # Core Java Sun -[Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) #Core Java Exceptions -[Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) #Core Java Exceptions -[How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) #Core Java Exceptions -[JVM Log Forging](http://www.baeldung.com/jvm-log-forging) #Core Java JVM -[Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) #Core Java Networking (Part 2) -[Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) #Core Java Exceptions -[Retrieve Fields from a Java Class Using Reflection](https://www.baeldung.com/java-reflection-class-fields) #Core Java Reflection \ No newline at end of file diff --git a/data-structures/README.md b/data-structures/README.md index f9ca78679a..e3436695ce 100644 --- a/data-structures/README.md +++ b/data-structures/README.md @@ -10,3 +10,4 @@ This module contains articles about data structures in Java - [How to Print a Binary Tree Diagram](https://www.baeldung.com/java-print-binary-tree-diagram) - [Introduction to Big Queue](https://www.baeldung.com/java-big-queue) - [Guide to AVL Trees in Java](https://www.baeldung.com/java-avl-trees) +- [Graphs in Java](https://www.baeldung.com/java-graphs) diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/graph/Graph.java b/data-structures/src/main/java/com/baeldung/graph/Graph.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/graph/Graph.java rename to data-structures/src/main/java/com/baeldung/graph/Graph.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/graph/GraphTraversal.java b/data-structures/src/main/java/com/baeldung/graph/GraphTraversal.java similarity index 100% rename from core-java-modules/core-java/src/main/java/com/baeldung/graph/GraphTraversal.java rename to data-structures/src/main/java/com/baeldung/graph/GraphTraversal.java diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/graph/GraphUnitTest.java b/data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/graph/GraphUnitTest.java rename to data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java From 4fa2ffb229c34b608657121b48eb552c9bfe7fbb Mon Sep 17 00:00:00 2001 From: "amit.pandey" Date: Sun, 7 Jun 2020 20:28:16 +0530 Subject: [PATCH 078/118] pom formatting - make artifact name same as module name --- core-java-modules/core-java-8-datetime-2/pom.xml | 3 +-- maven-all/versions-maven-plugin/original/pom.xml | 2 +- persistence-modules/r2dbc/pom.xml | 2 +- quarkus-extension/quarkus-liquibase/pom.xml | 2 +- twitter4j/pom.xml | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core-java-modules/core-java-8-datetime-2/pom.xml b/core-java-modules/core-java-8-datetime-2/pom.xml index 629ce5234d..f66a89ca55 100644 --- a/core-java-modules/core-java-8-datetime-2/pom.xml +++ b/core-java-modules/core-java-8-datetime-2/pom.xml @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - core-java-8-datetime + core-java-8-datetime-2 ${project.parent.version} core-java-8-datetime jar @@ -41,7 +41,6 @@ - core-java-datetime-java8 src/main/resources diff --git a/maven-all/versions-maven-plugin/original/pom.xml b/maven-all/versions-maven-plugin/original/pom.xml index 54140aec9b..f81596661e 100644 --- a/maven-all/versions-maven-plugin/original/pom.xml +++ b/maven-all/versions-maven-plugin/original/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - versions-maven-plugin-example + original 0.0.1-SNAPSHOT diff --git a/persistence-modules/r2dbc/pom.xml b/persistence-modules/r2dbc/pom.xml index 70ff8d6a87..b1de88e9ea 100644 --- a/persistence-modules/r2dbc/pom.xml +++ b/persistence-modules/r2dbc/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.examples.r2dbc - r2dbc-example + r2dbc 0.0.1-SNAPSHOT r2dbc Sample R2DBC Project diff --git a/quarkus-extension/quarkus-liquibase/pom.xml b/quarkus-extension/quarkus-liquibase/pom.xml index 8ed6555ed7..fdede2000e 100644 --- a/quarkus-extension/quarkus-liquibase/pom.xml +++ b/quarkus-extension/quarkus-liquibase/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.quarkus.liquibase - quarkus-liquibase-parent + quarkus-liquibase quarkus-liquibase pom diff --git a/twitter4j/pom.xml b/twitter4j/pom.xml index 274b5c75c3..0c36e72892 100644 --- a/twitter4j/pom.xml +++ b/twitter4j/pom.xml @@ -2,7 +2,7 @@ 4.0.0 - twitter4J + twitter4j twitter4J jar From ea59a08f4fa1c0df1c527d0d29bdc4d28ff78c10 Mon Sep 17 00:00:00 2001 From: Krzysiek Date: Sun, 7 Jun 2020 17:53:06 +0200 Subject: [PATCH 079/118] JAVA-1782: Remove byte-buddy dep from the main pom.xml --- parent-boot-2/pom.xml | 5 ----- pom.xml | 6 ------ 2 files changed, 11 deletions(-) diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index 631d8a0581..c7bb11b1d5 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -32,11 +32,6 @@ io.rest-assured rest-assured - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - org.springframework.boot spring-boot-starter-test diff --git a/pom.xml b/pom.xml index f797f1bbce..20adc4bfef 100644 --- a/pom.xml +++ b/pom.xml @@ -69,12 +69,6 @@ ${hamcrest-all.version} test - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - test - org.mockito mockito-core From 1a5e943886db4b0234c674605cc09504d0384784 Mon Sep 17 00:00:00 2001 From: "amit.pandey" Date: Sun, 7 Jun 2020 21:28:59 +0530 Subject: [PATCH 080/118] updated the child pom as quarkus-extension/quarkus-liquibase pom artifactId is changed --- quarkus-extension/quarkus-liquibase/deployment/pom.xml | 2 +- quarkus-extension/quarkus-liquibase/runtime/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quarkus-extension/quarkus-liquibase/deployment/pom.xml b/quarkus-extension/quarkus-liquibase/deployment/pom.xml index 5c6b56e152..d7f1f995ff 100644 --- a/quarkus-extension/quarkus-liquibase/deployment/pom.xml +++ b/quarkus-extension/quarkus-liquibase/deployment/pom.xml @@ -8,7 +8,7 @@ com.baeldung.quarkus.liquibase - quarkus-liquibase-parent + quarkus-liquibase 1.0-SNAPSHOT diff --git a/quarkus-extension/quarkus-liquibase/runtime/pom.xml b/quarkus-extension/quarkus-liquibase/runtime/pom.xml index 760e6ab719..5d3b05ef92 100644 --- a/quarkus-extension/quarkus-liquibase/runtime/pom.xml +++ b/quarkus-extension/quarkus-liquibase/runtime/pom.xml @@ -7,7 +7,7 @@ com.baeldung.quarkus.liquibase - quarkus-liquibase-parent + quarkus-liquibase 1.0-SNAPSHOT From 0ad021f13402a31a27d2204dad7d4401e6bfa3ba Mon Sep 17 00:00:00 2001 From: Krzysiek Date: Sun, 7 Jun 2020 18:17:05 +0200 Subject: [PATCH 081/118] JAVA-1782: Add byte-buddy explicitly to avoid versions confilict --- jhipster-5/bookstore-monolith/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jhipster-5/bookstore-monolith/pom.xml b/jhipster-5/bookstore-monolith/pom.xml index 233765e0f3..4e4c82f327 100644 --- a/jhipster-5/bookstore-monolith/pom.xml +++ b/jhipster-5/bookstore-monolith/pom.xml @@ -225,6 +225,12 @@ io.dropwizard.metrics metrics-core + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + From fdcf192cbe13f85507ab18e45f78c8367da5f6f5 Mon Sep 17 00:00:00 2001 From: mikr Date: Sun, 7 Jun 2020 18:17:43 +0200 Subject: [PATCH 082/118] JAVA-1522 Fix integration test for encoding package --- .../com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core-java-modules/{core-java => core-java-string-operations-2}/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java (100%) diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java similarity index 100% rename from core-java-modules/core-java/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java rename to core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java From 7b8b9390c737a12a5d6e228f0b50f7c37b5fde9d Mon Sep 17 00:00:00 2001 From: mikr Date: Sun, 7 Jun 2020 21:46:55 +0200 Subject: [PATCH 083/118] JAVA-1522 Fix integration test for encoding package (2) --- .../src/test/resources/encoding.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core-java-modules/{core-java => core-java-string-operations-2}/src/test/resources/encoding.txt (100%) diff --git a/core-java-modules/core-java/src/test/resources/encoding.txt b/core-java-modules/core-java-string-operations-2/src/test/resources/encoding.txt similarity index 100% rename from core-java-modules/core-java/src/test/resources/encoding.txt rename to core-java-modules/core-java-string-operations-2/src/test/resources/encoding.txt From a1742fc8561afa455d1de4890ecf9db4719e53c1 Mon Sep 17 00:00:00 2001 From: Krzysiek Date: Sun, 7 Jun 2020 22:48:02 +0200 Subject: [PATCH 084/118] JAVA-1782: Add byte-buddy explicitly to avoid versions confilict --- libraries-data-2/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index bdfb2c5ed6..bc2f2c77a1 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -153,6 +153,12 @@ renjin-script-engine ${renjin.version} + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + From aa5551bd9ba043060b58597bca9086db5d58accc Mon Sep 17 00:00:00 2001 From: GilvanOrnelas Date: Sun, 7 Jun 2020 19:18:58 -0300 Subject: [PATCH 085/118] Spring Import Annotation - initial commit (#9424) Co-authored-by: Gilvan Ornelas Fernandes Filho --- .../animal/AnimalConfiguration.java | 9 +++++ .../animal/AnimalScanConfiguration.java | 9 +++++ .../importannotation/animal/Bird.java | 4 +++ .../importannotation/animal/BirdConfig.java | 13 ++++++++ .../baeldung/importannotation/animal/Bug.java | 7 ++++ .../importannotation/animal/BugConfig.java | 9 +++++ .../baeldung/importannotation/animal/Cat.java | 4 +++ .../importannotation/animal/CatConfig.java | 13 ++++++++ .../baeldung/importannotation/animal/Dog.java | 4 +++ .../importannotation/animal/DogConfig.java | 13 ++++++++ .../animal/MammalConfiguration.java | 9 +++++ .../importannotation/zoo/ZooApplication.java | 11 +++++++ .../animal/AnimalConfigUnitTest.java | 31 +++++++++++++++++ .../animal/BugConfigUnitTest.java | 25 ++++++++++++++ .../animal/ConfigUnitTest.java | 31 +++++++++++++++++ .../animal/MammalConfigUnitTest.java | 33 +++++++++++++++++++ .../zoo/ZooApplicationUnitTest.java | 26 +++++++++++++++ 17 files changed, 251 insertions(+) create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalConfiguration.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalScanConfiguration.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bird.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/BirdConfig.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bug.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/BugConfig.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/Cat.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/CatConfig.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/Dog.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/DogConfig.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/animal/MammalConfiguration.java create mode 100644 spring-core-4/src/main/java/com/baeldung/importannotation/zoo/ZooApplication.java create mode 100644 spring-core-4/src/test/java/com/baeldung/importannotation/animal/AnimalConfigUnitTest.java create mode 100644 spring-core-4/src/test/java/com/baeldung/importannotation/animal/BugConfigUnitTest.java create mode 100644 spring-core-4/src/test/java/com/baeldung/importannotation/animal/ConfigUnitTest.java create mode 100644 spring-core-4/src/test/java/com/baeldung/importannotation/animal/MammalConfigUnitTest.java create mode 100644 spring-core-4/src/test/java/com/baeldung/importannotation/zoo/ZooApplicationUnitTest.java diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalConfiguration.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalConfiguration.java new file mode 100644 index 0000000000..94f22788b8 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalConfiguration.java @@ -0,0 +1,9 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import({ MammalConfiguration.class, BirdConfig.class }) +class AnimalConfiguration { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalScanConfiguration.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalScanConfiguration.java new file mode 100644 index 0000000000..9b4310b6d3 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/AnimalScanConfiguration.java @@ -0,0 +1,9 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +public class AnimalScanConfiguration { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bird.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bird.java new file mode 100644 index 0000000000..a785cf7641 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bird.java @@ -0,0 +1,4 @@ +package com.baeldung.importannotation.animal; + +class Bird { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BirdConfig.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BirdConfig.java new file mode 100644 index 0000000000..c5cefe8b22 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BirdConfig.java @@ -0,0 +1,13 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class BirdConfig { + + @Bean + Bird bird() { + return new Bird(); + } +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bug.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bug.java new file mode 100644 index 0000000000..6abe08e393 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Bug.java @@ -0,0 +1,7 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.stereotype.Component; + +@Component(value = "bug") +class Bug { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BugConfig.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BugConfig.java new file mode 100644 index 0000000000..9bea16413a --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/BugConfig.java @@ -0,0 +1,9 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import(Bug.class) +class BugConfig { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Cat.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Cat.java new file mode 100644 index 0000000000..7eb36c81ce --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Cat.java @@ -0,0 +1,4 @@ +package com.baeldung.importannotation.animal; + +class Cat { +} \ No newline at end of file diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/CatConfig.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/CatConfig.java new file mode 100644 index 0000000000..ebb35ffc11 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/CatConfig.java @@ -0,0 +1,13 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class CatConfig { + + @Bean + Cat cat() { + return new Cat(); + } +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Dog.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Dog.java new file mode 100644 index 0000000000..00374c1bc0 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/Dog.java @@ -0,0 +1,4 @@ +package com.baeldung.importannotation.animal; + +class Dog { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/DogConfig.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/DogConfig.java new file mode 100644 index 0000000000..c11ee44623 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/DogConfig.java @@ -0,0 +1,13 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class DogConfig { + + @Bean + Dog dog() { + return new Dog(); + } +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/animal/MammalConfiguration.java b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/MammalConfiguration.java new file mode 100644 index 0000000000..3d77ac878c --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/animal/MammalConfiguration.java @@ -0,0 +1,9 @@ +package com.baeldung.importannotation.animal; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import({ DogConfig.class, CatConfig.class }) +class MammalConfiguration { +} diff --git a/spring-core-4/src/main/java/com/baeldung/importannotation/zoo/ZooApplication.java b/spring-core-4/src/main/java/com/baeldung/importannotation/zoo/ZooApplication.java new file mode 100644 index 0000000000..01aa36a796 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/importannotation/zoo/ZooApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.importannotation.zoo; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import com.baeldung.importannotation.animal.AnimalScanConfiguration; + +@Configuration +@Import(AnimalScanConfiguration.class) +class ZooApplication { +} diff --git a/spring-core-4/src/test/java/com/baeldung/importannotation/animal/AnimalConfigUnitTest.java b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/AnimalConfigUnitTest.java new file mode 100644 index 0000000000..7f4795da25 --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/AnimalConfigUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.importannotation.animal; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { AnimalConfiguration.class }) +class AnimalConfigUnitTest { + + @Autowired + ApplicationContext context; + + @Test + void givenImportedBeans_whenGettingEach_shallFindOnlyTheImportedBeans() { + assertThatBeanExists("dog", Dog.class); + assertThatBeanExists("cat", Cat.class); + assertThatBeanExists("bird", Cat.class); + } + + private void assertThatBeanExists(String beanName, Class beanClass) { + assertTrue(context.containsBean(beanName)); + assertNotNull(context.getBean(beanClass)); + } +} diff --git a/spring-core-4/src/test/java/com/baeldung/importannotation/animal/BugConfigUnitTest.java b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/BugConfigUnitTest.java new file mode 100644 index 0000000000..2a2e0b332a --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/BugConfigUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.importannotation.animal; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = BugConfig.class) +class BugConfigUnitTest { + + @Autowired + ApplicationContext context; + + @Test + void givenImportInComponent_whenLookForBean_shallFindIt() { + assertTrue(context.containsBean("bug")); + assertNotNull(context.getBean(Bug.class)); + } +} diff --git a/spring-core-4/src/test/java/com/baeldung/importannotation/animal/ConfigUnitTest.java b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/ConfigUnitTest.java new file mode 100644 index 0000000000..dadd2abae6 --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/ConfigUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.importannotation.animal; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { BirdConfig.class, CatConfig.class, DogConfig.class }) +class ConfigUnitTest { + + @Autowired + ApplicationContext context; + + @Test + void givenImportedBeans_whenGettingEach_shallFindIt() { + assertThatBeanExists("dog", Dog.class); + assertThatBeanExists("cat", Cat.class); + assertThatBeanExists("bird", Bird.class); + } + + private void assertThatBeanExists(String beanName, Class beanClass) { + assertTrue(context.containsBean(beanName)); + assertNotNull(context.getBean(beanClass)); + } +} diff --git a/spring-core-4/src/test/java/com/baeldung/importannotation/animal/MammalConfigUnitTest.java b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/MammalConfigUnitTest.java new file mode 100644 index 0000000000..5e1596253c --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/importannotation/animal/MammalConfigUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.importannotation.animal; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { MammalConfiguration.class }) +class MammalConfigUnitTest { + + @Autowired + ApplicationContext context; + + @Test + void givenImportedBeans_whenGettingEach_shallFindOnlyTheImportedBeans() { + assertThatBeanExists("dog", Dog.class); + assertThatBeanExists("cat", Cat.class); + + assertFalse(context.containsBean("bird")); + } + + private void assertThatBeanExists(String beanName, Class beanClass) { + assertTrue(context.containsBean(beanName)); + assertNotNull(context.getBean(beanClass)); + } +} diff --git a/spring-core-4/src/test/java/com/baeldung/importannotation/zoo/ZooApplicationUnitTest.java b/spring-core-4/src/test/java/com/baeldung/importannotation/zoo/ZooApplicationUnitTest.java new file mode 100644 index 0000000000..e832e27b28 --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/importannotation/zoo/ZooApplicationUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.importannotation.zoo; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = ZooApplication.class) +class ZooApplicationUnitTest { + + @Autowired + ApplicationContext context; + + @Test + void givenTheScanInTheAnimalPackage_whenGettingAnyAnimal_shallFindItInTheContext() { + assertNotNull(context.getBean("dog")); + assertNotNull(context.getBean("bird")); + assertNotNull(context.getBean("cat")); + assertNotNull(context.getBean("bug")); + } +} From 2a6533cb96384b2c9aa94a52c66e8d5199263822 Mon Sep 17 00:00:00 2001 From: mikr Date: Mon, 8 Jun 2020 00:22:04 +0200 Subject: [PATCH 086/118] JAVA-101 Split Core Kotlin --- core-kotlin-modules/core-kotlin-2/README.md | 9 ----- .../core-kotlin-collections/README.md | 1 + .../com/baeldung/sorting/SortingExample.kt | 0 .../baeldung/sorting/SortingExampleKtTest.kt | 0 .../core-kotlin-datastructures/README.md | 6 ++++ .../core-kotlin-datastructures/pom.xml | 29 +++++++++++++++ .../kotlin/com/baeldung/binarytree/Main.kt | 0 .../kotlin/com/baeldung/binarytree/Node.kt | 0 .../test/kotlin/com}/binarytree/NodeTest.kt | 2 +- .../core-kotlin-date-time/README.md | 6 ++++ .../core-kotlin-date-time/pom.xml | 36 +++++++++++++++++++ .../baeldung/dates/datetime/UseDuration.kt | 0 .../baeldung/dates/datetime/UseLocalDate.kt | 0 .../dates/datetime/UseLocalDateTime.kt | 0 .../baeldung/dates/datetime/UseLocalTime.kt | 0 .../com/baeldung/dates/datetime/UsePeriod.kt | 0 .../dates/datetime/UseZonedDateTime.kt | 0 .../com/baeldung/dates/CreateDateUnitTest.kt | 0 .../com/baeldung/dates/ExtractDateUnitTest.kt | 0 .../com/baeldung/dates/FormatDateUnitTest.kt | 0 .../com/baeldung/dates/PeriodDateUnitTest.kt | 0 .../datetime/UseLocalDateTimeUnitTest.kt | 0 .../dates/datetime/UseLocalDateUnitTest.kt | 0 .../dates/datetime/UseLocalTimeUnitTest.kt | 0 .../dates/datetime/UsePeriodUnitTest.kt | 0 .../datetime/UseZonedDateTimeUnitTest.kt | 0 .../core-kotlin-design-patterns/README.md | 6 ++++ .../core-kotlin-design-patterns/pom.xml | 29 +++++++++++++++ .../kotlin/com/baeldung/builder/FoodOrder.kt | 0 .../com/baeldung/builder/FoodOrderApply.kt | 0 .../com/baeldung/builder/FoodOrderNamed.kt | 0 .../main/kotlin/com/baeldung/builder/Main.kt | 0 .../builder/BuilderPatternUnitTest.kt | 0 .../core-kotlin-lang-2/README.md | 1 + .../com/baeldung/scope/ScopeFunctions.kt | 0 .../baeldung/scope/ScopeFunctionsUnitTest.kt | 0 .../core-kotlin-testing/README.md | 6 ++++ .../pom.xml | 14 +++++--- .../kotlin/com/baeldung/junit5/Calculator.kt | 0 .../com/baeldung/junit5/CalculatorUnitTest.kt | 0 .../baeldung/junit5/DivideByZeroException.kt | 0 .../com/baeldung/junit5/SimpleUnitTest.kt | 0 core-kotlin-modules/core-kotlin/README.md | 12 ++----- .../nullassertion/NotNullAssertionUnitTest.kt | 0 .../com/baeldung/sequences/SequencesTest.kt | 0 .../baeldung/ternary/TernaryOperatorTest.kt | 0 core-kotlin-modules/pom.xml | 6 ++-- .../kotlin/com/baeldung/gson/GsonUnitTest.kt | 0 48 files changed, 136 insertions(+), 27 deletions(-) delete mode 100644 core-kotlin-modules/core-kotlin-2/README.md rename core-kotlin-modules/{core-kotlin => core-kotlin-collections}/src/main/kotlin/com/baeldung/sorting/SortingExample.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-collections}/src/test/kotlin/com/baeldung/sorting/SortingExampleKtTest.kt (100%) create mode 100644 core-kotlin-modules/core-kotlin-datastructures/README.md create mode 100644 core-kotlin-modules/core-kotlin-datastructures/pom.xml rename core-kotlin-modules/{core-kotlin => core-kotlin-datastructures}/src/main/kotlin/com/baeldung/binarytree/Main.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-datastructures}/src/main/kotlin/com/baeldung/binarytree/Node.kt (100%) rename core-kotlin-modules/{core-kotlin/src/test/kotlin/com/baeldung => core-kotlin-datastructures/src/test/kotlin/com}/binarytree/NodeTest.kt (99%) create mode 100644 core-kotlin-modules/core-kotlin-date-time/README.md create mode 100644 core-kotlin-modules/core-kotlin-date-time/pom.xml rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UseDuration.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDate.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDateTime.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UseLocalTime.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UsePeriod.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/main/kotlin/com/baeldung/dates/datetime/UseZonedDateTime.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/CreateDateUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/ExtractDateUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/FormatDateUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/PeriodDateUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateTimeUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/datetime/UseLocalTimeUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/datetime/UsePeriodUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-date-time}/src/test/kotlin/com/baeldung/dates/datetime/UseZonedDateTimeUnitTest.kt (100%) create mode 100644 core-kotlin-modules/core-kotlin-design-patterns/README.md create mode 100644 core-kotlin-modules/core-kotlin-design-patterns/pom.xml rename core-kotlin-modules/{core-kotlin => core-kotlin-design-patterns}/src/main/kotlin/com/baeldung/builder/FoodOrder.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-design-patterns}/src/main/kotlin/com/baeldung/builder/FoodOrderApply.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-design-patterns}/src/main/kotlin/com/baeldung/builder/FoodOrderNamed.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-design-patterns}/src/main/kotlin/com/baeldung/builder/Main.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-design-patterns}/src/test/kotlin/com/baeldung/builder/BuilderPatternUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-lang-2}/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-lang-2}/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt (100%) create mode 100644 core-kotlin-modules/core-kotlin-testing/README.md rename core-kotlin-modules/{core-kotlin-2 => core-kotlin-testing}/pom.xml (64%) rename core-kotlin-modules/{core-kotlin => core-kotlin-testing}/src/test/kotlin/com/baeldung/junit5/Calculator.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-testing}/src/test/kotlin/com/baeldung/junit5/CalculatorUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-testing}/src/test/kotlin/com/baeldung/junit5/DivideByZeroException.kt (100%) rename core-kotlin-modules/{core-kotlin => core-kotlin-testing}/src/test/kotlin/com/baeldung/junit5/SimpleUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin}/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin}/src/test/kotlin/com/baeldung/sequences/SequencesTest.kt (100%) rename core-kotlin-modules/{core-kotlin-2 => core-kotlin}/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt (100%) rename {core-kotlin-modules/core-kotlin => kotlin-libraries-2}/src/test/kotlin/com/baeldung/gson/GsonUnitTest.kt (100%) diff --git a/core-kotlin-modules/core-kotlin-2/README.md b/core-kotlin-modules/core-kotlin-2/README.md deleted file mode 100644 index d6d6b2f706..0000000000 --- a/core-kotlin-modules/core-kotlin-2/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## Core Kotlin 2 - -This module contains articles about Kotlin core features. - -### Relevant articles: -- [Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates) -- [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator) -- [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences) -- [[<-- Prev]](/core-kotlin-modules/core-kotlin) diff --git a/core-kotlin-modules/core-kotlin-collections/README.md b/core-kotlin-modules/core-kotlin-collections/README.md index 66f15e7419..997680c2bc 100644 --- a/core-kotlin-modules/core-kotlin-collections/README.md +++ b/core-kotlin-modules/core-kotlin-collections/README.md @@ -10,3 +10,4 @@ This module contains articles about core Kotlin collections. - [Filtering Kotlin Collections](https://www.baeldung.com/kotlin-filter-collection) - [Collection Transformations in Kotlin](https://www.baeldung.com/kotlin-collection-transformations) - [Difference between fold and reduce in Kotlin](https://www.baeldung.com/kotlin/fold-vs-reduce) +- [Guide to Sorting in Kotlin](https://www.baeldung.com/kotlin-sort) diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/sorting/SortingExample.kt b/core-kotlin-modules/core-kotlin-collections/src/main/kotlin/com/baeldung/sorting/SortingExample.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/sorting/SortingExample.kt rename to core-kotlin-modules/core-kotlin-collections/src/main/kotlin/com/baeldung/sorting/SortingExample.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/sorting/SortingExampleKtTest.kt b/core-kotlin-modules/core-kotlin-collections/src/test/kotlin/com/baeldung/sorting/SortingExampleKtTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/sorting/SortingExampleKtTest.kt rename to core-kotlin-modules/core-kotlin-collections/src/test/kotlin/com/baeldung/sorting/SortingExampleKtTest.kt diff --git a/core-kotlin-modules/core-kotlin-datastructures/README.md b/core-kotlin-modules/core-kotlin-datastructures/README.md new file mode 100644 index 0000000000..3b22730a76 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-datastructures/README.md @@ -0,0 +1,6 @@ +## Core Kotlin + +This module contains articles about data structures in Kotlin + +### Relevant articles: +[Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) diff --git a/core-kotlin-modules/core-kotlin-datastructures/pom.xml b/core-kotlin-modules/core-kotlin-datastructures/pom.xml new file mode 100644 index 0000000000..eae11c17cf --- /dev/null +++ b/core-kotlin-modules/core-kotlin-datastructures/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + core-kotlin-datastructures + core-kotlin-datastructures + jar + + + com.baeldung.core-kotlin-modules + core-kotlin-modules + 1.0.0-SNAPSHOT + + + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + + + 1.1.1 + + + \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/binarytree/Main.kt b/core-kotlin-modules/core-kotlin-datastructures/src/main/kotlin/com/baeldung/binarytree/Main.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/binarytree/Main.kt rename to core-kotlin-modules/core-kotlin-datastructures/src/main/kotlin/com/baeldung/binarytree/Main.kt diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/binarytree/Node.kt b/core-kotlin-modules/core-kotlin-datastructures/src/main/kotlin/com/baeldung/binarytree/Node.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/binarytree/Node.kt rename to core-kotlin-modules/core-kotlin-datastructures/src/main/kotlin/com/baeldung/binarytree/Node.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/binarytree/NodeTest.kt b/core-kotlin-modules/core-kotlin-datastructures/src/test/kotlin/com/binarytree/NodeTest.kt similarity index 99% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/binarytree/NodeTest.kt rename to core-kotlin-modules/core-kotlin-datastructures/src/test/kotlin/com/binarytree/NodeTest.kt index 9414d7dde9..5a7f7fc50f 100644 --- a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/binarytree/NodeTest.kt +++ b/core-kotlin-modules/core-kotlin-datastructures/src/test/kotlin/com/binarytree/NodeTest.kt @@ -1,4 +1,4 @@ -package com.baeldung.binarytree +package com.binarytree import org.junit.After import org.junit.Assert.assertEquals diff --git a/core-kotlin-modules/core-kotlin-date-time/README.md b/core-kotlin-modules/core-kotlin-date-time/README.md new file mode 100644 index 0000000000..a3e358d4e3 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-date-time/README.md @@ -0,0 +1,6 @@ +## Core Kotlin Date and Time + +This module contains articles about Kotlin core date/time features. + +### Relevant articles: +[Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates) diff --git a/core-kotlin-modules/core-kotlin-date-time/pom.xml b/core-kotlin-modules/core-kotlin-date-time/pom.xml new file mode 100644 index 0000000000..f3cacefc19 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-date-time/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + core-kotlin-date-time + core-kotlin-date-time + jar + + + com.baeldung.core-kotlin-modules + core-kotlin-modules + 1.0.0-SNAPSHOT + + + + + org.assertj + assertj-core + ${org.assertj.core.version} + test + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + + + 1.1.1 + 3.9.0 + + + \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseDuration.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseDuration.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseDuration.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseDuration.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDate.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDate.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDate.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDate.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDateTime.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDateTime.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDateTime.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalDateTime.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalTime.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalTime.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseLocalTime.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseLocalTime.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UsePeriod.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UsePeriod.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UsePeriod.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UsePeriod.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseZonedDateTime.kt b/core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseZonedDateTime.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/main/kotlin/com/baeldung/dates/datetime/UseZonedDateTime.kt rename to core-kotlin-modules/core-kotlin-date-time/src/main/kotlin/com/baeldung/dates/datetime/UseZonedDateTime.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/CreateDateUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/CreateDateUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/CreateDateUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/CreateDateUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/ExtractDateUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/ExtractDateUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/ExtractDateUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/ExtractDateUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/FormatDateUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/FormatDateUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/FormatDateUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/FormatDateUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/PeriodDateUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/PeriodDateUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/PeriodDateUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/PeriodDateUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateTimeUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateTimeUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateTimeUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateTimeUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalDateUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalTimeUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalTimeUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseLocalTimeUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseLocalTimeUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UsePeriodUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UsePeriodUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UsePeriodUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UsePeriodUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseZonedDateTimeUnitTest.kt b/core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseZonedDateTimeUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/dates/datetime/UseZonedDateTimeUnitTest.kt rename to core-kotlin-modules/core-kotlin-date-time/src/test/kotlin/com/baeldung/dates/datetime/UseZonedDateTimeUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-design-patterns/README.md b/core-kotlin-modules/core-kotlin-design-patterns/README.md new file mode 100644 index 0000000000..4bdc164a47 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-design-patterns/README.md @@ -0,0 +1,6 @@ +## Core Kotlin Design Patterns + +This module contains articles about design patterns in Kotlin + +### Relevant articles: +- [Creational Design Patterns in Kotlin: Builder](https://www.baeldung.com/kotlin-builder-pattern) diff --git a/core-kotlin-modules/core-kotlin-design-patterns/pom.xml b/core-kotlin-modules/core-kotlin-design-patterns/pom.xml new file mode 100644 index 0000000000..c112602bc2 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-design-patterns/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + core-kotlin-design-patterns + core-kotlin-design-patterns + jar + + + com.baeldung.core-kotlin-modules + core-kotlin-modules + 1.0.0-SNAPSHOT + + + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + + + 1.1.1 + + + \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrder.kt b/core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrder.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrder.kt rename to core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrder.kt diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrderApply.kt b/core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrderApply.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrderApply.kt rename to core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrderApply.kt diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrderNamed.kt b/core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrderNamed.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/FoodOrderNamed.kt rename to core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/FoodOrderNamed.kt diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/Main.kt b/core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/Main.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/builder/Main.kt rename to core-kotlin-modules/core-kotlin-design-patterns/src/main/kotlin/com/baeldung/builder/Main.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/builder/BuilderPatternUnitTest.kt b/core-kotlin-modules/core-kotlin-design-patterns/src/test/kotlin/com/baeldung/builder/BuilderPatternUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/builder/BuilderPatternUnitTest.kt rename to core-kotlin-modules/core-kotlin-design-patterns/src/test/kotlin/com/baeldung/builder/BuilderPatternUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-lang-2/README.md b/core-kotlin-modules/core-kotlin-lang-2/README.md index e64a39cb9b..76d490226f 100644 --- a/core-kotlin-modules/core-kotlin-lang-2/README.md +++ b/core-kotlin-modules/core-kotlin-lang-2/README.md @@ -10,4 +10,5 @@ This module contains articles about core features in the Kotlin language. - [Initializing Arrays in Kotlin](https://www.baeldung.com/kotlin-initialize-array) - [Lazy Initialization in Kotlin](https://www.baeldung.com/kotlin-lazy-initialization) - [Comprehensive Guide to Null Safety in Kotlin](https://www.baeldung.com/kotlin-null-safety) +- [Kotlin Scope Functions](https://www.baeldung.com/kotlin-scope-functions) - [[<-- Prev]](/core-kotlin-modules/core-kotlin-lang) diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt b/core-kotlin-modules/core-kotlin-lang-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt rename to core-kotlin-modules/core-kotlin-lang-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt b/core-kotlin-modules/core-kotlin-lang-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt rename to core-kotlin-modules/core-kotlin-lang-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-testing/README.md b/core-kotlin-modules/core-kotlin-testing/README.md new file mode 100644 index 0000000000..f4d89593a7 --- /dev/null +++ b/core-kotlin-modules/core-kotlin-testing/README.md @@ -0,0 +1,6 @@ +## Core Kotlin Testing + +This module contains articles about testing in Kotlin + +### Relevant articles: +- [JUnit 5 for Kotlin Developers](https://www.baeldung.com/junit-5-kotlin) \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin-2/pom.xml b/core-kotlin-modules/core-kotlin-testing/pom.xml similarity index 64% rename from core-kotlin-modules/core-kotlin-2/pom.xml rename to core-kotlin-modules/core-kotlin-testing/pom.xml index ae6e2d175a..d38bc62409 100644 --- a/core-kotlin-modules/core-kotlin-2/pom.xml +++ b/core-kotlin-modules/core-kotlin-testing/pom.xml @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - core-kotlin-2 - core-kotlin-2 + core-kotlin-testing + core-kotlin-testing jar @@ -15,11 +15,15 @@ - org.assertj - assertj-core - ${assertj.version} + org.junit.platform + junit-platform-runner + ${junit.platform.version} test + + 1.1.1 + + \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/Calculator.kt b/core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/Calculator.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/Calculator.kt rename to core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/Calculator.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/CalculatorUnitTest.kt b/core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/CalculatorUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/CalculatorUnitTest.kt rename to core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/CalculatorUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/DivideByZeroException.kt b/core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/DivideByZeroException.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/DivideByZeroException.kt rename to core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/DivideByZeroException.kt diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/SimpleUnitTest.kt b/core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/SimpleUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/junit5/SimpleUnitTest.kt rename to core-kotlin-modules/core-kotlin-testing/src/test/kotlin/com/baeldung/junit5/SimpleUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin/README.md b/core-kotlin-modules/core-kotlin/README.md index 90caccf5c8..48d19c987a 100644 --- a/core-kotlin-modules/core-kotlin/README.md +++ b/core-kotlin-modules/core-kotlin/README.md @@ -7,13 +7,5 @@ This module contains articles about Kotlin core features. - [Kotlin Java Interoperability](https://www.baeldung.com/kotlin-java-interoperability) - [Get a Random Number in Kotlin](https://www.baeldung.com/kotlin-random-number) - [Create a Java and Kotlin Project with Maven](https://www.baeldung.com/kotlin-maven-java-project) -- [Guide to Sorting in Kotlin](https://www.baeldung.com/kotlin-sort) -- [Creational Design Patterns in Kotlin: Builder](https://www.baeldung.com/kotlin-builder-pattern) -- [Kotlin Scope Functions](https://www.baeldung.com/kotlin-scope-functions) -- [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) -- [JUnit 5 for Kotlin Developers](https://www.baeldung.com/junit-5-kotlin) -- [Converting Kotlin Data Class from JSON using GSON](https://www.baeldung.com/kotlin-json-convert-data-class) -- [Fuel HTTP Library with Kotlin](https://www.baeldung.com/kotlin-fuel) -- [Introduction to Kovenant Library for Kotlin](https://www.baeldung.com/kotlin-kovenant) -- [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt) -- [[More --> ]](/core-kotlin-modules/core-kotlin-2) +- [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator) +- [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences) diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt b/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt rename to core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/nullassertion/NotNullAssertionUnitTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/sequences/SequencesTest.kt b/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/sequences/SequencesTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/sequences/SequencesTest.kt rename to core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/sequences/SequencesTest.kt diff --git a/core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt b/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin-2/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt rename to core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/ternary/TernaryOperatorTest.kt diff --git a/core-kotlin-modules/pom.xml b/core-kotlin-modules/pom.xml index de41aecf73..8b626e1c1b 100644 --- a/core-kotlin-modules/pom.xml +++ b/core-kotlin-modules/pom.xml @@ -18,17 +18,19 @@ core-kotlin - core-kotlin-2 core-kotlin-advanced core-kotlin-annotations core-kotlin-collections core-kotlin-concurrency + core-kotlin-date-time + core-kotlin-design-patterns core-kotlin-io core-kotlin-lang core-kotlin-lang-2 - core-kotlin-strings core-kotlin-lang-oop core-kotlin-lang-oop-2 + core-kotlin-strings + core-kotlin-testing diff --git a/core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/gson/GsonUnitTest.kt b/kotlin-libraries-2/src/test/kotlin/com/baeldung/gson/GsonUnitTest.kt similarity index 100% rename from core-kotlin-modules/core-kotlin/src/test/kotlin/com/baeldung/gson/GsonUnitTest.kt rename to kotlin-libraries-2/src/test/kotlin/com/baeldung/gson/GsonUnitTest.kt From 694261868d0eab7d9e4271e7b32bb107adbf896b Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Mon, 8 Jun 2020 12:59:01 +0530 Subject: [PATCH 087/118] JAVA-931: Migrate spring-cloud-connectors-heroku to parent-boot-2 --- .../spring-cloud-connectors-heroku/pom.xml | 14 ++++++++++---- .../connectors/heroku/book/BookController.java | 4 +++- .../cloud/connectors/heroku/book/BookService.java | 6 ++++-- .../heroku/product/ProductController.java | 4 +++- .../connectors/heroku/product/ProductService.java | 6 ++++-- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/spring-cloud/spring-cloud-connectors-heroku/pom.xml b/spring-cloud/spring-cloud-connectors-heroku/pom.xml index 1dad3ddcb7..c09a282197 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/pom.xml +++ b/spring-cloud/spring-cloud-connectors-heroku/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../parent-boot-2 @@ -35,6 +35,11 @@ org.postgresql postgresql + + net.bytebuddy + byte-buddy-dep + ${bytebuddy.version} + com.h2database h2 @@ -55,8 +60,9 @@ - Brixton.SR7 - 9.4-1201-jdbc4 + Hoxton.SR4 + 42.2.10 + 1.10.10 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookController.java b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookController.java index eb2972f35a..f998059028 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookController.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookController.java @@ -1,5 +1,7 @@ package com.baeldung.spring.cloud.connectors.heroku.book; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -15,7 +17,7 @@ public class BookController { } @GetMapping("/{bookId}") - public Book findBook(@PathVariable Long bookId) { + public Optional findBook(@PathVariable Long bookId) { return bookService.findBookById(bookId); } diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookService.java b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookService.java index 4978ded65f..a83dfe64b7 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookService.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/book/BookService.java @@ -1,5 +1,7 @@ package com.baeldung.spring.cloud.connectors.heroku.book; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -15,8 +17,8 @@ public class BookService { this.bookRepository = bookRepository; } - public Book findBookById(Long bookId) { - return bookRepository.findOne(bookId); + public Optional findBookById(Long bookId) { + return bookRepository.findById(bookId); } @Transactional(propagation = Propagation.REQUIRED) diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductController.java b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductController.java index 51cf4412bf..7875c712f9 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductController.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductController.java @@ -1,5 +1,7 @@ package com.baeldung.spring.cloud.connectors.heroku.product; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -15,7 +17,7 @@ public class ProductController { } @GetMapping("/{productId}") - public Product findProduct(@PathVariable Long productId) { + public Optional findProduct(@PathVariable Long productId) { return productService.findProductById(productId); } diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductService.java b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductService.java index f25b4ecf7b..bdd13e9863 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductService.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/java/com/baeldung/spring/cloud/connectors/heroku/product/ProductService.java @@ -1,5 +1,7 @@ package com.baeldung.spring.cloud.connectors.heroku.product; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -15,8 +17,8 @@ public class ProductService { this.productRepository = productRepository; } - public Product findProductById(Long productId) { - return productRepository.findOne(productId); + public Optional findProductById(Long productId) { + return productRepository.findById(productId); } @Transactional(propagation = Propagation.REQUIRED) From 03903e9ee50b9eabc084e8884465966a9e28a514 Mon Sep 17 00:00:00 2001 From: Krzysztof Woyke Date: Mon, 8 Jun 2020 10:35:11 +0200 Subject: [PATCH 088/118] JAVA-1782: Add byte-buddy explicitly to avoid versions confilict --- libraries-testing/pom.xml | 7 +++++++ persistence-modules/hibernate-enterprise/pom.xml | 6 ++++++ .../data-flow-server/pom.xml | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/libraries-testing/pom.xml b/libraries-testing/pom.xml index 89cb0bd494..5a5cb99238 100644 --- a/libraries-testing/pom.xml +++ b/libraries-testing/pom.xml @@ -151,6 +151,13 @@ test + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + + diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index 060cb4c904..ae58e409c4 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -55,6 +55,12 @@ hibernate-testing ${hibernate.version} + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml index ba108dc5c7..34da489cd1 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml @@ -50,6 +50,12 @@ hibernate-entitymanager ${hibernate.compatible.version} + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + From 051ed8f03511547e3714852237dd3c8acf2bde35 Mon Sep 17 00:00:00 2001 From: Ricardo Caldas Date: Mon, 8 Jun 2020 08:49:36 -0300 Subject: [PATCH 089/118] Code indentation fix --- .../JavaArraysToStringUnitTest.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java index 2c81b1358b..146e04df1a 100644 --- a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java +++ b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java @@ -12,25 +12,32 @@ import static org.junit.Assert.assertTrue; public class JavaArraysToStringUnitTest { - @Test public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() { - Object[] arrayOfObjects = { "John", 2, true }; - assertTrue(arrayOfObjects.toString().startsWith("[Ljava.lang.Object;")); - } + @Test + public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() { + Object[] arrayOfObjects = { "John", 2, true }; + assertTrue(arrayOfObjects.toString() + .startsWith("[Ljava.lang.Object;")); + } - @Test public void givenInstanceOfArray_useArraysToStringToConvert_thenValueOfObjectsAreShown() { - Object[] arrayOfObjects = { "John", 2, true }; - assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]"); - } + @Test + public void givenInstanceOfArray_useArraysToStringToConvert_thenValueOfObjectsAreShown() { + Object[] arrayOfObjects = { "John", 2, true }; + assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]"); + } - @Test public void givenInstanceOfDeepArray_userArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() { - Object[] innerArray = { "We", "Are", "Inside" }; - Object[] arrayOfObjects = { "John", 2, innerArray }; - assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]"); - } + @Test + public void givenInstanceOfDeepArray_userArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() { + Object[] innerArray = { "We", "Are", "Inside" }; + Object[] arrayOfObjects = { "John", 2, innerArray }; + assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]"); + } - @Test public void givenInstanceOfDeepArray_useStreamsToConvert_thenValueOfObjectsAreShown() { - Object[] arrayOfObjects = { "John", 2, true }; - List listOfString = Stream.of(arrayOfObjects).map(Object::toString).collect(Collectors.toList()); - assertEquals(listOfString.toString(), "[John, 2, true]"); - } + @Test + public void givenInstanceOfDeepArray_useStreamsToConvert_thenValueOfObjectsAreShown() { + Object[] arrayOfObjects = { "John", 2, true }; + List listOfString = Stream.of(arrayOfObjects) + .map(Object::toString) + .collect(Collectors.toList()); + assertEquals(listOfString.toString(), "[John, 2, true]"); + } } From c098ffa7e940490889261bf9e4918848ea12f92f Mon Sep 17 00:00:00 2001 From: Cristian Rosu Date: Mon, 8 Jun 2020 15:01:46 +0300 Subject: [PATCH 090/118] BAEL-4070: updated test names and parameter ordering + moved code to spring-boot-properties-2 --- .../lists/ListsPropertiesUnitTest.java | 34 +++++++++---------- .../SpringListPropertiesApplication.java | 0 .../src/test/resources/lists.properties | 0 3 files changed, 17 insertions(+), 17 deletions(-) rename spring-boot-modules/{spring-boot-properties => spring-boot-properties-2}/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java (61%) rename spring-boot-modules/{spring-boot-properties => spring-boot-properties-2}/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java (100%) rename spring-boot-modules/{spring-boot-properties => spring-boot-properties-2}/src/test/resources/lists.properties (100%) diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java similarity index 61% rename from spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java rename to spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java index 80cb8e9ea0..60ba4cc108 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/lists/ListsPropertiesUnitTest.java @@ -46,43 +46,43 @@ public class ListsPropertiesUnitTest { private Environment environment; @Test - public void whenContextIsInitialized_ThenInjectedArrayContainsExpectedValues() { - assertEquals(arrayOfStrings, new String[] {"Baeldung", "dot", "com"}); + public void whenContextIsInitialized_thenInjectedArrayContainsExpectedValues() { + assertEquals(new String[] {"Baeldung", "dot", "com"}, arrayOfStrings); } @Test - public void whenContextIsInitialized_ThenInjectedListContainsUnexpectedValues() { - assertEquals(unexpectedListOfStrings, Collections.singletonList("Baeldung,dot,com")); + public void whenContextIsInitialized_thenInjectedListContainsUnexpectedValues() { + assertEquals(Collections.singletonList("Baeldung,dot,com"), unexpectedListOfStrings); } @Test - public void whenContextIsInitialized_ThenInjectedListContainsExpectedValues() { - assertEquals(listOfStrings, Arrays.asList("Baeldung", "dot", "com")); + public void whenContextIsInitialized_thenInjectedListContainsExpectedValues() { + assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStrings); } @Test - public void whenContextIsInitialized_ThenInjectedListV2ContainsExpectedValues() { - assertEquals(listOfStringsV2, Arrays.asList("Baeldung", "dot", "com")); + public void whenContextIsInitialized_thenInjectedListV2ContainsExpectedValues() { + assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStringsV2); } @Test - public void whenContextIsInitialized_ThenInjectedListWithCustomDelimiterContainsExpectedValues() { - assertEquals(listOfStringsWithCustomDelimiter, Arrays.asList("Baeldung", "dot", "com")); + public void whenContextIsInitialized_thenInjectedListWithCustomDelimiterContainsExpectedValues() { + assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStringsWithCustomDelimiter); } @Test - public void whenContextIsInitialized_ThenInjectedListOfBasicTypesContainsExpectedValues() { - assertEquals(listOfBooleans, Arrays.asList(false, false, true)); - assertEquals(listOfIntegers, Arrays.asList(1, 2, 3, 4)); - assertEquals(listOfCharacters, Arrays.asList('a', 'b', 'c')); + public void whenContextIsInitialized_thenInjectedListOfBasicTypesContainsExpectedValues() { + assertEquals(Arrays.asList(false, false, true), listOfBooleans); + assertEquals(Arrays.asList(1, 2, 3, 4), listOfIntegers); + assertEquals(Arrays.asList('a', 'b', 'c'), listOfCharacters); } @Test - public void whenReadingFromSpringEnvironment_ThenPropertiesHaveExpectedValues() { + public void whenReadingFromSpringEnvironment_thenPropertiesHaveExpectedValues() { String[] arrayOfStrings = environment.getProperty("arrayOfStrings", String[].class); List listOfStrings = (List)environment.getProperty("arrayOfStrings", List.class); - assertEquals(arrayOfStrings, new String[] {"Baeldung", "dot", "com"}); - assertEquals(listOfStrings, Arrays.asList("Baeldung", "dot", "com")); + assertEquals(new String[] {"Baeldung", "dot", "com"}, arrayOfStrings); + assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStrings); } } diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java similarity index 100% rename from spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java rename to spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/lists/SpringListPropertiesApplication.java diff --git a/spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties b/spring-boot-modules/spring-boot-properties-2/src/test/resources/lists.properties similarity index 100% rename from spring-boot-modules/spring-boot-properties/src/test/resources/lists.properties rename to spring-boot-modules/spring-boot-properties-2/src/test/resources/lists.properties From facf0c3929d7140880a14b18434e83fc6ca6b749 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Mon, 8 Jun 2020 18:22:26 +0530 Subject: [PATCH 091/118] JAVA-936: Migrate spring-cloud-task to parent-boot-2 --- spring-cloud/spring-cloud-task/pom.xml | 8 ++++---- .../spring-cloud-task/springcloudtaskbatch/pom.xml | 8 ++++++++ .../src/test/resources/application.yml | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/spring-cloud/spring-cloud-task/pom.xml b/spring-cloud/spring-cloud-task/pom.xml index 377d16a999..e2006ee9d3 100644 --- a/spring-cloud/spring-cloud-task/pom.xml +++ b/spring-cloud/spring-cloud-task/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../parent-boot-2 @@ -40,8 +40,8 @@ - Brixton.SR7 - 1.2.2.RELEASE + Hoxton.SR4 + 2.2.3.RELEASE diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml index fd10322efb..4e6b8b8b6c 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml @@ -45,6 +45,13 @@ org.springframework.cloud spring-cloud-task-batch + + + net.bytebuddy + byte-buddy-dep + ${bytebuddy.version} + + com.h2database h2 @@ -63,6 +70,7 @@ com.baeldung.TaskDemo + 1.10.10 diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml index 794ac4d247..8a6e4fc172 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml @@ -1,6 +1,6 @@ spring: datasource: - url: jdbc:h2:mem:springcloud + url: jdbc:h2:mem:springcloud;DB_CLOSE_ON_EXIT=FALSE username: sa password: jpa: From db295e33871b7f2d7f728e472a62ef87405bc093 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Mon, 8 Jun 2020 18:33:45 +0530 Subject: [PATCH 092/118] JAVA-936: Migrate spring-cloud-task to parent-boot-2 --- spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml index 93255959e4..33f6ccde74 100644 --- a/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml @@ -50,8 +50,7 @@ - 1.2.2.RELEASE - 1.3.0.RELEASE + 2.3.1.RELEASE From 78d3c27e1f98df5d5acda9c11d9fff26291e21ab Mon Sep 17 00:00:00 2001 From: Ricardo Caldas Date: Mon, 8 Jun 2020 12:21:05 -0300 Subject: [PATCH 093/118] Code indentation fix --- .../baeldung/arraystostring/JavaArraysToStringUnitTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java index 146e04df1a..68cd90e7b4 100644 --- a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java +++ b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java @@ -15,8 +15,7 @@ public class JavaArraysToStringUnitTest { @Test public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() { Object[] arrayOfObjects = { "John", 2, true }; - assertTrue(arrayOfObjects.toString() - .startsWith("[Ljava.lang.Object;")); + assertTrue(arrayOfObjects.toString().startsWith("[Ljava.lang.Object;")); } @Test From 32259e7caf765879ac2a9eba2ab6c39f03ef2908 Mon Sep 17 00:00:00 2001 From: Amit Pandey Date: Tue, 9 Jun 2020 00:26:31 +0530 Subject: [PATCH 094/118] Java 1687 1 (#9450) * used password encoder over plaintext password * used password encoder over plaintext password --- .../loginextrafieldscustom/CustomUserRepository.java | 9 ++++++++- .../baeldung/loginextrafieldscustom/SecurityConfig.java | 2 ++ .../baeldung/loginextrafieldssimple/SecurityConfig.java | 2 ++ .../loginextrafieldssimple/SimpleUserRepository.java | 9 ++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/CustomUserRepository.java b/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/CustomUserRepository.java index 428c8bf532..effc750940 100644 --- a/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/CustomUserRepository.java +++ b/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/CustomUserRepository.java @@ -5,11 +5,18 @@ import java.util.Collection; import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Repository; @Repository("userRepository") public class CustomUserRepository implements UserRepository { + private PasswordEncoder passwordEncoder; + + public CustomUserRepository(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + @Override public User findUser(String username, String domain) { if (StringUtils.isAnyBlank(username, domain)) { @@ -17,7 +24,7 @@ public class CustomUserRepository implements UserRepository { } else { Collection authorities = new ArrayList<>(); User user = new User(username, domain, - "$2a$10$U3GhSMpsMSOE8Kqsbn58/edxDBKlVuYMh7qk/7ErApYFjJzi2VG5K", true, + passwordEncoder.encode("secret"), true, true, true, true, authorities); return user; } diff --git a/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/SecurityConfig.java index def85ab978..88380f1ed6 100644 --- a/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/SecurityConfig.java +++ b/spring-5-security/src/main/java/com/baeldung/loginextrafieldscustom/SecurityConfig.java @@ -1,6 +1,7 @@ package com.baeldung.loginextrafieldscustom; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -56,6 +57,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { return new SimpleUrlAuthenticationFailureHandler("/login?error=true"); } + @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } diff --git a/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SecurityConfig.java index d8c5ea8147..48ca53c0b2 100644 --- a/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SecurityConfig.java +++ b/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SecurityConfig.java @@ -1,6 +1,7 @@ package com.baeldung.loginextrafieldssimple; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -59,6 +60,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { return new SimpleUrlAuthenticationFailureHandler("/login?error=true"); } + @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } diff --git a/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SimpleUserRepository.java b/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SimpleUserRepository.java index e8aaa774a1..44929c6189 100644 --- a/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SimpleUserRepository.java +++ b/spring-5-security/src/main/java/com/baeldung/loginextrafieldssimple/SimpleUserRepository.java @@ -5,11 +5,18 @@ import java.util.Collection; import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Repository; @Repository("userRepository") public class SimpleUserRepository implements UserRepository { + private PasswordEncoder passwordEncoder; + + public SimpleUserRepository(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + @Override public User findUser(String username, String domain) { if (StringUtils.isAnyBlank(username, domain)) { @@ -17,7 +24,7 @@ public class SimpleUserRepository implements UserRepository { } else { Collection authorities = new ArrayList<>(); User user = new User(username, domain, - "$2a$10$U3GhSMpsMSOE8Kqsbn58/edxDBKlVuYMh7qk/7ErApYFjJzi2VG5K", true, + passwordEncoder.encode("secret"), true, true, true, true, authorities); return user; } From 8076eebbf8e40e659879a96fc2cacf3bd3b19e0d Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Mon, 8 Jun 2020 17:59:52 -0500 Subject: [PATCH 095/118] Bael 4082 - update README (#9465) * BAEL-3336 BAEL-3058 add links * BAEL-3319: add link * BAEL-3284: add link * BAEL-3198: add link to article * BAEL-3479: add link to article * BAEL-3485: add article link * SCALA-38: move to new package and add link back to article * SCALA-38: add imports back into unit test * BAEL-3908: add link back to article * BAEL-2893 BAEL-3927 add link back to article * BAEL-4082: add link back to article --- spring-core-4/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-core-4/README.md b/spring-core-4/README.md index 592f4cd011..11a966f23d 100644 --- a/spring-core-4/README.md +++ b/spring-core-4/README.md @@ -6,4 +6,5 @@ This module contains articles about core Spring functionality - [Creating Spring Beans Through Factory Methods](https://www.baeldung.com/spring-beans-factory-methods) - [How to dynamically Autowire a Bean in Spring](https://www.baeldung.com/spring-dynamic-autowire) +- [Spring @Import Annotation](https://www.baeldung.com/spring-import-annotation) - More articles: [[<-- prev]](/spring-core-3) From 5f55b2bbbac9989e668ae447cecdd7ee55f8176c Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Tue, 9 Jun 2020 15:01:40 +0530 Subject: [PATCH 096/118] JAVA-935: Migrate spring-cloud-stream-starters to parent-boot-2 --- .../twitterhdfs/pom.xml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/pom.xml b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/pom.xml index 1cfbf7e7c8..c9a73b9aa1 100644 --- a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/pom.xml +++ b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/pom.xml @@ -9,10 +9,10 @@ jar - com.baeldung - parent-boot-1 - 0.0.1-SNAPSHOT - ../../../parent-boot-1 + org.springframework.boot + spring-boot-starter-parent + 2.1.13.RELEASE + @@ -32,6 +32,11 @@ javax.servlet jstl + + org.springframework.boot + spring-boot-starter-test + test + @@ -45,7 +50,7 @@ - 1.3.1.RELEASE + 2.1.2.RELEASE \ No newline at end of file From c387fe5dd604120243e131636533839dc7c8212b Mon Sep 17 00:00:00 2001 From: kwoyke Date: Tue, 9 Jun 2020 21:44:45 +0200 Subject: [PATCH 097/118] BAEL-3979: Get rid of the Spring Snapshots & Milestones repos (#9434) --- .../spring-boot-kotlin/pom.xml | 38 ++----------------- .../repository/ProductRepository.kt | 7 ++-- .../repository/ProductRepositoryCoroutines.kt | 7 ++-- 3 files changed, 9 insertions(+), 43 deletions(-) diff --git a/spring-boot-modules/spring-boot-kotlin/pom.xml b/spring-boot-modules/spring-boot-kotlin/pom.xml index 79d62645da..7ee048546a 100644 --- a/spring-boot-modules/spring-boot-kotlin/pom.xml +++ b/spring-boot-modules/spring-boot-kotlin/pom.xml @@ -14,38 +14,6 @@ ../../parent-kotlin - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - org.jetbrains.kotlin @@ -142,9 +110,9 @@ 1.3.31 - 1.0.0.M1 - 1.0.0.M7 - 1.0.0.BUILD-SNAPSHOT + 1.0.0.RELEASE + 0.8.2.RELEASE + 0.8.4.RELEASE 1.2.1 diff --git a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepository.kt b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepository.kt index 20c3827c26..64ffd014ad 100644 --- a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepository.kt +++ b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepository.kt @@ -1,7 +1,7 @@ package com.baeldung.nonblockingcoroutines.repository import com.baeldung.nonblockingcoroutines.model.Product -import org.springframework.data.r2dbc.function.DatabaseClient +import org.springframework.data.r2dbc.core.DatabaseClient import org.springframework.stereotype.Repository import reactor.core.publisher.Flux import reactor.core.publisher.Mono @@ -10,7 +10,7 @@ import reactor.core.publisher.Mono class ProductRepository(private val client: DatabaseClient) { fun getProductById(id: Int): Mono { - return client.execute().sql("SELECT * FROM products WHERE id = $1") + return client.execute("SELECT * FROM products WHERE id = $1") .bind(0, id) .`as`(Product::class.java) .fetch() @@ -18,8 +18,7 @@ class ProductRepository(private val client: DatabaseClient) { } fun addNewProduct(name: String, price: Float): Mono { - return client.execute() - .sql("INSERT INTO products (name, price) VALUES($1, $2)") + return client.execute("INSERT INTO products (name, price) VALUES($1, $2)") .bind(0, name) .bind(1, price) .then() diff --git a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepositoryCoroutines.kt b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepositoryCoroutines.kt index 60a19d4d00..f2667ec033 100644 --- a/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepositoryCoroutines.kt +++ b/spring-boot-modules/spring-boot-kotlin/src/main/kotlin/com/baeldung/nonblockingcoroutines/repository/ProductRepositoryCoroutines.kt @@ -6,14 +6,14 @@ import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactive.flow.asFlow -import org.springframework.data.r2dbc.function.DatabaseClient +import org.springframework.data.r2dbc.core.DatabaseClient import org.springframework.stereotype.Repository @Repository class ProductRepositoryCoroutines(private val client: DatabaseClient) { suspend fun getProductById(id: Int): Product? = - client.execute().sql("SELECT * FROM products WHERE id = $1") + client.execute("SELECT * FROM products WHERE id = $1") .bind(0, id) .`as`(Product::class.java) .fetch() @@ -21,8 +21,7 @@ class ProductRepositoryCoroutines(private val client: DatabaseClient) { .awaitFirstOrNull() suspend fun addNewProduct(name: String, price: Float) = - client.execute() - .sql("INSERT INTO products (name, price) VALUES($1, $2)") + client.execute("INSERT INTO products (name, price) VALUES($1, $2)") .bind(0, name) .bind(1, price) .then() From 26c11b3e85981879f8248b5bdfb89a88f352e17d Mon Sep 17 00:00:00 2001 From: Mihai238 Date: Tue, 9 Jun 2020 21:49:03 +0200 Subject: [PATCH 098/118] add example for security with profiles (#9185) Co-authored-by: Mihai Lepadat --- .../baeldung/securityprofile/Application.java | 14 ++++++++++ .../ApplicationNoSecurity.java | 17 +++++++++++ .../securityprofile/ApplicationSecurity.java | 16 +++++++++++ .../securityprofile/EmployeeController.java | 16 +++++++++++ .../EmployeeControllerNoSecurityUnitTest.java | 28 +++++++++++++++++++ .../EmployeeControllerUnitTest.java | 28 +++++++++++++++++++ 6 files changed, 119 insertions(+) create mode 100644 spring-5-security/src/main/java/com/baeldung/securityprofile/Application.java create mode 100644 spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationNoSecurity.java create mode 100644 spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationSecurity.java create mode 100644 spring-5-security/src/main/java/com/baeldung/securityprofile/EmployeeController.java create mode 100644 spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerNoSecurityUnitTest.java create mode 100644 spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerUnitTest.java diff --git a/spring-5-security/src/main/java/com/baeldung/securityprofile/Application.java b/spring-5-security/src/main/java/com/baeldung/securityprofile/Application.java new file mode 100644 index 0000000000..5f17227777 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/securityprofile/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.securityprofile; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@SpringBootApplication +@EnableWebSecurity +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationNoSecurity.java b/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationNoSecurity.java new file mode 100644 index 0000000000..c899eb9268 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationNoSecurity.java @@ -0,0 +1,17 @@ +package com.baeldung.securityprofile; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@Profile("test") +public class ApplicationNoSecurity extends WebSecurityConfigurerAdapter { + + @Override + public void configure(WebSecurity web) { + web.ignoring().antMatchers("/**"); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationSecurity.java b/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationSecurity.java new file mode 100644 index 0000000000..51a8d6aa11 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/securityprofile/ApplicationSecurity.java @@ -0,0 +1,16 @@ +package com.baeldung.securityprofile; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@Profile("prod") +public class ApplicationSecurity extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().authenticated(); + } +} diff --git a/spring-5-security/src/main/java/com/baeldung/securityprofile/EmployeeController.java b/spring-5-security/src/main/java/com/baeldung/securityprofile/EmployeeController.java new file mode 100644 index 0000000000..a28a5129ca --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/securityprofile/EmployeeController.java @@ -0,0 +1,16 @@ +package com.baeldung.securityprofile; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; + +@RestController +public class EmployeeController { + + @GetMapping("/employees") + public List getEmployees() { + return Collections.singletonList("Adam Johnson"); + } +} diff --git a/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerNoSecurityUnitTest.java b/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerNoSecurityUnitTest.java new file mode 100644 index 0000000000..7112392412 --- /dev/null +++ b/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerNoSecurityUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.securityprofile; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@WebMvcTest(value = EmployeeController.class) +@ActiveProfiles("test") +public class EmployeeControllerNoSecurityUnitTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenSecurityDisabled_shouldBeOk() throws Exception { + this.mockMvc.perform(get("/employees")) + .andExpect(status().isOk()); + } + +} \ No newline at end of file diff --git a/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerUnitTest.java b/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerUnitTest.java new file mode 100644 index 0000000000..b8c8b79eb5 --- /dev/null +++ b/spring-5-security/src/test/java/com/baeldung/securityprofile/EmployeeControllerUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.securityprofile; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@WebMvcTest(value = EmployeeController.class) +@ActiveProfiles("prod") +public class EmployeeControllerUnitTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenSecurityEnabled_shouldBeForbidden() throws Exception { + this.mockMvc.perform(get("/employees")) + .andExpect(status().isForbidden()); + } + +} \ No newline at end of file From bb2d9b400ebc9f918fb3d3f3e82ced4b50ac13b2 Mon Sep 17 00:00:00 2001 From: Greg Martin Date: Tue, 9 Jun 2020 16:03:05 -0400 Subject: [PATCH 099/118] Moved Thymeleaf code into it's own package. --- .../com/baeldung/{pdf => pdfthymeleaf}/PDFThymeleafExample.java | 2 +- .../baeldung/{pdf => pdfthymeleaf}/PDFThymeleafUnitTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename pdf/src/main/java/com/baeldung/{pdf => pdfthymeleaf}/PDFThymeleafExample.java (97%) rename pdf/src/test/java/com/baeldung/{pdf => pdfthymeleaf}/PDFThymeleafUnitTest.java (98%) diff --git a/pdf/src/main/java/com/baeldung/pdf/PDFThymeleafExample.java b/pdf/src/main/java/com/baeldung/pdfthymeleaf/PDFThymeleafExample.java similarity index 97% rename from pdf/src/main/java/com/baeldung/pdf/PDFThymeleafExample.java rename to pdf/src/main/java/com/baeldung/pdfthymeleaf/PDFThymeleafExample.java index 2e1df1d320..28879b8958 100644 --- a/pdf/src/main/java/com/baeldung/pdf/PDFThymeleafExample.java +++ b/pdf/src/main/java/com/baeldung/pdfthymeleaf/PDFThymeleafExample.java @@ -1,4 +1,4 @@ -package com.baeldung.pdf; +package com.baeldung.pdfthymeleaf; import com.lowagie.text.DocumentException; import org.thymeleaf.TemplateEngine; diff --git a/pdf/src/test/java/com/baeldung/pdf/PDFThymeleafUnitTest.java b/pdf/src/test/java/com/baeldung/pdfthymeleaf/PDFThymeleafUnitTest.java similarity index 98% rename from pdf/src/test/java/com/baeldung/pdf/PDFThymeleafUnitTest.java rename to pdf/src/test/java/com/baeldung/pdfthymeleaf/PDFThymeleafUnitTest.java index e253dce06c..75d38fbf22 100644 --- a/pdf/src/test/java/com/baeldung/pdf/PDFThymeleafUnitTest.java +++ b/pdf/src/test/java/com/baeldung/pdfthymeleaf/PDFThymeleafUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.pdf; +package com.baeldung.pdfthymeleaf; import com.lowagie.text.DocumentException; import org.junit.Test; From f01c29efe0eb113f6d7586fbee3aea8065d0f0dd Mon Sep 17 00:00:00 2001 From: Kirill Vlasov Date: Wed, 10 Jun 2020 14:37:14 +0500 Subject: [PATCH 100/118] BAEL-3824 code review fixes --- .../spring-boot-mvc-3/.gitignore | 25 ------------------- .../spring-boot-mvc-3/README.md | 2 ++ 2 files changed, 2 insertions(+), 25 deletions(-) delete mode 100644 spring-boot-modules/spring-boot-mvc-3/.gitignore diff --git a/spring-boot-modules/spring-boot-mvc-3/.gitignore b/spring-boot-modules/spring-boot-mvc-3/.gitignore deleted file mode 100644 index 82eca336e3..0000000000 --- a/spring-boot-modules/spring-boot-mvc-3/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/build/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/README.md b/spring-boot-modules/spring-boot-mvc-3/README.md index 1050adb2d6..c220c6c405 100644 --- a/spring-boot-modules/spring-boot-mvc-3/README.md +++ b/spring-boot-modules/spring-boot-mvc-3/README.md @@ -3,3 +3,5 @@ This module contains articles about Spring Web MVC in Spring Boot projects. ### Relevant Articles: + +- More articles: [[prev -->]](/spring-boot-modules/spring-boot-mvc-2) \ No newline at end of file From e2fb7160107e3e205bfa9008c3da1b2e7d80879d Mon Sep 17 00:00:00 2001 From: Ricardo Caldas Date: Wed, 10 Jun 2020 08:03:34 -0300 Subject: [PATCH 101/118] change method names, move package --- .../baeldung/arrays}/JavaArraysToStringUnitTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename core-java-modules/{core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring => core-java-arrays-guides/src/test/java/com/baeldung/arrays}/JavaArraysToStringUnitTest.java (72%) diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java b/core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/arrays/JavaArraysToStringUnitTest.java similarity index 72% rename from core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java rename to core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/arrays/JavaArraysToStringUnitTest.java index 68cd90e7b4..064803465d 100644 --- a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/arraystostring/JavaArraysToStringUnitTest.java +++ b/core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/arrays/JavaArraysToStringUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.arraystostring; +package com.baeldung.arrays; import org.junit.Test; @@ -19,24 +19,24 @@ public class JavaArraysToStringUnitTest { } @Test - public void givenInstanceOfArray_useArraysToStringToConvert_thenValueOfObjectsAreShown() { + public void givenInstanceOfArray_whenUsingArraysToStringToConvert_thenValueOfObjectsAreShown() { Object[] arrayOfObjects = { "John", 2, true }; assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]"); } @Test - public void givenInstanceOfDeepArray_userArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() { + public void givenInstanceOfDeepArray_whenUsingArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() { Object[] innerArray = { "We", "Are", "Inside" }; Object[] arrayOfObjects = { "John", 2, innerArray }; assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]"); } @Test - public void givenInstanceOfDeepArray_useStreamsToConvert_thenValueOfObjectsAreShown() { + public void givenInstanceOfDeepArray_whenUsingStreamsToConvert_thenValueOfObjectsAreShown() { Object[] arrayOfObjects = { "John", 2, true }; List listOfString = Stream.of(arrayOfObjects) - .map(Object::toString) - .collect(Collectors.toList()); + .map(Object::toString) + .collect(Collectors.toList()); assertEquals(listOfString.toString(), "[John, 2, true]"); } } From 8f20c9cca45200d22860bb0b23d0539d1ac17e78 Mon Sep 17 00:00:00 2001 From: Catalin Burcea Date: Wed, 10 Jun 2020 16:15:57 +0300 Subject: [PATCH 102/118] BAEL-1362 - Retry with Spring Cloud Ribbon (#9237) --- spring-cloud/pom.xml | 1 + .../spring-cloud-ribbon-retry/pom.xml | 40 ++++++++++++++ .../ribbon-client-service/pom.xml | 39 ++++++++++++++ .../cloud/ribbon/retry/RibbonClientApp.java | 12 +++++ .../ExponentialBackoffRetryFactory.java | 26 ++++++++++ .../ExponentialRandomBackoffRetryFactory.java | 26 ++++++++++ .../backoff/FixedBackoffRetryFactory.java | 24 +++++++++ .../retry/config/RibbonConfiguration.java | 20 +++++++ .../WeatherClientRibbonConfiguration.java | 19 +++++++ .../controller/RibbonClientController.java | 21 ++++++++ .../src/main/resources/application.yml | 17 ++++++ .../RibbonRetryFailureIntegrationTest.java | 50 ++++++++++++++++++ .../RibbonRetrySuccessIntegrationTest.java | 52 +++++++++++++++++++ .../ribbon-weather-service/pom.xml | 21 ++++++++ .../ribbon/retry/RibbonWeatherServiceApp.java | 12 +++++ .../cloud/ribbon/retry/WeatherController.java | 39 ++++++++++++++ .../src/main/resources/application.properties | 2 + 17 files changed, 421 insertions(+) create mode 100644 spring-cloud/spring-cloud-ribbon-retry/pom.xml create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/pom.xml create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonClientApp.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialBackoffRetryFactory.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialRandomBackoffRetryFactory.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/FixedBackoffRetryFactory.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/RibbonConfiguration.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/WeatherClientRibbonConfiguration.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/controller/RibbonClientController.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/resources/application.yml create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetryFailureIntegrationTest.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetrySuccessIntegrationTest.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/pom.xml create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonWeatherServiceApp.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/WeatherController.java create mode 100644 spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/resources/application.properties diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index 3de527c33b..6fddb1693f 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -40,6 +40,7 @@ spring-cloud-task spring-cloud-zuul spring-cloud-zuul-fallback + spring-cloud-ribbon-retry diff --git a/spring-cloud/spring-cloud-ribbon-retry/pom.xml b/spring-cloud/spring-cloud-ribbon-retry/pom.xml new file mode 100644 index 0000000000..5318ea6913 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + com.baeldung.spring.cloud + spring-cloud-ribbon-retry + 0.0.1-SNAPSHOT + spring-cloud-ribbon-retry + pom + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + ribbon-client-service + ribbon-weather-service + + + + + + org.springframework.cloud + spring-cloud-starter-parent + ${spring-cloud.version} + pom + import + + + + + + Hoxton.SR3 + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/pom.xml b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/pom.xml new file mode 100644 index 0000000000..ad47eb6c84 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + ribbon-client-service + + + com.baeldung.spring.cloud + spring-cloud-ribbon-retry + 0.0.1-SNAPSHOT + + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.retry + spring-retry + + + com.baeldung.spring.cloud + ribbon-weather-service + 0.0.1-SNAPSHOT + test + + + + + Hoxton.SR3 + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonClientApp.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonClientApp.java new file mode 100644 index 0000000000..e06d4a93a1 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonClientApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.cloud.ribbon.retry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RibbonClientApp { + + public static void main(String[] args) { + SpringApplication.run(RibbonClientApp.class, args); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialBackoffRetryFactory.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialBackoffRetryFactory.java new file mode 100644 index 0000000000..c70ee71b7d --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialBackoffRetryFactory.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.cloud.ribbon.retry.backoff; + +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryFactory; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.retry.backoff.BackOffPolicy; +import org.springframework.retry.backoff.ExponentialBackOffPolicy; +import org.springframework.stereotype.Component; + +@Component +@Profile("exponential-backoff") +class ExponentialBackoffRetryFactory extends RibbonLoadBalancedRetryFactory { + + public ExponentialBackoffRetryFactory(SpringClientFactory clientFactory) { + super(clientFactory); + } + + @Override + public BackOffPolicy createBackOffPolicy(String service) { + ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy(); + exponentialBackOffPolicy.setInitialInterval(1000); + exponentialBackOffPolicy.setMultiplier(2); + exponentialBackOffPolicy.setMaxInterval(10000); + return exponentialBackOffPolicy; + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialRandomBackoffRetryFactory.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialRandomBackoffRetryFactory.java new file mode 100644 index 0000000000..c1fad4d1a0 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/ExponentialRandomBackoffRetryFactory.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.cloud.ribbon.retry.backoff; + +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryFactory; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.retry.backoff.BackOffPolicy; +import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy; +import org.springframework.stereotype.Component; + +@Component +@Profile("exponential-random-backoff") +class ExponentialRandomBackoffRetryFactory extends RibbonLoadBalancedRetryFactory { + + public ExponentialRandomBackoffRetryFactory(SpringClientFactory clientFactory) { + super(clientFactory); + } + + @Override + public BackOffPolicy createBackOffPolicy(String service) { + ExponentialRandomBackOffPolicy exponentialRandomBackOffPolicy = new ExponentialRandomBackOffPolicy(); + exponentialRandomBackOffPolicy.setInitialInterval(1000); + exponentialRandomBackOffPolicy.setMultiplier(2); + exponentialRandomBackOffPolicy.setMaxInterval(10000); + return exponentialRandomBackOffPolicy; + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/FixedBackoffRetryFactory.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/FixedBackoffRetryFactory.java new file mode 100644 index 0000000000..6dab5d15b4 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/backoff/FixedBackoffRetryFactory.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.cloud.ribbon.retry.backoff; + +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryFactory; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.retry.backoff.BackOffPolicy; +import org.springframework.retry.backoff.FixedBackOffPolicy; +import org.springframework.stereotype.Component; + +@Component +@Profile("fixed-backoff") +class FixedBackoffRetryFactory extends RibbonLoadBalancedRetryFactory { + + public FixedBackoffRetryFactory(SpringClientFactory clientFactory) { + super(clientFactory); + } + + @Override + public BackOffPolicy createBackOffPolicy(String service) { + FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); + fixedBackOffPolicy.setBackOffPeriod(2000); + return fixedBackOffPolicy; + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/RibbonConfiguration.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/RibbonConfiguration.java new file mode 100644 index 0000000000..c493b4dbe2 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/RibbonConfiguration.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.cloud.ribbon.retry.config; + +import com.netflix.loadbalancer.IPing; +import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.PingUrl; +import com.netflix.loadbalancer.WeightedResponseTimeRule; +import org.springframework.context.annotation.Bean; + +public class RibbonConfiguration { + + @Bean + public IPing ribbonPing() { + return new PingUrl(); + } + + @Bean + public IRule ribbonRule() { + return new WeightedResponseTimeRule(); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/WeatherClientRibbonConfiguration.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/WeatherClientRibbonConfiguration.java new file mode 100644 index 0000000000..88955db025 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/config/WeatherClientRibbonConfiguration.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.cloud.ribbon.retry.config; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +@RibbonClient(name = "weather-service", configuration = RibbonConfiguration.class) +public class WeatherClientRibbonConfiguration { + + @LoadBalanced + @Bean + RestTemplate getRestTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/controller/RibbonClientController.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/controller/RibbonClientController.java new file mode 100644 index 0000000000..ebe5b58386 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/controller/RibbonClientController.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.cloud.ribbon.retry.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +public class RibbonClientController { + + private static final String WEATHER_SERVICE = "weather-service"; + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/client/weather") + public String weather() { + String result = restTemplate.getForObject("http://" + WEATHER_SERVICE + "/weather", String.class); + return "Weather Service Response: " + result; + } +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/resources/application.yml b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/resources/application.yml new file mode 100644 index 0000000000..3199f38dce --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + profiles: + # fixed-backoff, exponential-backoff, exponential-random-backoff + active: fixed-backoff + application: + name: ribbon-client + +weather-service: + ribbon: + eureka: + enabled: false + listOfServers: http://localhost:8081, http://localhost:8082 + ServerListRefreshInterval: 5000 + MaxAutoRetries: 3 + MaxAutoRetriesNextServer: 1 + OkToRetryOnAllOperations: true + retryableStatusCodes: 503, 408 diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetryFailureIntegrationTest.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetryFailureIntegrationTest.java new file mode 100644 index 0000000000..0e72bdbb86 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetryFailureIntegrationTest.java @@ -0,0 +1,50 @@ +package com.baeldung.spring.cloud.ribbon.retry; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RibbonClientApp.class) +public class RibbonRetryFailureIntegrationTest { + + private static ConfigurableApplicationContext weatherServiceInstance1; + private static ConfigurableApplicationContext weatherServiceInstance2; + + @LocalServerPort + private int port; + private TestRestTemplate restTemplate = new TestRestTemplate(); + + @BeforeAll + public static void setup() { + weatherServiceInstance1 = startApp(8081); + weatherServiceInstance2 = startApp(8082); + } + + @AfterAll + public static void cleanup() { + weatherServiceInstance1.close(); + weatherServiceInstance2.close(); + } + + private static ConfigurableApplicationContext startApp(int port) { + return SpringApplication.run(RibbonWeatherServiceApp.class, "--server.port=" + port, "--successful.call.divisor=6"); + } + + @Test + public void whenRibbonClientIsCalledAndServiceUnavailable_thenFailure() { + String url = "http://localhost:" + port + "/client/weather"; + + ResponseEntity response = restTemplate.getForEntity(url, String.class); + + assertTrue(response.getStatusCode().is5xxServerError()); + } + +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetrySuccessIntegrationTest.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetrySuccessIntegrationTest.java new file mode 100644 index 0000000000..2055159117 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-client-service/src/test/java/com/baeldung/spring/cloud/ribbon/retry/RibbonRetrySuccessIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.spring.cloud.ribbon.retry; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RibbonClientApp.class) +public class RibbonRetrySuccessIntegrationTest { + + private static ConfigurableApplicationContext weatherServiceInstance1; + private static ConfigurableApplicationContext weatherServiceInstance2; + + @LocalServerPort + private int port; + private TestRestTemplate restTemplate = new TestRestTemplate(); + + @BeforeAll + public static void setup() { + weatherServiceInstance1 = startApp(8081); + weatherServiceInstance2 = startApp(8082); + } + + private static ConfigurableApplicationContext startApp(int port) { + return SpringApplication.run(RibbonWeatherServiceApp.class, "--server.port=" + port, "--successful.call.divisor=3"); + } + + @AfterAll + public static void cleanup() { + weatherServiceInstance1.close(); + weatherServiceInstance2.close(); + } + + @Test + public void whenRibbonClientIsCalledAndServiceAvailable_thenSuccess() { + String url = "http://localhost:" + port + "/client/weather"; + + ResponseEntity response = restTemplate.getForEntity(url, String.class); + + assertTrue(response.getStatusCode().is2xxSuccessful()); + assertEquals(response.getBody(), "Weather Service Response: Today's a sunny day"); + } + +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/pom.xml b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/pom.xml new file mode 100644 index 0000000000..f091341025 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + ribbon-weather-service + + + com.baeldung.spring.cloud + spring-cloud-ribbon-retry + 0.0.1-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonWeatherServiceApp.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonWeatherServiceApp.java new file mode 100644 index 0000000000..ceeacbd426 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/RibbonWeatherServiceApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.cloud.ribbon.retry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RibbonWeatherServiceApp { + + public static void main(String[] args) { + SpringApplication.run(RibbonWeatherServiceApp.class, args); + } +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/WeatherController.java b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/WeatherController.java new file mode 100644 index 0000000000..ec0b94e505 --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/java/com/baeldung/spring/cloud/ribbon/retry/WeatherController.java @@ -0,0 +1,39 @@ +package com.baeldung.spring.cloud.ribbon.retry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WeatherController { + + private static final Logger LOGGER = LoggerFactory.getLogger(WeatherController.class); + + private int nrOfCalls = 0; + + @Value("${successful.call.divisor}") + private int divisor; + + @GetMapping("/") + public String health() { + return "I am Ok"; + } + + @GetMapping("/weather") + public ResponseEntity weather() { + LOGGER.info("Providing today's weather information"); + if (isServiceUnavailable()) { + return new ResponseEntity<>(HttpStatus.SERVICE_UNAVAILABLE); + } + LOGGER.info("Today's a sunny day"); + return new ResponseEntity<>("Today's a sunny day", HttpStatus.OK); + } + + private boolean isServiceUnavailable() { + return ++nrOfCalls % divisor != 0; + } +} diff --git a/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/resources/application.properties b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/resources/application.properties new file mode 100644 index 0000000000..ea25e8f2da --- /dev/null +++ b/spring-cloud/spring-cloud-ribbon-retry/ribbon-weather-service/src/main/resources/application.properties @@ -0,0 +1,2 @@ +spring.application.name=weather-service +successful.call.divisor=3 From 265bfbfe103156818f8846f22eb5bb40c3597cfc Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Wed, 10 Jun 2020 19:14:45 +0530 Subject: [PATCH 103/118] JAVA-622: Moved code from core-java-lang to core-java-lang-oop-types --- .../src/main/java/com/baeldung/enums/values/Element1.java | 0 .../src/main/java/com/baeldung/enums/values/Element2.java | 0 .../src/main/java/com/baeldung/enums/values/Element3.java | 0 .../src/main/java/com/baeldung/enums/values/Element4.java | 0 .../src/main/java/com/baeldung/enums/values/Labeled.java | 0 .../test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java | 0 .../java/com/baeldung/enums/iteration/EnumIterationExamples.java | 0 .../src/test/java/com/baeldung/enums/values/Element1UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element2UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element3UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element4UnitTest.java | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/values/Element1.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/values/Element2.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/values/Element3.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/values/Element4.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/values/Labeled.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/iteration/EnumIterationExamples.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/values/Element1UnitTest.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/values/Element2UnitTest.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/values/Element3UnitTest.java (100%) rename core-java-modules/{core-java-lang => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/values/Element4UnitTest.java (100%) diff --git a/core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element1.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element1.java similarity index 100% rename from core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element1.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element1.java diff --git a/core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element2.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element2.java similarity index 100% rename from core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element2.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element2.java diff --git a/core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element3.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element3.java similarity index 100% rename from core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element3.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element3.java diff --git a/core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element4.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element4.java similarity index 100% rename from core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Element4.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Element4.java diff --git a/core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Labeled.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Labeled.java similarity index 100% rename from core-java-modules/core-java-lang/src/main/java/com/baeldung/enums/values/Labeled.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/values/Labeled.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/iteration/DaysOfWeekEnum.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/iteration/EnumIterationExamples.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/iteration/EnumIterationExamples.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/iteration/EnumIterationExamples.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/iteration/EnumIterationExamples.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element1UnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element1UnitTest.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element1UnitTest.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element1UnitTest.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element2UnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element2UnitTest.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element2UnitTest.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element2UnitTest.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element3UnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element3UnitTest.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element3UnitTest.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element3UnitTest.java diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element4UnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element4UnitTest.java similarity index 100% rename from core-java-modules/core-java-lang/src/test/java/com/baeldung/enums/values/Element4UnitTest.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/values/Element4UnitTest.java From da319363e8ca7b0ffe3a938eab9dfa0ee36c9c4b Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Wed, 10 Jun 2020 19:16:13 +0530 Subject: [PATCH 104/118] JAVA-622: Move from core-java-lang-syntax to core-java-lang-oop-types --- .../src/main/java/com/baeldung/enums/Pizza.java | 0 .../src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java | 0 .../java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java | 0 .../src/test/java/com/baeldung/enums/PizzaUnitTest.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename core-java-modules/{core-java-lang-syntax => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/Pizza.java (100%) rename core-java-modules/{core-java-lang-syntax => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java (100%) rename core-java-modules/{core-java-lang-syntax => core-java-lang-oop-types}/src/main/java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java (100%) rename core-java-modules/{core-java-lang-syntax => core-java-lang-oop-types}/src/test/java/com/baeldung/enums/PizzaUnitTest.java (100%) diff --git a/core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/Pizza.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java similarity index 100% rename from core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/Pizza.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java diff --git a/core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java similarity index 100% rename from core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/PizzaDeliveryStrategy.java diff --git a/core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java similarity index 100% rename from core-java-modules/core-java-lang-syntax/src/main/java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java rename to core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/PizzaDeliverySystemConfiguration.java diff --git a/core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/enums/PizzaUnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java similarity index 100% rename from core-java-modules/core-java-lang-syntax/src/test/java/com/baeldung/enums/PizzaUnitTest.java rename to core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java From b90191c5bc68f8a01f425512be89c85cc99d984e Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Wed, 10 Jun 2020 19:17:01 +0530 Subject: [PATCH 105/118] JAVA-622: readme changes, moved all enum articles to core-java-lang-oop-types --- core-java-modules/core-java-lang-oop-types/README.md | 3 +++ core-java-modules/core-java-lang/README.md | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core-java-modules/core-java-lang-oop-types/README.md b/core-java-modules/core-java-lang-oop-types/README.md index 80344c70fa..449a0f59cc 100644 --- a/core-java-modules/core-java-lang-oop-types/README.md +++ b/core-java-modules/core-java-lang-oop-types/README.md @@ -7,3 +7,6 @@ This module contains articles about types in Java - [Guide to the this Java Keyword](https://www.baeldung.com/java-this) - [Nested Classes in Java](https://www.baeldung.com/java-nested-classes) - [Marker Interfaces in Java](https://www.baeldung.com/java-marker-interfaces) +- [Iterating Over Enum Values in Java](https://www.baeldung.com/java-enum-iteration) +- [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values) +- [A Guide to Java Enums](https://www.baeldung.com/a-guide-to-java-enums) diff --git a/core-java-modules/core-java-lang/README.md b/core-java-modules/core-java-lang/README.md index 9e98bb849b..9166b93b7f 100644 --- a/core-java-modules/core-java-lang/README.md +++ b/core-java-modules/core-java-lang/README.md @@ -4,7 +4,6 @@ This module contains articles about core features in the Java language ### Relevant Articles: - [Generate equals() and hashCode() with Eclipse](https://www.baeldung.com/java-eclipse-equals-and-hashcode) -- [Iterating Over Enum Values in Java](https://www.baeldung.com/java-enum-iteration) - [Comparator and Comparable in Java](https://www.baeldung.com/java-comparator-comparable) - [Recursion In Java](https://www.baeldung.com/java-recursion) - [A Guide to the finalize Method in Java](https://www.baeldung.com/java-finalize) @@ -12,8 +11,6 @@ This module contains articles about core features in the Java language - [Using Java Assertions](https://www.baeldung.com/java-assert) - [Synthetic Constructs in Java](https://www.baeldung.com/java-synthetic) - [Retrieving a Class Name in Java](https://www.baeldung.com/java-class-name) -- [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values) - [The Java continue and break Keywords](https://www.baeldung.com/java-continue-and-break) -- [A Guide to Java Enums](https://www.baeldung.com/a-guide-to-java-enums) - [Infinite Loops in Java](https://www.baeldung.com/infinite-loops-java) - [[More --> ]](/core-java-modules/core-java-lang-2) From 2b928b04ce9ee002e3a515129444e7b59442b96d Mon Sep 17 00:00:00 2001 From: Usman Mohyuddin Date: Wed, 10 Jun 2020 20:21:22 +0500 Subject: [PATCH 106/118] Dev determine groovy datatype (#9235) * add code files for "How to groovy data types" add code files for "How to groovy data types" * added Tests in example * Update pom.xml change tab into spaces * remove the package determine-datatype as per comments * Update pom.xml add dependency for tests * remvoe the unwanted junit5 dependency and refine the structure of code remvoe the unwanted junit5 dependency and refine the structure of code * add missing "()" * correct the package as per sugesstion --- .../baeldung/determinedatatype/Person.groovy | 14 +++++ .../determinedatatype/PersonTest.groovy | 56 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy create mode 100644 core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy diff --git a/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy b/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy new file mode 100644 index 0000000000..3ac88b7952 --- /dev/null +++ b/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy @@ -0,0 +1,14 @@ +package com.baeldung.determinedatatype + +class Person { + + private int ageAsInt + private Double ageAsDouble + private String ageAsString + + Person() {} + Person(int ageAsInt) { this.ageAsInt = ageAsInt} + Person(Double ageAsDouble) { this.ageAsDouble = ageAsDouble} + Person(String ageAsString) { this.ageAsString = ageAsString} +} +class Student extends Person {} diff --git a/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy new file mode 100644 index 0000000000..4c6589f207 --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy @@ -0,0 +1,56 @@ +package com.baeldung.determinedatatype + +import org.junit.Assert +import org.junit.Test +import com.baeldung.determinedatatype.Person + +public class PersonTest { + + @Test + public void givenWhenParameterTypeIsInteger_thenReturnTrue() { + Person personObj = new Person(10) + Assert.assertTrue(personObj.ageAsInt instanceof Integer) + } + + @Test + public void givenWhenParameterTypeIsDouble_thenReturnTrue() { + Person personObj = new Person(10.0) + Assert.assertTrue((personObj.ageAsDouble).getClass() == Double) + } + + @Test + public void givenWhenParameterTypeIsString_thenReturnTrue() { + Person personObj = new Person("10 years") + Assert.assertTrue(personObj.ageAsString.class == String) + } + + @Test + public void givenClassName_WhenParameterIsInteger_thenReturnTrue() { + Assert.assertTrue(Person.class.getDeclaredField('ageAsInt').type == int.class) + } + + @Test + public void givenWhenObjectIsInstanceOfType_thenReturnTrue() { + Person personObj = new Person() + Assert.assertTrue(personObj instanceof Person) + } + + @Test + public void givenWhenInstanceIsOfSubtype_thenReturnTrue() { + Student studentObj = new Student() + Assert.assertTrue(studentObj in Person) + } + + @Test + public void givenGroovyList_WhenFindClassName_thenReturnTrue() { + def ageList = ['ageAsString','ageAsDouble', 10] + Assert.assertTrue(ageList.class == ArrayList) + Assert.assertTrue(ageList.getClass() == ArrayList) + } + + @Test + public void givenGrooyMap_WhenFindClassName_thenReturnTrue() { + def ageMap = [ageAsString: '10 years', ageAsDouble: 10.0] + Assert.assertFalse(ageMap.class == LinkedHashMap) + } +} \ No newline at end of file From 5d9b41411d0682f3e5dff0f7667fdeebd3b76fbb Mon Sep 17 00:00:00 2001 From: Anshul BANSAL Date: Thu, 11 Jun 2020 07:34:34 +0300 Subject: [PATCH 107/118] bcel version updated --- core-java-modules/core-java-jvm/pom.xml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index a2c35c154c..5e731363ae 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -54,31 +54,28 @@ org.ow2.asm asm - 8.0.1 + ${asm.version} org.ow2.asm asm-util - 8.0.1 + ${asm.version} org.apache.bcel bcel - 6.4.1 - - - org.javassist - javassist - 3.27.0-GA - + ${bcel.version} + 3.6.1 - 3.21.0-GA + 3.27.0-GA 2.1.0.1 1.8.0 + 8.0.1 + 6.5.0 From 1bd8a0b90c58753bd290a000d2ac163f5f6cea4d Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Thu, 11 Jun 2020 12:39:13 +0100 Subject: [PATCH 108/118] BAEL-4041: Simulate playing 2048 (#9439) * Set up the ability to play the game * Actually able to play the game --- .../baeldung/algorithms/play2048/Board.java | 208 ++++++++++++++++++ .../baeldung/algorithms/play2048/Cell.java | 26 +++ .../algorithms/play2048/Computer.java | 27 +++ .../baeldung/algorithms/play2048/Human.java | 126 +++++++++++ .../baeldung/algorithms/play2048/Move.java | 8 + .../algorithms/play2048/Play2048.java | 73 ++++++ 6 files changed, 468 insertions(+) create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Board.java create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Cell.java create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Computer.java create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Human.java create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Move.java create mode 100644 algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Play2048.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Board.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Board.java new file mode 100644 index 0000000000..ddb5901682 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Board.java @@ -0,0 +1,208 @@ +package com.baeldung.algorithms.play2048; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Board { + private static final Logger LOG = LoggerFactory.getLogger(Board.class); + + private final int[][] board; + + private final int score; + + public Board(int size) { + assert(size > 0); + + this.board = new int[size][]; + this.score = 0; + + for (int x = 0; x < size; ++x) { + this.board[x] = new int[size]; + for (int y = 0; y < size; ++y) { + board[x][y] = 0; + } + } + } + + private Board(int[][] board, int score) { + this.score = score; + this.board = new int[board.length][]; + + for (int x = 0; x < board.length; ++x) { + this.board[x] = Arrays.copyOf(board[x], board[x].length); + } + } + + public int getSize() { + return board.length; + } + + public int getScore() { + return score; + } + + public int getCell(Cell cell) { + int x = cell.getX(); + int y = cell.getY(); + assert(x >= 0 && x < board.length); + assert(y >= 0 && y < board.length); + + return board[x][y]; + } + + public boolean isEmpty(Cell cell) { + return getCell(cell) == 0; + } + + public List emptyCells() { + List result = new ArrayList<>(); + for (int x = 0; x < board.length; ++x) { + for (int y = 0; y < board[x].length; ++y) { + Cell cell = new Cell(x, y); + if (isEmpty(cell)) { + result.add(cell); + } + } + } + return result; + } + + public Board placeTile(Cell cell, int number) { + if (!isEmpty(cell)) { + throw new IllegalArgumentException("That cell is not empty"); + } + + Board result = new Board(this.board, this.score); + result.board[cell.getX()][cell.getY()] = number; + return result; + } + + public Board move(Move move) { + // Clone the board + int[][] tiles = new int[this.board.length][]; + for (int x = 0; x < this.board.length; ++x) { + tiles[x] = Arrays.copyOf(this.board[x], this.board[x].length); + } + + LOG.debug("Before move: {}", Arrays.deepToString(tiles)); + // If we're doing an Left/Right move then transpose the board to make it a Up/Down move + if (move == Move.LEFT || move == Move.RIGHT) { + tiles = transpose(tiles); + LOG.debug("After transpose: {}", Arrays.deepToString(tiles)); + } + // If we're doing a Right/Down move then reverse the board. + // With the above we're now always doing an Up move + if (move == Move.DOWN || move == Move.RIGHT) { + tiles = reverse(tiles); + LOG.debug("After reverse: {}", Arrays.deepToString(tiles)); + } + LOG.debug("Ready to move: {}", Arrays.deepToString(tiles)); + + // Shift everything up + int[][] result = new int[tiles.length][]; + int newScore = 0; + for (int x = 0; x < tiles.length; ++x) { + LinkedList thisRow = new LinkedList<>(); + for (int y = 0; y < tiles[0].length; ++y) { + if (tiles[x][y] > 0) { + thisRow.add(tiles[x][y]); + } + } + + LOG.debug("Unmerged row: {}", thisRow); + LinkedList newRow = new LinkedList<>(); + while (thisRow.size() >= 2) { + int first = thisRow.pop(); + int second = thisRow.peek(); + LOG.debug("Looking at numbers {} and {}", first, second); + if (second == first) { + LOG.debug("Numbers match, combining"); + int newNumber = first * 2; + newRow.add(newNumber); + newScore += newNumber; + thisRow.pop(); + } else { + LOG.debug("Numbers don't match"); + newRow.add(first); + } + } + newRow.addAll(thisRow); + LOG.debug("Merged row: {}", newRow); + + result[x] = new int[tiles[0].length]; + for (int y = 0; y < tiles[0].length; ++y) { + if (newRow.isEmpty()) { + result[x][y] = 0; + } else { + result[x][y] = newRow.pop(); + } + } + } + LOG.debug("After moves: {}", Arrays.deepToString(result)); + + // Un-reverse the board + if (move == Move.DOWN || move == Move.RIGHT) { + result = reverse(result); + LOG.debug("After reverse: {}", Arrays.deepToString(result)); + } + // Un-transpose the board + if (move == Move.LEFT || move == Move.RIGHT) { + result = transpose(result); + LOG.debug("After transpose: {}", Arrays.deepToString(result)); + } + return new Board(result, this.score + newScore); + } + + private static int[][] transpose(int[][] input) { + int[][] result = new int[input.length][]; + + for (int x = 0; x < input.length; ++x) { + result[x] = new int[input[0].length]; + for (int y = 0; y < input[0].length; ++y) { + result[x][y] = input[y][x]; + } + } + + return result; + } + + private static int[][] reverse(int[][] input) { + int[][] result = new int[input.length][]; + + for (int x = 0; x < input.length; ++x) { + result[x] = new int[input[0].length]; + for (int y = 0; y < input[0].length; ++y) { + result[x][y] = input[x][input.length - y - 1]; + } + } + + return result; + } + + @Override + public String toString() { + return Arrays.deepToString(board); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Board board1 = (Board) o; + return Arrays.deepEquals(board, board1.board); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(board); + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Cell.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Cell.java new file mode 100644 index 0000000000..98ee23ac90 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Cell.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.play2048; + +import java.util.StringJoiner; + +public class Cell { + private int x; + private int y; + + public Cell(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + @Override + public String toString() { + return new StringJoiner(", ", Cell.class.getSimpleName() + "[", "]").add("x=" + x).add("y=" + y).toString(); + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Computer.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Computer.java new file mode 100644 index 0000000000..5ef1d04368 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Computer.java @@ -0,0 +1,27 @@ +package com.baeldung.algorithms.play2048; + +import java.security.SecureRandom; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Computer { + private static final Logger LOG = LoggerFactory.getLogger(Computer.class); + + private final SecureRandom rng = new SecureRandom(); + + public Board makeMove(Board input) { + List emptyCells = input.emptyCells(); + LOG.info("Number of empty cells: {}", emptyCells.size()); + + double numberToPlace = rng.nextDouble(); + LOG.info("New number probability: {}", numberToPlace); + + int indexToPlace = rng.nextInt(emptyCells.size()); + Cell cellToPlace = emptyCells.get(indexToPlace); + LOG.info("Placing number into empty cell: {}", cellToPlace); + + return input.placeTile(cellToPlace, numberToPlace >= 0.9 ? 4 : 2); + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Human.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Human.java new file mode 100644 index 0000000000..d1b32f0309 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Human.java @@ -0,0 +1,126 @@ +package com.baeldung.algorithms.play2048; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.math3.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Human { + private static final Logger LOG = LoggerFactory.getLogger(Human.class); + + public Board makeMove(Board input) { + // For each move in MOVE + // Generate board from move + // Generate Score for Board + // Return board with the best score + // + // Generate Score + // If Depth Limit + // Return Final Score + // Total Score = 0 + // For every empty square in new board + // Generate board with "2" in square + // Calculate Score + // Total Score += (Score * 0.9) + // Generate board with "4" in square + // Calculate Score + // Total Score += (Score * 0.1) + // + // Calculate Score + // For each move in MOVE + // Generate board from move + // Generate score for board + // Return the best generated score + + return Arrays.stream(Move.values()) + .parallel() + .map(input::move) + .filter(board -> !board.equals(input)) + .max(Comparator.comparingInt(board -> generateScore(board, 0))) + .orElse(input); + } + + private int generateScore(Board board, int depth) { + if (depth >= 3) { + int finalScore = calculateFinalScore(board); + LOG.debug("Final score for board {}: {}", board,finalScore); + return finalScore; + } + + return board.emptyCells().stream() + .parallel() + .flatMap(cell -> Stream.of(new Pair<>(cell, 2), new Pair<>(cell, 4))) + .mapToInt(move -> { + LOG.debug("Simulating move {} at depth {}", move, depth); + Board newBoard = board.placeTile(move.getFirst(), move.getSecond()); + int boardScore = calculateScore(newBoard, depth + 1); + int calculatedScore = (int) (boardScore * (move.getSecond() == 2 ? 0.9 : 0.1)); + LOG.debug("Calculated score for board {} and move {} at depth {}: {}", newBoard, move, depth, calculatedScore); + return calculatedScore; + }) + .sum(); + } + + private int calculateScore(Board board, int depth) { + return Arrays.stream(Move.values()) + .parallel() + .map(board::move) + .filter(moved -> !moved.equals(board)) + .mapToInt(newBoard -> generateScore(newBoard, depth)) + .max() + .orElse(0); + } + + private int calculateFinalScore(Board board) { + List> rowsToScore = new ArrayList<>(); + for (int i = 0; i < board.getSize(); ++i) { + List row = new ArrayList<>(); + List col = new ArrayList<>(); + + for (int j = 0; j < board.getSize(); ++j) { + row.add(board.getCell(new Cell(i, j))); + col.add(board.getCell(new Cell(j, i))); + } + + rowsToScore.add(row); + rowsToScore.add(col); + } + + return rowsToScore.stream() + .parallel() + .mapToInt(row -> { + List preMerged = row.stream() + .filter(value -> value != 0) + .collect(Collectors.toList()); + + int numMerges = 0; + int monotonicityLeft = 0; + int monotonicityRight = 0; + for (int i = 0; i < preMerged.size() - 1; ++i) { + Integer first = preMerged.get(i); + Integer second = preMerged.get(i + 1); + if (first.equals(second)) { + ++numMerges; + } else if (first > second) { + monotonicityLeft += first - second; + } else { + monotonicityRight += second - first; + } + } + + int score = 1000; + score += 250 * row.stream().filter(value -> value == 0).count(); + score += 750 * numMerges; + score -= 10 * row.stream().mapToInt(value -> value).sum(); + score -= 50 * Math.min(monotonicityLeft, monotonicityRight); + return score; + }) + .sum(); + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Move.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Move.java new file mode 100644 index 0000000000..8678cec833 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Move.java @@ -0,0 +1,8 @@ +package com.baeldung.algorithms.play2048; + +public enum Move { + UP, + DOWN, + LEFT, + RIGHT +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Play2048.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Play2048.java new file mode 100644 index 0000000000..ec5b3dca40 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/play2048/Play2048.java @@ -0,0 +1,73 @@ +package com.baeldung.algorithms.play2048; + +public class Play2048 { + private static final int SIZE = 3; + private static final int INITIAL_NUMBERS = 2; + + public static void main(String[] args) { + // The board and players + Board board = new Board(SIZE); + Computer computer = new Computer(); + Human human = new Human(); + + // The computer has two moves first + System.out.println("Setup"); + System.out.println("====="); + for (int i = 0; i < INITIAL_NUMBERS; ++i) { + board = computer.makeMove(board); + } + + printBoard(board); + do { + board = human.makeMove(board); + System.out.println("Human move"); + System.out.println("=========="); + printBoard(board); + + board = computer.makeMove(board); + System.out.println("Computer move"); + System.out.println("============="); + printBoard(board); + } while (!board.emptyCells().isEmpty()); + + System.out.println("Final Score: " + board.getScore()); + + } + + private static void printBoard(Board board) { + StringBuilder topLines = new StringBuilder(); + StringBuilder midLines = new StringBuilder(); + for (int x = 0; x < board.getSize(); ++x) { + topLines.append("+--------"); + midLines.append("| "); + } + topLines.append("+"); + midLines.append("|"); + + + for (int y = 0; y < board.getSize(); ++y) { + System.out.println(topLines); + System.out.println(midLines); + for (int x = 0; x < board.getSize(); ++x) { + Cell cell = new Cell(x, y); + System.out.print("|"); + if (board.isEmpty(cell)) { + System.out.print(" "); + } else { + StringBuilder output = new StringBuilder(Integer.toString(board.getCell(cell))); + while (output.length() < 8) { + output.append(" "); + if (output.length() < 8) { + output.insert(0, " "); + } + } + System.out.print(output); + } + } + System.out.println("|"); + System.out.println(midLines); + } + System.out.println(topLines); + System.out.println("Score: " + board.getScore()); + } +} From d804f6b2944db819c5aa6b3d167e6a1080305330 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Thu, 11 Jun 2020 18:59:09 +0530 Subject: [PATCH 109/118] JAVA-938: Migrate spring-cloud-data-flow to parent-boot-2 --- spring-cloud-data-flow/apache-spark-job/pom.xml | 10 ---------- .../com/baeldung/spring/cloud/PiApproximation.java | 2 +- spring-cloud-data-flow/batch-job/pom.xml | 10 ++++------ spring-cloud-data-flow/pom.xml | 5 +++-- .../customer-mongodb-sink/pom.xml | 5 ++--- .../customer-transform/pom.xml | 5 ++--- 6 files changed, 12 insertions(+), 25 deletions(-) diff --git a/spring-cloud-data-flow/apache-spark-job/pom.xml b/spring-cloud-data-flow/apache-spark-job/pom.xml index 65a57671ea..a4816a30ba 100644 --- a/spring-cloud-data-flow/apache-spark-job/pom.xml +++ b/spring-cloud-data-flow/apache-spark-job/pom.xml @@ -22,16 +22,6 @@ org.apache.spark spark-core_${scala.version} ${spark.version} - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - diff --git a/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java index dfead21728..3f7c3be678 100644 --- a/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java +++ b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java @@ -13,7 +13,7 @@ import java.util.stream.IntStream; public class PiApproximation { public static void main(String[] args) { - SparkConf conf = new SparkConf().setAppName("BaeldungPIApproximation"); + SparkConf conf = new SparkConf().setAppName("BaeldungPIApproximation").setMaster("local[2]"); JavaSparkContext context = new JavaSparkContext(conf); int slices = args.length >= 1 ? Integer.valueOf(args[0]) : 2; int n = (100000L * slices) > Integer.MAX_VALUE ? Integer.MAX_VALUE : 100000 * slices; diff --git a/spring-cloud-data-flow/batch-job/pom.xml b/spring-cloud-data-flow/batch-job/pom.xml index e11df0df8e..6b02b000e1 100644 --- a/spring-cloud-data-flow/batch-job/pom.xml +++ b/spring-cloud-data-flow/batch-job/pom.xml @@ -11,9 +11,8 @@ com.baeldung - parent-boot-1 + spring-cloud-data-flow 0.0.1-SNAPSHOT - ../../parent-boot-1 @@ -21,7 +20,7 @@ org.springframework.cloud spring-cloud-dependencies - Brixton.SR5 + Hoxton.SR4 pom import @@ -31,8 +30,7 @@ org.springframework.cloud - spring-cloud-task-starter - ${spring-cloud-task-starter.version} + spring-cloud-starter-task @@ -48,7 +46,7 @@ - 1.0.3.RELEASE + 2.2.3.RELEASE diff --git a/spring-cloud-data-flow/pom.xml b/spring-cloud-data-flow/pom.xml index e2a0664f30..5b516146ae 100644 --- a/spring-cloud-data-flow/pom.xml +++ b/spring-cloud-data-flow/pom.xml @@ -9,8 +9,9 @@ com.baeldung - parent-modules - 1.0.0-SNAPSHOT + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-mongodb-sink/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-mongodb-sink/pom.xml index 9fd378b171..43772505a4 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-mongodb-sink/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-mongodb-sink/pom.xml @@ -9,9 +9,8 @@ com.baeldung - parent-boot-2 + spring-cloud-data-flow-etl 0.0.1-SNAPSHOT - ../../../parent-boot-2 @@ -63,7 +62,7 @@ UTF-8 UTF-8 - Greenwich.RELEASE + Hoxton.SR4 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-transform/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-transform/pom.xml index fdec22f3b3..f0d18a1c4f 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-transform/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-etl/customer-transform/pom.xml @@ -9,9 +9,8 @@ com.baeldung - parent-boot-2 + spring-cloud-data-flow-etl 0.0.1-SNAPSHOT - ../../../parent-boot-2 @@ -55,7 +54,7 @@ UTF-8 UTF-8 - Greenwich.RELEASE + Hoxton.SR4 From adb04983e7b505b2b827f4cd50a1ebd2da566a35 Mon Sep 17 00:00:00 2001 From: Sampada <46674082+sampada07@users.noreply.github.com> Date: Thu, 11 Jun 2020 21:27:04 +0530 Subject: [PATCH 110/118] BAEL-4061: Removed request mirroring (#9448) * BAEL-4061: Removed request mirroring * BAEL-4061: Code refactoring * BAEL-4061: more refactoring * BAEL-4061: renamed methods --- .../http/server/CustomHttpServerHandler.java | 29 ++--------- ...ResponseBuilder.java => RequestUtils.java} | 48 +++---------------- .../http/server/HttpServerLiveTest.java | 5 +- 3 files changed, 13 insertions(+), 69 deletions(-) rename netty/src/main/java/com/baeldung/http/server/{ResponseBuilder.java => RequestUtils.java} (61%) diff --git a/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java b/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java index 038f559329..abefbed0d9 100644 --- a/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java +++ b/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java @@ -5,8 +5,6 @@ import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; -import java.util.Set; - import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -20,9 +18,6 @@ import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.codec.http.cookie.Cookie; -import io.netty.handler.codec.http.cookie.ServerCookieDecoder; -import io.netty.handler.codec.http.cookie.ServerCookieEncoder; import io.netty.util.CharsetUtil; public class CustomHttpServerHandler extends SimpleChannelInboundHandler { @@ -45,22 +40,20 @@ public class CustomHttpServerHandler extends SimpleChannelInboundHandler } responseData.setLength(0); - responseData.append(ResponseBuilder.addRequestAttributes(request)); - responseData.append(ResponseBuilder.addHeaders(request)); - responseData.append(ResponseBuilder.addParams(request)); + responseData.append(RequestUtils.formatParams(request)); } - responseData.append(ResponseBuilder.addDecoderResult(request)); + responseData.append(RequestUtils.evaluateDecoderResult(request)); if (msg instanceof HttpContent) { HttpContent httpContent = (HttpContent) msg; - responseData.append(ResponseBuilder.addBody(httpContent)); - responseData.append(ResponseBuilder.addDecoderResult(request)); + responseData.append(RequestUtils.formatBody(httpContent)); + responseData.append(RequestUtils.evaluateDecoderResult(request)); if (msg instanceof LastHttpContent) { LastHttpContent trailer = (LastHttpContent) msg; - responseData.append(ResponseBuilder.addLastResponse(request, trailer)); + responseData.append(RequestUtils.prepareLastResponse(request, trailer)); writeResponse(ctx, trailer, responseData); } } @@ -88,18 +81,6 @@ public class CustomHttpServerHandler extends SimpleChannelInboundHandler .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } - String cookieString = request.headers() - .get(HttpHeaderNames.COOKIE); - if (cookieString != null) { - Set cookies = ServerCookieDecoder.STRICT.decode(cookieString); - if (!cookies.isEmpty()) { - for (Cookie cookie : cookies) { - httpResponse.headers() - .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie)); - } - } - } - ctx.write(httpResponse); if (!keepAlive) { diff --git a/netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java b/netty/src/main/java/com/baeldung/http/server/RequestUtils.java similarity index 61% rename from netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java rename to netty/src/main/java/com/baeldung/http/server/RequestUtils.java index 6d4e7845da..92ec2242f3 100644 --- a/netty/src/main/java/com/baeldung/http/server/ResponseBuilder.java +++ b/netty/src/main/java/com/baeldung/http/server/RequestUtils.java @@ -7,32 +7,15 @@ import java.util.Map.Entry; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.http.HttpContent; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.CharsetUtil; -class ResponseBuilder { +class RequestUtils { - static StringBuilder addRequestAttributes(HttpRequest request) { - StringBuilder responseData = new StringBuilder(); - responseData.append("Version: ") - .append(request.protocolVersion()) - .append("\r\n"); - responseData.append("Host: ") - .append(request.headers() - .get(HttpHeaderNames.HOST, "unknown")) - .append("\r\n"); - responseData.append("URI: ") - .append(request.uri()) - .append("\r\n\r\n"); - return responseData; - } - - static StringBuilder addParams(HttpRequest request) { + static StringBuilder formatParams(HttpRequest request) { StringBuilder responseData = new StringBuilder(); QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri()); Map> params = queryStringDecoder.parameters(); @@ -42,9 +25,9 @@ class ResponseBuilder { List vals = p.getValue(); for (String val : vals) { responseData.append("Parameter: ") - .append(key) + .append(key.toUpperCase()) .append(" = ") - .append(val) + .append(val.toUpperCase()) .append("\r\n"); } } @@ -53,24 +36,7 @@ class ResponseBuilder { return responseData; } - static StringBuilder addHeaders(HttpRequest request) { - StringBuilder responseData = new StringBuilder(); - HttpHeaders headers = request.headers(); - if (!headers.isEmpty()) { - for (Map.Entry header : headers) { - CharSequence key = header.getKey(); - CharSequence value = header.getValue(); - responseData.append(key) - .append(" = ") - .append(value) - .append("\r\n"); - } - responseData.append("\r\n"); - } - return responseData; - } - - static StringBuilder addBody(HttpContent httpContent) { + static StringBuilder formatBody(HttpContent httpContent) { StringBuilder responseData = new StringBuilder(); ByteBuf content = httpContent.content(); if (content.isReadable()) { @@ -81,7 +47,7 @@ class ResponseBuilder { return responseData; } - static StringBuilder addDecoderResult(HttpObject o) { + static StringBuilder evaluateDecoderResult(HttpObject o) { StringBuilder responseData = new StringBuilder(); DecoderResult result = o.decoderResult(); @@ -94,7 +60,7 @@ class ResponseBuilder { return responseData; } - static StringBuilder addLastResponse(HttpRequest request, LastHttpContent trailer) { + static StringBuilder prepareLastResponse(HttpRequest request, LastHttpContent trailer) { StringBuilder responseData = new StringBuilder(); responseData.append("Good Bye!\r\n"); diff --git a/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java b/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java index 7a0f884724..77f1288838 100644 --- a/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java +++ b/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java @@ -89,7 +89,7 @@ public class HttpServerLiveTest { } @Test - public void whenGetSent_thenCookieReceivedInResponse() throws Exception { + public void whenGetSent_thenResponseOK() throws Exception { DefaultFullHttpRequest request = createRequest(null); channel.writeAndFlush(request); @@ -98,9 +98,6 @@ public class HttpServerLiveTest { assertEquals(200, response.getStatus()); assertEquals("HTTP/1.1", response.getVersion()); - Map headers = response.getHeaders(); - String cookies = headers.get("set-cookie"); - assertTrue(cookies.contains("my-cookie")); } @After From c529170a43ef9074f63d1657e7807a1030377d35 Mon Sep 17 00:00:00 2001 From: Joe Zhang Date: Fri, 12 Jun 2020 22:18:54 +0800 Subject: [PATCH 111/118] Leasy Zhang/shiwangzhihe@gmail.com (#9445) * add primary key demo * add primary key * use eclipse link * update unit test * refact package name * format code with space Co-authored-by: joe zhang --- .../baeldung/jpa/generateidvalue/Admin.java | 36 +++++++++ .../baeldung/jpa/generateidvalue/Article.java | 39 +++++++++ .../jpa/generateidvalue/IdGenerator.java | 48 +++++++++++ .../baeldung/jpa/generateidvalue/Task.java | 39 +++++++++ .../baeldung/jpa/generateidvalue/User.java | 37 +++++++++ .../main/resources/META-INF/persistence.xml | 25 ++++++ .../main/resources/primary_key_generator.sql | 4 + .../generateidvalue/PrimaryKeyUnitTest.java | 81 +++++++++++++++++++ 8 files changed, 309 insertions(+) create mode 100644 persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Admin.java create mode 100644 persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Article.java create mode 100644 persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/IdGenerator.java create mode 100644 persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Task.java create mode 100644 persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/User.java create mode 100644 persistence-modules/java-jpa-2/src/main/resources/primary_key_generator.sql create mode 100644 persistence-modules/java-jpa-2/src/test/java/com/baeldung/jpa/generateidvalue/PrimaryKeyUnitTest.java diff --git a/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Admin.java b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Admin.java new file mode 100644 index 0000000000..1c59b33ab8 --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Admin.java @@ -0,0 +1,36 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "app_admin") +public class Admin { + + @Id + @GeneratedValue + private Long id; + + @Column(name = "admin_name") + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Article.java b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Article.java new file mode 100644 index 0000000000..06465de179 --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Article.java @@ -0,0 +1,39 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +@Entity +@Table(name = "article") +public class Article { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "article_gen") + @SequenceGenerator(name = "article_gen", sequenceName = "article_seq") + private Long id; + + @Column(name = "article_name") + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/IdGenerator.java b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/IdGenerator.java new file mode 100644 index 0000000000..0fac86747f --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/IdGenerator.java @@ -0,0 +1,48 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Table(name = "id_gen") +@Entity +public class IdGenerator { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "gen_name") + private String gen_name; + + @Column(name = "gen_value") + private Long gen_value; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getGen_name() { + return gen_name; + } + + public void setGen_name(String gen_name) { + this.gen_name = gen_name; + } + + public Long getGen_value() { + return gen_value; + } + + public void setGen_value(Long gen_value) { + this.gen_value = gen_value; + } + +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Task.java b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Task.java new file mode 100644 index 0000000000..a51ec53418 --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/Task.java @@ -0,0 +1,39 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.TableGenerator; + +@Entity +@Table(name = "task") +public class Task { + + @Id + @TableGenerator(name = "id_generator", table = "id_gen", pkColumnName = "gen_name", valueColumnName = "gen_value", pkColumnValue = "task_gen", initialValue = 10000, allocationSize = 10) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "id_generator") + private Long id; + + @Column(name = "name") + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/User.java b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/User.java new file mode 100644 index 0000000000..88fefe7ba6 --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/java/com/baeldung/jpa/generateidvalue/User.java @@ -0,0 +1,37 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "app_user") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_name") + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-2/src/main/resources/META-INF/persistence.xml index eec7f7cf6e..3bc81910d9 100644 --- a/persistence-modules/java-jpa-2/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-2/src/main/resources/META-INF/persistence.xml @@ -184,4 +184,29 @@ value="false" /> + + + org.eclipse.persistence.jpa.PersistenceProvider + com.baeldung.jpa.generateidvalue.Admin + com.baeldung.jpa.generateidvalue.Article + com.baeldung.jpa.generateidvalue.IdGenerator + com.baeldung.jpa.generateidvalue.Task + com.baeldung.jpa.generateidvalue.User + true + + + + + + + + + + + + + diff --git a/persistence-modules/java-jpa-2/src/main/resources/primary_key_generator.sql b/persistence-modules/java-jpa-2/src/main/resources/primary_key_generator.sql new file mode 100644 index 0000000000..9acd1bc11b --- /dev/null +++ b/persistence-modules/java-jpa-2/src/main/resources/primary_key_generator.sql @@ -0,0 +1,4 @@ +CREATE SEQUENCE article_seq MINVALUE 1 START WITH 50 INCREMENT BY 50; + +INSERT INTO id_gen (gen_name, gen_val) VALUES ('id_generator', 0); +INSERT INTO id_gen (gen_name, gen_val) VALUES ('task_gen', 10000); \ No newline at end of file diff --git a/persistence-modules/java-jpa-2/src/test/java/com/baeldung/jpa/generateidvalue/PrimaryKeyUnitTest.java b/persistence-modules/java-jpa-2/src/test/java/com/baeldung/jpa/generateidvalue/PrimaryKeyUnitTest.java new file mode 100644 index 0000000000..eead56dbff --- /dev/null +++ b/persistence-modules/java-jpa-2/src/test/java/com/baeldung/jpa/generateidvalue/PrimaryKeyUnitTest.java @@ -0,0 +1,81 @@ +package com.baeldung.jpa.generateidvalue; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * PrimaryKeyGeneratorTest class + * + * @author shiwangzhihe@gmail.com + */ +public class PrimaryKeyUnitTest { + private static EntityManager entityManager; + + @BeforeClass + public static void setup() { + EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-primarykey"); + entityManager = factory.createEntityManager(); + } + + @Test + public void givenIdentityStrategy_whenCommitTransction_thenReturnPrimaryKey() { + User user = new User(); + user.setName("TestName"); + + entityManager.getTransaction() + .begin(); + entityManager.persist(user); + Assert.assertNull(user.getId()); + entityManager.getTransaction() + .commit(); + + Long expectPrimaryKey = 1L; + Assert.assertEquals(expectPrimaryKey, user.getId()); + } + + @Test + public void givenTableStrategy_whenPersist_thenReturnPrimaryKey() { + Task task = new Task(); + task.setName("Test Task"); + + entityManager.getTransaction() + .begin(); + entityManager.persist(task); + Long expectPrimaryKey = 10000L; + Assert.assertEquals(expectPrimaryKey, task.getId()); + + entityManager.getTransaction() + .commit(); + } + + @Test + public void givenSequenceStrategy_whenPersist_thenReturnPrimaryKey() { + Article article = new Article(); + article.setName("Test Name"); + + entityManager.getTransaction() + .begin(); + entityManager.persist(article); + Long expectPrimaryKey = 51L; + Assert.assertEquals(expectPrimaryKey, article.getId()); + + entityManager.getTransaction() + .commit(); + } + + @Test + public void givenAutoStrategy_whenPersist_thenReturnPrimaryKey() { + Admin admin = new Admin(); + admin.setName("Test Name"); + + entityManager.persist(admin); + + Long expectPrimaryKey = 1L; + Assert.assertEquals(expectPrimaryKey, admin.getId()); + } +} \ No newline at end of file From 3a99a52d11eda6d4537c381f7a48879fa44dd79a Mon Sep 17 00:00:00 2001 From: Mark Thomas Date: Fri, 12 Jun 2020 09:37:48 -0500 Subject: [PATCH 112/118] Fix default SpEL expression (#9489) --- .../java/com/baeldung/beanpostprocessor/GlobalEventBus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-core-4/src/main/java/com/baeldung/beanpostprocessor/GlobalEventBus.java b/spring-core-4/src/main/java/com/baeldung/beanpostprocessor/GlobalEventBus.java index 8b3c528c4d..fff9eb8a0f 100644 --- a/spring-core-4/src/main/java/com/baeldung/beanpostprocessor/GlobalEventBus.java +++ b/spring-core-4/src/main/java/com/baeldung/beanpostprocessor/GlobalEventBus.java @@ -8,7 +8,7 @@ import java.util.concurrent.Executors; @SuppressWarnings("ALL") public final class GlobalEventBus { - public static final String GLOBAL_EVENT_BUS_EXPRESSION = "T(com.baeldung.postprocessor.GlobalEventBus).getEventBus()"; + public static final String GLOBAL_EVENT_BUS_EXPRESSION = "T(com.baeldung.beanpostprocessor.GlobalEventBus).getEventBus()"; private static final String IDENTIFIER = "global-event-bus"; From edd28c1b43c07adb7a84029aa5a1c24ac26d50b4 Mon Sep 17 00:00:00 2001 From: Carlos Cavero Date: Fri, 12 Jun 2020 19:40:14 +0200 Subject: [PATCH 113/118] BAEL-3756-Spring-YAML-vs-Properties (#9482) * Remove Dockerfile because it is not longer needed in the article * Add different YAML configurations and process into POJO * Remove .dockerignore file because it is not longer needed in the article * Add default Spring profile to test and force also in the Unit tests --- .../spring-boot-properties/.dockerignore | 13 -- .../spring-boot-properties/Dockerfile | 10 -- .../java/com/baeldung/yaml/MyApplication.java | 20 ++++ .../java/com/baeldung/yaml/YAMLConfig.java | 112 ++++++++++++++++++ .../src/main/resources/application.yml | 34 ++++-- .../baeldung/yaml/YAMLIntegrationTest.java | 2 + 6 files changed, 161 insertions(+), 30 deletions(-) delete mode 100644 spring-boot-modules/spring-boot-properties/.dockerignore delete mode 100644 spring-boot-modules/spring-boot-properties/Dockerfile diff --git a/spring-boot-modules/spring-boot-properties/.dockerignore b/spring-boot-modules/spring-boot-properties/.dockerignore deleted file mode 100644 index df36044e46..0000000000 --- a/spring-boot-modules/spring-boot-properties/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -# Logs -logs -*.log - -# Git -.git -.cache - -# Classes -**/*.class - -# Ignore md files -*.md diff --git a/spring-boot-modules/spring-boot-properties/Dockerfile b/spring-boot-modules/spring-boot-properties/Dockerfile deleted file mode 100644 index d6bd2a95ae..0000000000 --- a/spring-boot-modules/spring-boot-properties/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM maven:3.6.0-jdk-11 -WORKDIR /code/spring-boot-modules/spring-boot-properties/ -COPY ./spring-boot-modules/spring-boot-properties/pom.xml . -COPY ./spring-boot-modules/spring-boot-properties/src ./src -COPY ./parent-boot-2/pom.xml /code/parent-boot-2/pom.xml -COPY ./pom.xml /code/pom.xml -COPY ./custom-pmd-0.0.1.jar /code/custom-pmd-0.0.1.jar -COPY ./baeldung-pmd-rules.xml /code/baeldung-pmd-rules.xml -RUN mvn dependency:resolve -CMD ["mvn", "spring-boot:run"] \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/MyApplication.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/MyApplication.java index d42b731213..f3cfff57b7 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/MyApplication.java +++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/MyApplication.java @@ -11,6 +11,9 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import com.baeldung.yaml.YAMLConfig.Idm; +import com.baeldung.yaml.YAMLConfig.Service; + @SpringBootApplication public class MyApplication implements CommandLineRunner { @@ -26,6 +29,23 @@ public class MyApplication implements CommandLineRunner { System.out.println("using environment:" + myConfig.getEnvironment()); System.out.println("name:" + myConfig.getName()); System.out.println("servers:" + myConfig.getServers()); + + if ("testing".equalsIgnoreCase(myConfig.getEnvironment())) { + System.out.println("external:" + myConfig.getExternal()); + System.out.println("map:" + myConfig.getMap()); + + Idm idm = myConfig.getComponent().getIdm(); + Service service = myConfig.getComponent().getService(); + System.out.println("Idm:"); + System.out.println(" Url: " + idm.getUrl()); + System.out.println(" User: " + idm.getUser()); + System.out.println(" Password: " + idm.getPassword()); + System.out.println(" Description: " + idm.getDescription()); + System.out.println("Service:"); + System.out.println(" Url: " + service.getUrl()); + System.out.println(" Token: " + service.getToken()); + System.out.println(" Description: " + service.getDescription()); + } } } diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/YAMLConfig.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/YAMLConfig.java index ad633c4b56..83c083734c 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/YAMLConfig.java +++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/yaml/YAMLConfig.java @@ -1,7 +1,10 @@ package com.baeldung.yaml; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -13,6 +16,9 @@ public class YAMLConfig { private String name; private String environment; private List servers = new ArrayList(); + private List external = new ArrayList(); + private Map map = new HashMap(); + private Component component = new Component(); public List getServers() { return servers; @@ -37,5 +43,111 @@ public class YAMLConfig { public void setEnvironment(String environment) { this.environment = environment; } + + public Component getComponent() { + return component; + } + + public void setComponent(Component component) { + this.component = component; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public List getExternal() { + return external; + } + + public void setExternal(List external) { + this.external = external; + } + + public class Component { + private Idm idm = new Idm(); + private Service service = new Service(); + + public Idm getIdm() { + return idm; + } + public void setIdm(Idm idm) { + this.idm = idm; + } + + public Service getService() { + return service; + } + public void setService(Service service) { + this.service = service; + } + + } + + public class Idm { + private String url; + private String user; + private String password; + private String description; + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + + public String getUser() { + return user; + } + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + } + + public class Service { + private String url; + private String token; + private String description; + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + + public String getToken() { + return token; + } + public void setToken(String token) { + this.token = token; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + } } diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/application.yml b/spring-boot-modules/spring-boot-properties/src/main/resources/application.yml index 4914ff15f7..30e64f9d35 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/resources/application.yml +++ b/spring-boot-modules/spring-boot-properties/src/main/resources/application.yml @@ -6,22 +6,42 @@ spring: --- spring: - profiles: test + profiles: test name: test-YAML environment: testing servers: - - www.abc.test.com - - www.xyz.test.com - + - www.abc.test.com + - www.xyz.test.com + +external: [www.abc.test.com, www.xyz.test.com] + +map: + firstkey: key1 + secondkey: key2 + +component: + idm: + url: myurl + user: user + password: password + description: > + this should be a long + description + service: + url: myurlservice + token: token + description: > + this should be another long + description --- spring: - profiles: prod + profiles: prod name: prod-YAML environment: production servers: - - www.abc.com - - www.xyz.com + - www.abc.com + - www.xyz.com --- diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/yaml/YAMLIntegrationTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/yaml/YAMLIntegrationTest.java index 090d5c592e..19412c91f5 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/yaml/YAMLIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/yaml/YAMLIntegrationTest.java @@ -11,6 +11,7 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(classes = MyApplication.class) +@TestPropertySource(properties = {"spring.profiles.active = test"}) class YAMLIntegrationTest { @Autowired @@ -20,5 +21,6 @@ class YAMLIntegrationTest { void whenProfileTest_thenNameTesting() { assertTrue("testing".equalsIgnoreCase(config.getEnvironment())); assertTrue("test-YAML".equalsIgnoreCase(config.getName())); + assertTrue("myurl".equalsIgnoreCase(config.getComponent().getIdm().getUrl())); } } From ca9ab77e7c60ae57997be58c90bf4cdeac38b0b1 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Fri, 12 Jun 2020 20:32:04 -0500 Subject: [PATCH 114/118] Bael 3766 update README (#9493) * BAEL-3336 BAEL-3058 add links * BAEL-3319: add link * BAEL-3284: add link * BAEL-3198: add link to article * BAEL-3479: add link to article * BAEL-3485: add article link * SCALA-38: move to new package and add link back to article * SCALA-38: add imports back into unit test * BAEL-3908: add link back to article * BAEL-2893 BAEL-3927 add link back to article * BAEL-3766: add link back to article --- persistence-modules/java-jpa-2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/java-jpa-2/README.md b/persistence-modules/java-jpa-2/README.md index 4b822c4782..d711eef1b0 100644 --- a/persistence-modules/java-jpa-2/README.md +++ b/persistence-modules/java-jpa-2/README.md @@ -13,4 +13,5 @@ This module contains articles about the Java Persistence API (JPA) in Java. - [JPA Annotation for the PostgreSQL TEXT Type](https://www.baeldung.com/jpa-annotation-postgresql-text-type) - [Mapping a Single Entity to Multiple Tables in JPA](https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables) - [Constructing a JPA Query Between Unrelated Entities](https://www.baeldung.com/jpa-query-unrelated-entities) +- [When Does JPA Set the Primary Key](https://www.baeldung.com/jpa-strategies-when-set-primary-key) - More articles: [[<-- prev]](/java-jpa) From 3e6f576265c72c701360760c9ddb253bb96ab89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Dupire?= Date: Sat, 13 Jun 2020 11:11:35 +0200 Subject: [PATCH 115/118] [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin in guava modules (#9477) * [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin versions in guava-modules * Set guava-modules parent pom's parent to parent-java and submodules' parent to guava-modules parent * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin versions in guava * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin versions in guava-collections * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin versions in guava-collections-map * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * [JAVA-1660] Upgrade JUnit and Maven Surefire Plugin versions in guava-collections-set * Upgraded Maven Surefire Plugin version to 2.22.2 * Upgraded JUnit version to 5.6.2 * [JAVA-1660] Upgraded JUnit and Maven Surefire Plugin in guava-io module * Fixed project structure and added missing resources to make tests work * Upgraded Maven Surefire Plugin to version 2.22.2 * Upgraded JUnit version to 5.6.2 --- guava-collections-map/pom.xml | 27 ++++++++++++ guava-collections-set/pom.xml | 29 +++++++++++-- guava-collections/pom.xml | 43 ++++++++++++++----- guava-io/pom.xml | 26 +++++++++++ .../GuavaCountingOutputStreamUnitTest.java | 0 .../com/baeldung/guava/GuavaIOUnitTest.java | 19 +++++++- guava-io/src/test/resources/test1.in | 1 + guava-io/src/test/resources/test1_1.in | 1 + guava-io/src/test/resources/test2.in | 4 ++ guava-modules/guava-18/pom.xml | 4 +- guava-modules/guava-19/pom.xml | 4 +- guava-modules/guava-21/pom.xml | 4 +- guava-modules/pom.xml | 33 ++++++++++++-- guava/pom.xml | 43 ++++++++++++++----- 14 files changed, 204 insertions(+), 34 deletions(-) rename guava-io/src/{main => }/test/java/com/baeldung/guava/GuavaCountingOutputStreamUnitTest.java (100%) rename guava-io/src/{main => }/test/java/com/baeldung/guava/GuavaIOUnitTest.java (93%) create mode 100644 guava-io/src/test/resources/test1.in create mode 100644 guava-io/src/test/resources/test1_1.in create mode 100644 guava-io/src/test/resources/test2.in diff --git a/guava-collections-map/pom.xml b/guava-collections-map/pom.xml index ee8ceb10f3..06537d26bd 100644 --- a/guava-collections-map/pom.xml +++ b/guava-collections-map/pom.xml @@ -16,12 +16,39 @@ guava-collections-map + src/main/resources true + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + + + + + 5.6.2 + \ No newline at end of file diff --git a/guava-collections-set/pom.xml b/guava-collections-set/pom.xml index 8bb0b924f9..49d96965a7 100644 --- a/guava-collections-set/pom.xml +++ b/guava-collections-set/pom.xml @@ -13,8 +13,32 @@ ../parent-java + + guava-collections-set + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + org.assertj assertj-core @@ -23,13 +47,10 @@ - - guava-collections-set - - 3.6.1 + 5.6.2 diff --git a/guava-collections/pom.xml b/guava-collections/pom.xml index c6019362c5..744eba1a38 100644 --- a/guava-collections/pom.xml +++ b/guava-collections/pom.xml @@ -15,6 +15,25 @@ ../parent-java + + guava-collections + + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + @@ -27,7 +46,20 @@ commons-lang3 ${commons-lang3.version} + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + org.assertj assertj-core @@ -44,16 +76,6 @@ - - guava-collections - - - src/main/resources - true - - - - 4.1 @@ -61,6 +83,7 @@ 3.6.1 2.0.0.0 + 5.6.2 \ No newline at end of file diff --git a/guava-io/pom.xml b/guava-io/pom.xml index 7517d442b0..fd637f2474 100644 --- a/guava-io/pom.xml +++ b/guava-io/pom.xml @@ -4,6 +4,9 @@ 4.0.0 guava-io 0.1.0-SNAPSHOT + + 5.6.2 + guava-io @@ -15,12 +18,35 @@ guava-io + src/main/resources true + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + + \ No newline at end of file diff --git a/guava-io/src/main/test/java/com/baeldung/guava/GuavaCountingOutputStreamUnitTest.java b/guava-io/src/test/java/com/baeldung/guava/GuavaCountingOutputStreamUnitTest.java similarity index 100% rename from guava-io/src/main/test/java/com/baeldung/guava/GuavaCountingOutputStreamUnitTest.java rename to guava-io/src/test/java/com/baeldung/guava/GuavaCountingOutputStreamUnitTest.java diff --git a/guava-io/src/main/test/java/com/baeldung/guava/GuavaIOUnitTest.java b/guava-io/src/test/java/com/baeldung/guava/GuavaIOUnitTest.java similarity index 93% rename from guava-io/src/main/test/java/com/baeldung/guava/GuavaIOUnitTest.java rename to guava-io/src/test/java/com/baeldung/guava/GuavaIOUnitTest.java index 7d7b0ea04d..4d7c688f58 100644 --- a/guava-io/src/main/test/java/com/baeldung/guava/GuavaIOUnitTest.java +++ b/guava-io/src/test/java/com/baeldung/guava/GuavaIOUnitTest.java @@ -11,8 +11,11 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; +import org.junit.After; import org.junit.Test; import com.google.common.base.Charsets; @@ -31,6 +34,21 @@ import com.google.common.io.Resources; public class GuavaIOUnitTest { + @After + public void afterEach() throws Exception { + deleteProducedFiles(); + } + + private void deleteProducedFiles() throws IOException { + deleteIfExists("test.out"); + deleteIfExists("test_copy.in"); + deleteIfExists("test_le.txt"); + } + + private void deleteIfExists(String fileName) throws IOException { + java.nio.file.Files.deleteIfExists(Paths.get("src", "test", "resources", fileName)); + } + @Test public void whenWriteUsingFiles_thenWritten() throws IOException { final String expectedValue = "Hello world"; @@ -206,5 +224,4 @@ public class GuavaIOUnitTest { assertEquals(value, result); } - } diff --git a/guava-io/src/test/resources/test1.in b/guava-io/src/test/resources/test1.in new file mode 100644 index 0000000000..70c379b63f --- /dev/null +++ b/guava-io/src/test/resources/test1.in @@ -0,0 +1 @@ +Hello world \ No newline at end of file diff --git a/guava-io/src/test/resources/test1_1.in b/guava-io/src/test/resources/test1_1.in new file mode 100644 index 0000000000..8318c86b35 --- /dev/null +++ b/guava-io/src/test/resources/test1_1.in @@ -0,0 +1 @@ +Test \ No newline at end of file diff --git a/guava-io/src/test/resources/test2.in b/guava-io/src/test/resources/test2.in new file mode 100644 index 0000000000..622efea9e6 --- /dev/null +++ b/guava-io/src/test/resources/test2.in @@ -0,0 +1,4 @@ +John +Jane +Adam +Tom \ No newline at end of file diff --git a/guava-modules/guava-18/pom.xml b/guava-modules/guava-18/pom.xml index 30d9f953ac..d65fab1e57 100644 --- a/guava-modules/guava-18/pom.xml +++ b/guava-modules/guava-18/pom.xml @@ -8,9 +8,9 @@ com.baeldung - parent-java + guava-modules 0.0.1-SNAPSHOT - ../../parent-java + ../ diff --git a/guava-modules/guava-19/pom.xml b/guava-modules/guava-19/pom.xml index 0060afd426..20a405cff4 100644 --- a/guava-modules/guava-19/pom.xml +++ b/guava-modules/guava-19/pom.xml @@ -8,9 +8,9 @@ com.baeldung - parent-java + guava-modules 0.0.1-SNAPSHOT - ../../parent-java + ../ diff --git a/guava-modules/guava-21/pom.xml b/guava-modules/guava-21/pom.xml index 7932cfa6d8..b126df99cb 100644 --- a/guava-modules/guava-21/pom.xml +++ b/guava-modules/guava-21/pom.xml @@ -8,9 +8,9 @@ com.baeldung - parent-java + guava-modules 0.0.1-SNAPSHOT - ../../parent-java + ../ diff --git a/guava-modules/pom.xml b/guava-modules/pom.xml index 2b899df162..4e7282364d 100644 --- a/guava-modules/pom.xml +++ b/guava-modules/pom.xml @@ -4,13 +4,16 @@ 4.0.0 guava-modules guava-modules + + 5.6.2 + pom com.baeldung - parent-modules - 1.0.0-SNAPSHOT - .. + parent-java + 0.0.1-SNAPSHOT + ../parent-java @@ -19,4 +22,28 @@ guava-21 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + + diff --git a/guava/pom.xml b/guava/pom.xml index df6d57bd09..881390ae73 100644 --- a/guava/pom.xml +++ b/guava/pom.xml @@ -15,13 +15,45 @@ ../parent-java + + guava + + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + org.apache.commons commons-lang3 ${commons-lang3.version} + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + org.assertj assertj-core @@ -30,18 +62,9 @@ - - guava - - - src/main/resources - true - - - - + 5.6.2 3.6.1 From a6d6edb4947b10d8e3e7c186cd1f70882752c565 Mon Sep 17 00:00:00 2001 From: Mona Mohamadinia Date: Sat, 13 Jun 2020 14:23:32 +0430 Subject: [PATCH 116/118] BAEL-4125: How to get the insert ID in JDBC? (#9437) * Added the Code Samples * Refactor * Latest H2 Version * Avoid using * imports * Using givenXXX_whenYYY_thenZZZ Naming Convention --- .../core-java-persistence/pom.xml | 1 + .../genkeys/JdbcInsertIdIntegrationTest.java | 93 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 persistence-modules/core-java-persistence/src/test/java/com/baeldung/genkeys/JdbcInsertIdIntegrationTest.java diff --git a/persistence-modules/core-java-persistence/pom.xml b/persistence-modules/core-java-persistence/pom.xml index 1224523ac7..3dd8da1b7a 100644 --- a/persistence-modules/core-java-persistence/pom.xml +++ b/persistence-modules/core-java-persistence/pom.xml @@ -60,6 +60,7 @@ + 1.4.200 42.2.5.jre7 3.10.0 2.4.0 diff --git a/persistence-modules/core-java-persistence/src/test/java/com/baeldung/genkeys/JdbcInsertIdIntegrationTest.java b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/genkeys/JdbcInsertIdIntegrationTest.java new file mode 100644 index 0000000000..f1ea5bfbb4 --- /dev/null +++ b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/genkeys/JdbcInsertIdIntegrationTest.java @@ -0,0 +1,93 @@ +package com.baeldung.genkeys; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JdbcInsertIdIntegrationTest { + + private static final String QUERY = "insert into persons (name) values (?)"; + + private static Connection connection; + + @BeforeClass + public static void setUp() throws Exception { + connection = DriverManager.getConnection("jdbc:h2:mem:generated-keys", "sa", ""); + connection + .createStatement() + .execute("create table persons(id bigint auto_increment, name varchar(255))"); + } + + @AfterClass + public static void tearDown() throws SQLException { + connection + .createStatement() + .execute("drop table persons"); + connection.close(); + } + + @Test + public void givenInsert_whenUsingAutoGenFlag_thenBeAbleToFetchTheIdAfterward() throws SQLException { + try (PreparedStatement statement = connection.prepareStatement(QUERY, Statement.RETURN_GENERATED_KEYS)) { + statement.setString(1, "Foo"); + int affectedRows = statement.executeUpdate(); + assertThat(affectedRows).isPositive(); + + try (ResultSet keys = statement.getGeneratedKeys()) { + assertThat(keys.next()).isTrue(); + assertThat(keys.getLong(1)).isGreaterThanOrEqualTo(1); + } + } + } + + @Test + public void givenInsert_whenUsingAutoGenFlagViaExecute_thenBeAbleToFetchTheIdAfterward() throws SQLException { + try (Statement statement = connection.createStatement()) { + String query = "insert into persons (name) values ('Foo')"; + int affectedRows = statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS); + assertThat(affectedRows).isPositive(); + + try (ResultSet keys = statement.getGeneratedKeys()) { + assertThat(keys.next()).isTrue(); + assertThat(keys.getLong(1)).isGreaterThanOrEqualTo(1); + } + } + } + + @Test + public void givenInsert_whenUsingReturningCols_thenBeAbleToFetchTheIdAfterward() throws SQLException { + try (PreparedStatement statement = connection.prepareStatement(QUERY, new String[] { "id" })) { + statement.setString(1, "Foo"); + int affectedRows = statement.executeUpdate(); + assertThat(affectedRows).isPositive(); + + try (ResultSet keys = statement.getGeneratedKeys()) { + assertThat(keys.next()).isTrue(); + assertThat(keys.getLong(1)).isGreaterThanOrEqualTo(1); + } + } + } + + @Test + public void givenInsert_whenUsingReturningColsViaExecute_thenBeAbleToFetchTheIdAfterward() throws SQLException { + try (Statement statement = connection.createStatement()) { + String query = "insert into persons (name) values ('Foo')"; + int affectedRows = statement.executeUpdate(query, new String[] { "id" }); + assertThat(affectedRows).isPositive(); + + try (ResultSet keys = statement.getGeneratedKeys()) { + assertThat(keys.next()).isTrue(); + assertThat(keys.getLong(1)).isGreaterThanOrEqualTo(1); + } + } + } +} From 4744f3d4d2145e17788bc263d3f582304dd6a7a6 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Sat, 13 Jun 2020 17:29:06 +0530 Subject: [PATCH 117/118] JAVA-938: Migrate spring-cloud-data-flow-stream-processing to parent-boot-2 --- .../log-sink/pom.xml | 5 ++--- .../pom.xml | 14 +++++++++++--- .../time-processor/pom.xml | 5 ++--- .../time-source/pom.xml | 6 +++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml index 02d572aeb7..186e5b1886 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml @@ -10,9 +10,8 @@ com.baeldung - parent-boot-1 + spring-cloud-data-flow-stream-processing 0.0.1-SNAPSHOT - ../../../parent-boot-1 @@ -35,7 +34,7 @@ - Brixton.SR7 + Hoxton.SR4 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml index 5342049d73..e794287e10 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml @@ -2,6 +2,7 @@ 4.0.0 + com.baeldung spring-cloud-data-flow-stream-processing 0.0.1-SNAPSHOT spring-cloud-data-flow-stream-processing @@ -9,9 +10,8 @@ com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../ + spring-cloud-data-flow + 0.0.1-SNAPSHOT @@ -21,5 +21,13 @@ time-processor log-sink + + + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml index f8db434423..b4ad84cfe9 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml @@ -10,9 +10,8 @@ com.baeldung - parent-boot-1 + spring-cloud-data-flow-stream-processing 0.0.1-SNAPSHOT - ../../../parent-boot-1 @@ -35,7 +34,7 @@ - Brixton.SR7 + Hoxton.SR4 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml index 8194755814..05908d3c52 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml @@ -2,6 +2,7 @@ 4.0.0 + com.baeldung.spring.cloud time-source 0.0.1-SNAPSHOT time-source @@ -10,9 +11,8 @@ com.baeldung - parent-boot-1 + spring-cloud-data-flow-stream-processing 0.0.1-SNAPSHOT - ../../../parent-boot-1 @@ -35,7 +35,7 @@ - Brixton.SR7 + Hoxton.SR4 From 4456caf9d7fc30c7bfdb01e0f3aacf10b3731b63 Mon Sep 17 00:00:00 2001 From: Benjamin Caure Date: Sat, 13 Jun 2020 14:54:57 +0200 Subject: [PATCH 118/118] BAEL-4078 Rest template logging (#9430) --- spring-resttemplate-2/README.md | 7 +++ spring-resttemplate-2/pom.xml | 63 +++++++++++++++++++ .../RestTemplateConfigurationApplication.java | 14 +++++ .../web/controller/PersonController.java | 17 +++++ .../src/main/resources/application.properties | 2 + .../logging/LoggingInterceptor.java | 29 +++++++++ .../logging/RestTemplateLoggingLiveTest.java | 50 +++++++++++++++ .../src/test/resources/application.properties | 5 ++ 8 files changed, 187 insertions(+) create mode 100644 spring-resttemplate-2/README.md create mode 100644 spring-resttemplate-2/pom.xml create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/RestTemplateConfigurationApplication.java create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/web/controller/PersonController.java create mode 100644 spring-resttemplate-2/src/main/resources/application.properties create mode 100644 spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/LoggingInterceptor.java create mode 100644 spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/RestTemplateLoggingLiveTest.java create mode 100644 spring-resttemplate-2/src/test/resources/application.properties diff --git a/spring-resttemplate-2/README.md b/spring-resttemplate-2/README.md new file mode 100644 index 0000000000..e0a394c642 --- /dev/null +++ b/spring-resttemplate-2/README.md @@ -0,0 +1,7 @@ +## Spring RestTemplate + +This module contains articles about Spring RestTemplate + +### Relevant Articles: + + diff --git a/spring-resttemplate-2/pom.xml b/spring-resttemplate-2/pom.xml new file mode 100644 index 0000000000..1a594fd21e --- /dev/null +++ b/spring-resttemplate-2/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + spring-resttemplate + 0.1-SNAPSHOT + spring-resttemplate-2 + war + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + + + + + org.springframework + spring-web + + + commons-logging + commons-logging + + + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/RestTemplateConfigurationApplication.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/RestTemplateConfigurationApplication.java new file mode 100644 index 0000000000..4fa14edda1 --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/RestTemplateConfigurationApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.resttemplate.logging; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableAutoConfiguration +public class RestTemplateConfigurationApplication { + + public static void main(String[] args) { + SpringApplication.run(RestTemplateConfigurationApplication.class, args); + } +} diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/web/controller/PersonController.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/web/controller/PersonController.java new file mode 100644 index 0000000000..8436c52a4a --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/logging/web/controller/PersonController.java @@ -0,0 +1,17 @@ +package com.baeldung.resttemplate.logging.web.controller; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class PersonController { + + @PostMapping("/persons") + public List getPersons() { + return Arrays.asList(new String[] { "Lucie", "Jackie", "Danesh", "Tao" }); + } + +} \ No newline at end of file diff --git a/spring-resttemplate-2/src/main/resources/application.properties b/spring-resttemplate-2/src/main/resources/application.properties new file mode 100644 index 0000000000..ea4f7c866d --- /dev/null +++ b/spring-resttemplate-2/src/main/resources/application.properties @@ -0,0 +1,2 @@ +server.port=8080 +server.servlet.context-path=/spring-rest \ No newline at end of file diff --git a/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/LoggingInterceptor.java b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/LoggingInterceptor.java new file mode 100644 index 0000000000..17ce390d8a --- /dev/null +++ b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/LoggingInterceptor.java @@ -0,0 +1,29 @@ +package com.baeldung.resttemplate.logging; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +public class LoggingInterceptor implements ClientHttpRequestInterceptor { + + final static Logger log = LoggerFactory.getLogger(LoggingInterceptor.class); + + @Override + public ClientHttpResponse intercept(HttpRequest req, byte[] reqBody, ClientHttpRequestExecution ex) throws IOException { + log.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8)); + ClientHttpResponse response = ex.execute(req, reqBody); + InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8); + String body = new BufferedReader(isr).lines() + .collect(Collectors.joining("\n")); + log.debug("Response body: {}", body); + return response; + } +} diff --git a/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/RestTemplateLoggingLiveTest.java b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/RestTemplateLoggingLiveTest.java new file mode 100644 index 0000000000..99d0201eff --- /dev/null +++ b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/logging/RestTemplateLoggingLiveTest.java @@ -0,0 +1,50 @@ +package com.baeldung.resttemplate.logging; + +import static org.hamcrest.CoreMatchers.equalTo; + +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class RestTemplateLoggingLiveTest { + + private static final String baseUrl = "http://localhost:8080/spring-rest"; + + @Test + public void givenHttpClientConfiguration_whenSendGetForRequestEntity_thenRequestResponseFullLog() { + + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); + + final ResponseEntity response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenLoggingInterceptorConfiguration_whenSendGetForRequestEntity_thenRequestResponseCustomLog() { + + RestTemplate restTemplate = new RestTemplate(); + List interceptors = restTemplate.getInterceptors(); + if (CollectionUtils.isEmpty(interceptors)) { + interceptors = new ArrayList<>(); + } + interceptors.add(new LoggingInterceptor()); + restTemplate.setInterceptors(interceptors); + + final ResponseEntity response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } +} diff --git a/spring-resttemplate-2/src/test/resources/application.properties b/spring-resttemplate-2/src/test/resources/application.properties new file mode 100644 index 0000000000..7bc9e56041 --- /dev/null +++ b/spring-resttemplate-2/src/test/resources/application.properties @@ -0,0 +1,5 @@ +logging.level.org.springframework.web.client.RestTemplate=DEBUG +logging.level.com.baeldung.resttemplate.logging.LoggingInterceptor=DEBUG +logging.level.org.apache.http=DEBUG +logging.level.httpclient.wire=DEBUG +logging.pattern.console=%20logger{20} - %msg%n