diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/MultilineUnitTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/MultilineUnitTest.java
new file mode 100644
index 0000000000..4efd1ff362
--- /dev/null
+++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/MultilineUnitTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.java14.newfeatues;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class MultilineUnitTest {
+
+ @SuppressWarnings("preview")
+ String multiline = """
+ A quick brown fox jumps over a lazy dog; \
+ the lazy dog howls loudly.""";
+
+ @SuppressWarnings("preview")
+ String anotherMultiline = """
+ A quick brown fox jumps over a lazy dog;
+ the lazy dog howls loudly.""";
+
+ @Test
+ public void givenMultilineString_whenSlashUsed_thenNoNewLine() {
+ assertFalse(multiline.contains("\n"));
+ assertTrue(anotherMultiline.contains("\n"));
+ }
+
+}
diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/RecordUnitTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/RecordUnitTest.java
new file mode 100644
index 0000000000..3d7a55d3e6
--- /dev/null
+++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/RecordUnitTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.java14.newfeatues;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class RecordUnitTest {
+
+ @SuppressWarnings("preview")
+ public record User(int id, String password) {
+ };
+
+ private User user1 = new User(0, "UserOne");
+
+ @Test
+ public void givenRecord_whenObjInitialized_thenValuesCanBeFetchedWithGetters() {
+
+ assertEquals(0, user1.id());
+ assertEquals("UserOne", user1.password());
+ }
+
+ @Test
+ public void whenRecord_thenEqualsImplemented() {
+
+ User user2 = user1;
+
+ assertEquals(user1, user2);
+ }
+
+ @Test
+ public void whenRecord_thenToStringImplemented() {
+
+ assertTrue(user1.toString()
+ .contains("UserOne"));
+ }
+
+}
diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/SwitchExprUnitTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/SwitchExprUnitTest.java
new file mode 100644
index 0000000000..896b3ec7de
--- /dev/null
+++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/newfeatues/SwitchExprUnitTest.java
@@ -0,0 +1,50 @@
+package com.baeldung.java14.newfeatues;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class SwitchExprUnitTest {
+
+ @Test
+ public void givenDay_whenSunday_thenWeekend() {
+ assertTrue(isTodayHolidayInJava8("SUNDAY"));
+
+ assertTrue(isTodayHolidayInJava14("SUNDAY"));
+
+ assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> isTodayHolidayInJava8("SOMEDAY"));
+
+ assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> isTodayHolidayInJava14("SOMEDAY"));
+ }
+
+ private boolean isTodayHolidayInJava8(String day) {
+
+ boolean isTodayHoliday;
+ switch (day) {
+ case "MONDAY":
+ case "TUESDAY":
+ case "WEDNESDAY":
+ case "THURSDAY":
+ case "FRIDAY":
+ isTodayHoliday = false;
+ break;
+ case "SATURDAY":
+ case "SUNDAY":
+ isTodayHoliday = true;
+ break;
+ default:
+ throw new IllegalArgumentException("What's a " + day);
+ }
+ return isTodayHoliday;
+ }
+
+ private boolean isTodayHolidayInJava14(String day) {
+ return switch (day) {
+ case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> false;
+ case "SATURDAY", "SUNDAY" -> true;
+ default -> throw new IllegalArgumentException("What's a " + day);
+ };
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-4/README.md b/core-java-modules/core-java-collections-4/README.md
new file mode 100644
index 0000000000..6e117c98b1
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/README.md
@@ -0,0 +1,7 @@
+=========
+
+## Core Java Collections Cookbooks and Examples
+
+### Relevant Articles:
+
+- [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap)
diff --git a/core-java-modules/core-java-collections-4/pom.xml b/core-java-modules/core-java-collections-4/pom.xml
new file mode 100644
index 0000000000..0e3cabf40e
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+ core-java-collections-4
+ 0.1.0-SNAPSHOT
+ core-java-collections-4
+ jar
+
+ com.baeldung.core-java-modules
+ core-java-modules
+ 0.0.1-SNAPSHOT
+ ../pom.xml
+
+
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+
+
+ 3.18.0
+
+
+
diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ArrayListUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ArrayListUnitTest.java
new file mode 100644
index 0000000000..bc6a07d274
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ArrayListUnitTest.java
@@ -0,0 +1,30 @@
+package com.baeldung.collections.comparation;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ArrayListUnitTest {
+
+ @Test
+ void givenArrayList_whenItemAddedToSpecificIndex_thenItCanBeRetrieved() {
+ List list = new ArrayList<>();
+ list.add("Daniel");
+ list.add(0, "Marko");
+ assertThat(list).hasSize(2);
+ assertThat(list.get(0)).isEqualTo("Marko");
+ }
+
+ @Test
+ void givenArrayList_whenItemRemovedViaIndex_thenListSizeIsReduced() {
+ List list = new ArrayList<>(Arrays.asList("Daniel", "Marko"));
+ list.remove(1);
+ assertThat(list).hasSize(1);
+ assertThat(list).doesNotContain("Marko");
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java
new file mode 100644
index 0000000000..3b595472e0
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java
@@ -0,0 +1,31 @@
+package com.baeldung.collections.comparation;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class HashMapUnitTest {
+
+ @Test
+ void givenHashMap_whenItemAddedByKey_thenItCanBeRetrieved() {
+ Map map = new HashMap<>();
+ map.put("123456", "Daniel");
+ map.put("654321", "Marko");
+ assertThat(map.get("654321")).isEqualTo("Marko");
+ }
+
+ @Test
+ void givenHashMap_whenItemRemovedByKey_thenMapSizeIsReduced() {
+ Map map = new HashMap<>();
+ map.put("123456", "Daniel");
+ map.put("654321", "Marko");
+ map.remove("654321");
+ assertThat(map).hasSize(1);
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java
new file mode 100644
index 0000000000..aa6b7fa923
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java
@@ -0,0 +1,41 @@
+package com.baeldung.collections.comparation;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LinkedListUnitTest {
+
+ @Test
+ void givenLinkedList_whenItemIsAppended_thenItCanBeRetrieved() {
+ LinkedList list = new LinkedList<>();
+ list.addLast("Daniel");
+ list.addFirst("Marko");
+ assertThat(list).hasSize(2);
+ assertThat(list.getLast()).isEqualTo("Daniel");
+ }
+
+ @Test
+ void givenLinkedList_whenItemIsRemoved_thenListSizeIsReduced() {
+ LinkedList list = new LinkedList<>(Arrays.asList("Daniel", "Marko", "David"));
+ list.removeFirst();
+ list.removeLast();
+ assertThat(list).hasSize(1);
+ assertThat(list).containsExactly("Marko");
+ }
+
+ @Test
+ void givenLinkedList_whenItemInserted_thenItCanBeRetrievedAndDeleted() {
+ LinkedList list = new LinkedList<>();
+ list.push("Daniel");
+ list.push("Marko");
+ assertThat(list.poll()).isEqualTo("Marko");
+ assertThat(list).hasSize(1);
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ListVsMapUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ListVsMapUnitTest.java
new file mode 100644
index 0000000000..dd6bf760fd
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/ListVsMapUnitTest.java
@@ -0,0 +1,32 @@
+package com.baeldung.collections.comparation;
+
+import static org.assertj.core.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+
+class ListVsMapUnitTest {
+
+ @Test
+ void givenList_whenIteratingTroughValues_thenEachValueIsPresent() {
+ List list = new ArrayList<>();
+ list.add("Daniel");
+ list.add("Marko");
+ for (String name : list) {
+ assertThat(name).isIn(list);
+ }
+ assertThat(list).containsExactly("Daniel", "Marko");
+ }
+
+ @Test
+ void givenMap_whenIteratingTroughValues_thenEachValueIsPresent() {
+ Map map = new HashMap<>();
+ map.put(1, "Daniel");
+ map.put(2, "Marko");
+ for (String name : map.values()) {
+ assertThat(name).isIn(map.values());
+ }
+ assertThat(map.values()).containsExactlyInAnyOrder("Daniel", "Marko");
+ }
+
+}
diff --git a/core-java-modules/core-java-io-3/README.md b/core-java-modules/core-java-io-3/README.md
index 36617a210e..d0ac5387a8 100644
--- a/core-java-modules/core-java-io-3/README.md
+++ b/core-java-modules/core-java-io-3/README.md
@@ -13,4 +13,5 @@ This module contains articles about core Java input and output (IO)
- [Reading a Line at a Given Line Number From a File in Java](https://www.baeldung.com/java-read-line-at-number)
- [Find the Last Modified File in a Directory with Java](https://www.baeldung.com/java-last-modified-file)
- [Get a Filename Without the Extension in Java](https://www.baeldung.com/java-filename-without-extension)
+- [Writing byte[] to a File in Java](https://www.baeldung.com/java-write-byte-array-file)
- [[<-- Prev]](/core-java-modules/core-java-io-2)
diff --git a/core-java-modules/core-java-io-3/src/test/java/com/baeldung/writebytearray/WriteByteArrayUnitTest.java b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/writebytearray/WriteByteArrayUnitTest.java
new file mode 100644
index 0000000000..ef8c8e2470
--- /dev/null
+++ b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/writebytearray/WriteByteArrayUnitTest.java
@@ -0,0 +1,77 @@
+package com.baeldung.writebytearray;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.google.common.io.ByteSink;
+import com.google.common.io.MoreFiles;
+
+public class WriteByteArrayUnitTest {
+ private static byte[] dataForWriting;
+
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ dataForWriting = Files.readAllBytes(Paths.get("src/test/resources/example-image.jpg"));
+ }
+
+ @Test
+ public void whenUsingFileOutputStream_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-fos.jpg");
+ try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
+ outputStream.write(dataForWriting);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+ }
+
+ @Test
+ public void whenUsingNioFiles_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-nio-files.jpg");
+ Files.write(outputFile.toPath(), dataForWriting);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+
+ @Test
+ public void whenUsingGuavaFiles_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-guava-files.jpg");
+ com.google.common.io.Files.write(dataForWriting, outputFile);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+
+ @Test
+ public void whenUsingGuavaByteSink_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-guava-bs.jpg");
+ ByteSink byteSink = com.google.common.io.Files.asByteSink(outputFile);
+ byteSink.write(dataForWriting);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+
+ @Test
+ public void whenUsingGuavaByteSinkMoreFiles_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-guava-bs.jpg");
+ ByteSink byteSink = MoreFiles.asByteSink(outputFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
+ byteSink.write(dataForWriting);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+
+ @Test
+ public void whenUsingCommonsIo_thenByteArrayIsWritten() throws IOException {
+ File outputFile = tempFolder.newFile("example-file-utils.jpg");
+ FileUtils.writeByteArrayToFile(outputFile, dataForWriting);
+ assertThat(outputFile).hasBinaryContent(dataForWriting);
+ }
+}
diff --git a/core-java-modules/core-java-io-3/src/test/resources/example-image.jpg b/core-java-modules/core-java-io-3/src/test/resources/example-image.jpg
new file mode 100644
index 0000000000..43b8962793
Binary files /dev/null and b/core-java-modules/core-java-io-3/src/test/resources/example-image.jpg differ
diff --git a/core-java-modules/core-java-security-2/README.md b/core-java-modules/core-java-security-2/README.md
index bb5e204c98..9b99d624c9 100644
--- a/core-java-modules/core-java-security-2/README.md
+++ b/core-java-modules/core-java-security-2/README.md
@@ -14,4 +14,5 @@ This module contains articles about core Java Security
- [Get a List of Trusted Certificates in Java](https://www.baeldung.com/java-list-trusted-certificates)
- [Security Context Basics: User, Subject and Principal](https://www.baeldung.com/security-context-basics)
- [Java AES Encryption and Decryption](https://www.baeldung.com/java-aes-encryption-decryption)
+- [InvalidAlgorithmParameterException: Wrong IV Length](https://www.baeldung.com/java-invalidalgorithmparameter-exception)
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml
index 2f3965b237..0a9e818156 100644
--- a/core-java-modules/pom.xml
+++ b/core-java-modules/pom.xml
@@ -34,6 +34,7 @@
core-java-collections
core-java-collections-2
core-java-collections-3
+ core-java-collections-4
core-java-collections-array-list
core-java-collections-list
core-java-collections-list-2
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/bytearrays/BytesKey.java b/java-collections-maps-3/src/main/java/com/baeldung/map/bytearrays/BytesKey.java
new file mode 100644
index 0000000000..4bdcfe4b06
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/bytearrays/BytesKey.java
@@ -0,0 +1,28 @@
+package com.baeldung.map.bytearrays;
+
+import java.util.Arrays;
+
+public final class BytesKey {
+ private final byte[] array;
+
+ public BytesKey(byte[] array) {
+ this.array = array;
+ }
+
+ public byte[] getArray() {
+ return array.clone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BytesKey bytesKey = (BytesKey) o;
+ return Arrays.equals(array, bytesKey.array);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(array);
+ }
+}
diff --git a/java-collections-maps-3/src/test/java/com/baeldung/map/bytearrays/ByteArrayKeyUnitTest.java b/java-collections-maps-3/src/test/java/com/baeldung/map/bytearrays/ByteArrayKeyUnitTest.java
new file mode 100644
index 0000000000..8f5b89e11e
--- /dev/null
+++ b/java-collections-maps-3/src/test/java/com/baeldung/map/bytearrays/ByteArrayKeyUnitTest.java
@@ -0,0 +1,104 @@
+package com.baeldung.map.bytearrays;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Test;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ByteArrayKeyUnitTest {
+ @Test
+ void givenPrimitiveByteArrayKey_whenRetrievingFromMap_shouldRetrieveDifferentObjects() {
+ // given
+ byte[] key1 = {1, 2, 3};
+ byte[] key2 = {1, 2, 3};
+ String value1 = "value1";
+ String value2 = "value2";
+ Map map = new HashMap<>();
+ map.put(key1, value1);
+ map.put(key2, value2);
+
+ // when
+ String retrievedValue1 = map.get(key1);
+ String retrievedValue2 = map.get(key2);
+ String retrievedValue3 = map.get(new byte[]{1, 2, 3});
+
+ // then
+ assertThat(retrievedValue1).isEqualTo(value1);
+ assertThat(retrievedValue2).isEqualTo(value2);
+ assertThat(retrievedValue3).isNull();
+ }
+
+ @Test
+ void givenEncodedStringKey_whenRetrievingFromMap_shouldRetrieveLastPutObject() {
+ // given
+ String key1 = Base64.getEncoder().encodeToString(new byte[]{1, 2, 3});
+ String key2 = Base64.getEncoder().encodeToString(new byte[]{1, 2, 3});
+ String value1 = "value1";
+ String value2 = "value2";
+ Map map = new HashMap<>();
+ map.put(key1, value1);
+ map.put(key2, value2);
+
+ // when
+ String retrievedValue1 = map.get(key1);
+ String retrievedValue2 = map.get(key2);
+
+ // then
+ assertThat(key1).isEqualTo(key2);
+ assertThat(retrievedValue1).isEqualTo(value2);
+ assertThat(retrievedValue2).isEqualTo(value2);
+ assertThat(retrievedValue1).isEqualTo(retrievedValue2);
+ }
+
+ @Test
+ void givenByteListKey_whenRetrievingFromMap_shouldRetrieveLastPutObject() {
+ // given
+ List key1 = ImmutableList.of((byte)1, (byte)2, (byte)3);
+ List key2 = ImmutableList.of((byte)1, (byte)2, (byte)3);
+ String value1 = "value1";
+ String value2 = "value2";
+ Map, String> map = new HashMap<>();
+ map.put(key1, value1);
+ map.put(key2, value2);
+
+ // when
+ String retrievedValue1 = map.get(key1);
+ String retrievedValue2 = map.get(key2);
+
+ // then
+ assertThat(key1).isEqualTo(key2);
+ assertThat(retrievedValue1).isEqualTo(value2);
+ assertThat(retrievedValue2).isEqualTo(value2);
+ assertThat(retrievedValue1).isEqualTo(retrievedValue2);
+ }
+
+ @Test
+ void givenCustomWrapperKey_whenRetrievingFromMap_shouldRetrieveLastPutObject() {
+ // given
+ BytesKey key1 = new BytesKey(new byte[]{1, 2, 3});
+ BytesKey key2 = new BytesKey(new byte[]{1, 2, 3});
+ String value1 = "value1";
+ String value2 = "value2";
+ Map map = new HashMap<>();
+ map.put(key1, value1);
+ map.put(key2, value2);
+
+ // when
+ String retrievedValue1 = map.get(key1);
+ String retrievedValue2 = map.get(key2);
+ String retrievedValue3 = map.get(new BytesKey(new byte[]{1, 2, 3}));
+
+ // then
+ assertThat(key1).isEqualTo(key2);
+ assertThat(retrievedValue1).isEqualTo(value2);
+ assertThat(retrievedValue2).isEqualTo(value2);
+ assertThat(retrievedValue1).isEqualTo(retrievedValue2);
+ assertThat(retrievedValue3).isEqualTo(value2);
+
+ }
+}
diff --git a/java-numbers-4/src/test/java/com/baeldung/perfectsquare/PerfectSquareUnitTest.java b/java-numbers-4/src/test/java/com/baeldung/perfectsquare/PerfectSquareUnitTest.java
index 334b95ea9d..83fce31047 100644
--- a/java-numbers-4/src/test/java/com/baeldung/perfectsquare/PerfectSquareUnitTest.java
+++ b/java-numbers-4/src/test/java/com/baeldung/perfectsquare/PerfectSquareUnitTest.java
@@ -6,22 +6,21 @@ import static org.junit.Assert.assertEquals;
public class PerfectSquareUnitTest {
@Test
- public void test0xFFAssignedToInteger() {
+ public void testIsNumberPerfectSquare() {
long n = 18676209273604L; // 18676209273604 = 43621598 * 43621598
boolean expectedValue = true;
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingSqrt(n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingBinarySearch(1, Integer.MAX_VALUE, n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingNewtonMethod(n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareWithOptimization(n));
- }
- @Test
- public void test0xFFAssignedToByte() {
- long n = 549790047707L; // prime number
- boolean expectedValue = false;
+ n = 549790047707L; // prime number
+ expectedValue = false;
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingSqrt(n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingBinarySearch(1, Integer.MAX_VALUE, n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareByUsingNewtonMethod(n));
assertEquals(expectedValue, PerfectSquareUtil.isPerfectSquareWithOptimization(n));
}
+
+
}
diff --git a/persistence-modules/core-java-persistence-2/README.md b/persistence-modules/core-java-persistence-2/README.md
index 467de757ce..36c33cc6e1 100644
--- a/persistence-modules/core-java-persistence-2/README.md
+++ b/persistence-modules/core-java-persistence-2/README.md
@@ -1,3 +1,4 @@
### Relevant Articles:
- [Getting Database URL From JDBC Connection Object](https://www.baeldung.com/jdbc-get-url-from-connection)
+- [JDBC URL Format For Different Databases](https://www.baeldung.com/java-jdbc-url-format)
diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml
index 9845d5009d..a1088b0801 100644
--- a/persistence-modules/core-java-persistence-2/pom.xml
+++ b/persistence-modules/core-java-persistence-2/pom.xml
@@ -20,10 +20,43 @@
h2
${h2.version}
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ test
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.driver.version}
+
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ ${mssql.driver.version}
+
+
1.4.200
+ 42.2.5.jre7
+ 8.4.1.jre11
+ 10.2.0.4.0
+ 8.0.22
-
\ No newline at end of file
+
diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/jdbcurlformat/JdbcUrlFormatLiveTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/jdbcurlformat/JdbcUrlFormatLiveTest.java
new file mode 100644
index 0000000000..fc00119704
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/jdbcurlformat/JdbcUrlFormatLiveTest.java
@@ -0,0 +1,86 @@
+package com.baeldung.jdbcurlformat;
+
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import static org.junit.Assert.assertNotNull;
+
+public class JdbcUrlFormatLiveTest {
+ @Test
+ public void givenOracleSID_thenCreateConnectionObject() {
+ String oracleJdbcUrl = "jdbc:oracle:thin:@myoracle.db.server:1521:my_sid";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(oracleJdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void givenOracleServiceName_thenCreateConnectionObject() {
+ String oracleJdbcUrl = "jdbc:oracle:thin:@//myoracle.db.server:1521/my_servicename";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(oracleJdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void givenOracleTnsnames_thenCreateConnectionObject() {
+ String oracleJdbcUrl = "jdbc:oracle:thin:@" +
+ "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)" +
+ "(HOST=myoracle.db.server)(PORT=1521))" +
+ "(CONNECT_DATA=(SERVICE_NAME=my_servicename)))";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(oracleJdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void givenMysqlDb_thenCreateConnectionObject() {
+ String jdbcUrl = "jdbc:mysql://mysql.db.server:3306/my_database?useSSL=false&serverTimezone=UTC";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void givenMssqlDb_thenCreateConnectionObject() {
+ String jdbcUrl = "jdbc:sqlserver://mssql.db.server\\mssql_instance;databaseName=my_database";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void givenPostgreSqlDb_thenCreateConnectionObject() {
+ String jdbcUrl = "jdbc:postgresql://postgresql.db.server:5430/my_database?ssl=true&loglevel=2";
+ String username = "dbUser";
+ String password = "1234567";
+ try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
+ assertNotNull(conn);
+ } catch (SQLException e) {
+ System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 17e4fe1584..f6e3ddad6c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -662,8 +662,7 @@
spring-mobile
spring-mockito
-
- spring-mvc-basics
+
spring-mvc-basics-2
spring-mvc-basics-3
spring-mvc-basics-4
@@ -714,6 +713,7 @@
spring-vault
spring-vertx
+ spring-web-modules
spring-webflux-amqp
spring-websockets
@@ -1148,8 +1148,7 @@
spring-mobile
spring-mockito
-
- spring-mvc-basics
+
spring-mvc-basics-2
spring-mvc-basics-3
spring-mvc-basics-4
@@ -1199,6 +1198,7 @@
spring-vault
spring-vertx
+ spring-web-modules
spring-webflux-amqp
spring-websockets
diff --git a/spring-apache-camel/pom.xml b/spring-apache-camel/pom.xml
index 2d0d632546..9c7cc14381 100644
--- a/spring-apache-camel/pom.xml
+++ b/spring-apache-camel/pom.xml
@@ -47,6 +47,17 @@
camel-spring-javaconfig
${env.camel.version}
+
+ org.apache.camel
+ camel-jackson
+ ${env.camel.version}
+
+
+ org.apache.camel
+ camel-test
+ ${env.camel.version}
+ test
+
diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java b/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java
new file mode 100644
index 0000000000..1932131ddd
--- /dev/null
+++ b/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java
@@ -0,0 +1,24 @@
+package com.baeldung.camel.jackson;
+
+public class Fruit {
+
+ private String name;
+ private int id;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+}
diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java b/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java
new file mode 100644
index 0000000000..02f2b6feb0
--- /dev/null
+++ b/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java
@@ -0,0 +1,17 @@
+package com.baeldung.camel.jackson;
+
+import java.util.List;
+
+public class FruitList {
+
+ private List fruits;
+
+ public List getFruits() {
+ return fruits;
+ }
+
+ public void setFruits(List fruits) {
+ this.fruits = fruits;
+ }
+
+}
diff --git a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java
new file mode 100644
index 0000000000..4810d7370e
--- /dev/null
+++ b/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java
@@ -0,0 +1,60 @@
+package com.baeldung.camel.jackson;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jackson.ListJacksonDataFormat;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport {
+
+ @Test
+ public void givenJsonFruitArray_whenUnmarshalled_thenSuccess() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:marshalledObject");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(List.class);
+
+ String json = readJsonFromFile("/json/fruit-array.json");
+ template.sendBody("direct:jsonInput", json);
+ assertMockEndpointsSatisfied();
+
+ @SuppressWarnings("unchecked")
+ List fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(List.class);
+ assertNotNull("Fruit lists should not be null", fruitList);
+
+ assertEquals("There should be two fruits", 2, fruitList.size());
+
+ Fruit fruit = fruitList.get(0);
+ assertEquals("Fruit name", "Banana", fruit.getName());
+ assertEquals("Fruit id", 100, fruit.getId());
+
+ fruit = fruitList.get(1);
+ assertEquals("Fruit name", "Apple", fruit.getName());
+ assertEquals("Fruit id", 101, fruit.getId());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+
+ from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class))
+ .to("mock:marshalledObject");
+ }
+ };
+ }
+
+ private String readJsonFromFile(String path) throws URISyntaxException, IOException {
+ URL resource = FruitArrayJacksonUnmarshalUnitTest.class.getResource(path);
+ return new String(Files.readAllBytes(Paths.get(resource.toURI())));
+ }
+
+}
diff --git a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java
new file mode 100644
index 0000000000..b5647f02f9
--- /dev/null
+++ b/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java
@@ -0,0 +1,59 @@
+package com.baeldung.camel.jackson;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jackson.JacksonDataFormat;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport {
+
+ @Test
+ public void givenJsonFruitList_whenUnmarshalled_thenSuccess() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:marshalledObject");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(FruitList.class);
+
+ String json = readJsonFromFile("/json/fruit-list.json");
+ template.sendBody("direct:jsonInput", json);
+ assertMockEndpointsSatisfied();
+
+ FruitList fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(FruitList.class);
+ assertNotNull("Fruit lists should not be null", fruitList);
+
+ List fruits = fruitList.getFruits();
+ assertEquals("There should be two fruits", 2, fruits.size());
+
+ Fruit fruit = fruits.get(0);
+ assertEquals("Fruit name", "Banana", fruit.getName());
+ assertEquals("Fruit id", 100, fruit.getId());
+
+ fruit = fruits.get(1);
+ assertEquals("Fruit name", "Apple", fruit.getName());
+ assertEquals("Fruit id", 101, fruit.getId());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class))
+ .to("mock:marshalledObject");
+ }
+ };
+ }
+
+ private String readJsonFromFile(String path) throws URISyntaxException, IOException {
+ URL resource = FruitListJacksonUnmarshalUnitTest.class.getResource(path);
+ return new String(Files.readAllBytes(Paths.get(resource.toURI())));
+ }
+
+}
diff --git a/spring-apache-camel/src/test/resources/json/fruit-array.json b/spring-apache-camel/src/test/resources/json/fruit-array.json
new file mode 100644
index 0000000000..0bd917c53f
--- /dev/null
+++ b/spring-apache-camel/src/test/resources/json/fruit-array.json
@@ -0,0 +1,10 @@
+[
+ {
+ "id": 100,
+ "name": "Banana"
+ },
+ {
+ "id": 101,
+ "name": "Apple"
+ }
+]
\ No newline at end of file
diff --git a/spring-apache-camel/src/test/resources/json/fruit-list.json b/spring-apache-camel/src/test/resources/json/fruit-list.json
new file mode 100644
index 0000000000..357e08f7d5
--- /dev/null
+++ b/spring-apache-camel/src/test/resources/json/fruit-list.json
@@ -0,0 +1,12 @@
+{
+ "fruits": [
+ {
+ "id": 100,
+ "name": "Banana"
+ },
+ {
+ "id": 101,
+ "name": "Apple"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index 44b3e28291..825af8fb9e 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -69,6 +69,7 @@
spring-boot-vue
spring-boot-xml
spring-boot-actuator
+ spring-boot-data-2
diff --git a/spring-boot-modules/spring-boot-data-2/pom.xml b/spring-boot-modules/spring-boot-data-2/pom.xml
new file mode 100644
index 0000000000..199a204500
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/pom.xml
@@ -0,0 +1,21 @@
+
+
+
+ com.baeldung.spring-boot-modules
+ spring-boot-modules
+ 1.0.0-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ spring-boot-data-2
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/app/Application.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/app/Application.java
new file mode 100644
index 0000000000..6f57a534a8
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/app/Application.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.jackson.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(basePackages = "com.baeldung.boot.jackson.controller")
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java
new file mode 100644
index 0000000000..d1875d03d9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class CoffeeConstants {
+
+ public static final String DATETIME_FORMAT = "dd-MM-yyyy HH:mm";
+ public static final LocalDateTime FIXED_DATE = LocalDateTime.now();
+ public static LocalDateTimeSerializer LOCAL_DATETIME_SERIALIZER = new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATETIME_FORMAT));
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java
new file mode 100644
index 0000000000..edb2b478fc
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java
@@ -0,0 +1,18 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
+
+@Configuration
+public class CoffeeCustomizerConfig {
+
+ @Bean
+ public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
+ return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
+ .serializers(LOCAL_DATETIME_SERIALIZER);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java
new file mode 100644
index 0000000000..eff2b5c252
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
+
+@Configuration
+public class CoffeeHttpConverterConfiguration {
+
+ @Bean
+ public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
+ Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
+ .serializers(LOCAL_DATETIME_SERIALIZER)
+ .serializationInclusion(JsonInclude.Include.NON_NULL);
+ return new MappingJackson2HttpMessageConverter(builder.build());
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java
new file mode 100644
index 0000000000..8057fff3db
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
+
+@Configuration
+public class CoffeeJacksonBuilderConfig {
+
+ @Bean
+ @Primary
+ public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
+ return new Jackson2ObjectMapperBuilder()
+ .serializers(LOCAL_DATETIME_SERIALIZER)
+ .serializationInclusion(JsonInclude.Include.NON_NULL);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java
new file mode 100644
index 0000000000..f1ce6458ae
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java
@@ -0,0 +1,23 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
+
+@Configuration
+public class CoffeeObjectMapperConfig {
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ JavaTimeModule module = new JavaTimeModule();
+ module.addSerializer(LOCAL_DATETIME_SERIALIZER);
+ return new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL)
+ .registerModule(module);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java
new file mode 100644
index 0000000000..fc157f8156
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.jackson.config;
+
+import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER;
+
+@Configuration
+@PropertySource("classpath:coffee.properties")
+public class CoffeeRegisterModuleConfig {
+
+ @Bean
+ public Module javaTimeModule() {
+ JavaTimeModule module = new JavaTimeModule();
+ module.addSerializer(LOCAL_DATETIME_SERIALIZER);
+ return module;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java
new file mode 100644
index 0000000000..23749b18a2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.jackson.controller;
+
+import com.baeldung.boot.jackson.model.Coffee;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE;
+
+@RestController
+public class CoffeeController {
+
+ @GetMapping("/coffee")
+ public Coffee getCoffee(
+ @RequestParam(required = false) String brand,
+ @RequestParam(required = false) String name) {
+ return new Coffee().setBrand(brand)
+ .setDate(FIXED_DATE)
+ .setName(name);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/model/Coffee.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/model/Coffee.java
new file mode 100644
index 0000000000..4df6b4bd6d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/model/Coffee.java
@@ -0,0 +1,39 @@
+package com.baeldung.boot.jackson.model;
+
+import java.time.LocalDateTime;
+
+public class Coffee {
+
+ private String name;
+
+ private String brand;
+
+ private LocalDateTime date;
+
+ public String getName() {
+ return name;
+ }
+
+ public Coffee setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public String getBrand() {
+ return brand;
+ }
+
+ public Coffee setBrand(String brand) {
+ this.brand = brand;
+ return this;
+ }
+
+ public LocalDateTime getDate() {
+ return date;
+ }
+
+ public Coffee setDate(LocalDateTime date) {
+ this.date = date;
+ return this;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/resources/coffee.properties b/spring-boot-modules/spring-boot-data-2/src/main/resources/coffee.properties
new file mode 100644
index 0000000000..269845cbf1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/resources/coffee.properties
@@ -0,0 +1 @@
+spring.jackson.default-property-inclusion=non_null
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java
new file mode 100644
index 0000000000..f1bc35a8ce
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java
@@ -0,0 +1,33 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeConstants;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+
+import java.time.format.DateTimeFormatter;
+
+import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public abstract class AbstractCoffeeIntegrationTest {
+
+ @Autowired
+ protected TestRestTemplate restTemplate;
+
+ @Test
+ public void whenGetCoffee_thenSerializedWithDateAndNonNull() {
+ String formattedDate = DateTimeFormatter.ofPattern(CoffeeConstants.DATETIME_FORMAT)
+ .format(FIXED_DATE);
+
+ String brand = "Lavazza";
+ String url = "/coffee?brand=" + brand;
+
+ String response = restTemplate.getForObject(url, String.class);
+
+ assertThat(response).isEqualTo(
+ "{\"brand\":\"" + brand + "\",\"date\":\"" + formattedDate + "\"}");
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java
new file mode 100644
index 0000000000..d690de1b9c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeCustomizerConfig;
+import org.springframework.context.annotation.Import;
+
+@Import(CoffeeCustomizerConfig.class)
+public class CoffeeCustomizerIntegrationTest extends AbstractCoffeeIntegrationTest {
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java
new file mode 100644
index 0000000000..62b1d42152
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeHttpConverterConfiguration;
+import org.springframework.context.annotation.Import;
+
+@Import(CoffeeHttpConverterConfiguration.class)
+public class CoffeeHttpConverterIntegrationTest extends AbstractCoffeeIntegrationTest {
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java
new file mode 100644
index 0000000000..52a55394c0
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeJacksonBuilderConfig;
+import org.springframework.context.annotation.Import;
+
+@Import(CoffeeJacksonBuilderConfig.class)
+public class CoffeeJacksonBuilderIntegrationTest extends AbstractCoffeeIntegrationTest {
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java
new file mode 100644
index 0000000000..34743ceba5
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeObjectMapperConfig;
+import org.springframework.context.annotation.Import;
+
+@Import(CoffeeObjectMapperConfig.class)
+public class CoffeeObjectMapperIntegrationTest extends AbstractCoffeeIntegrationTest {
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java
new file mode 100644
index 0000000000..69bbd5be2a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.boot.jackson.app;
+
+import com.baeldung.boot.jackson.config.CoffeeRegisterModuleConfig;
+import org.springframework.context.annotation.Import;
+
+@Import(CoffeeRegisterModuleConfig.class)
+public class CoffeeRegisterModuleIntegrationTest extends AbstractCoffeeIntegrationTest {
+}
diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/reloading/configs/ReloadablePropertySource.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/reloading/configs/ReloadablePropertySource.java
index 6d76a2e1e2..5d4e170226 100644
--- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/reloading/configs/ReloadablePropertySource.java
+++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/reloading/configs/ReloadablePropertySource.java
@@ -15,7 +15,7 @@ public class ReloadablePropertySource extends PropertySource {
}
public ReloadablePropertySource(String name, String path) {
- super(StringUtils.isEmpty(name) ? path : name);
+ super(StringUtils.hasText(name) ? path : name);
try {
this.propertiesConfiguration = new PropertiesConfiguration(path);
FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();
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 fc9bb42a95..61d462bb5a 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,7 +6,9 @@ spring:
---
spring:
- profiles: test
+ config:
+ activate:
+ on-profile: test
name: test-YAML
environment: testing
enabled: false
@@ -37,7 +39,9 @@ component:
---
spring:
- profiles: prod
+ config:
+ activate:
+ on-profile: prod
name: prod-YAML
environment: production
enabled: true
@@ -48,7 +52,9 @@ servers:
---
spring:
- profiles: dev
+ config:
+ activate:
+ on-profile: dev
name: ${DEV_NAME:dev-YAML}
environment: development
enabled: true
diff --git a/spring-cloud/spring-cloud-eureka/pom.xml b/spring-cloud/spring-cloud-eureka/pom.xml
index 7af0c15352..9d7350e774 100644
--- a/spring-cloud/spring-cloud-eureka/pom.xml
+++ b/spring-cloud/spring-cloud-eureka/pom.xml
@@ -19,6 +19,7 @@
spring-cloud-eureka-server
spring-cloud-eureka-client
spring-cloud-eureka-feign-client
+ spring-cloud-eureka-feign-client-integration-test
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml
new file mode 100644
index 0000000000..3348dbb24f
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml
@@ -0,0 +1,97 @@
+
+
+ 4.0.0
+ spring-cloud-eureka-feign-client-integration-test
+ 1.0.0-SNAPSHOT
+ spring-cloud-eureka-feign-client-integration-test
+ jar
+ Spring Cloud Eureka - Feign Client Integration Tests
+
+
+ com.baeldung.spring.cloud
+ spring-cloud-eureka
+ 1.0.0-SNAPSHOT
+
+
+
+
+
+ org.junit
+ junit-bom
+ ${junit-jupiter.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-starter-parent
+ ${spring-cloud-dependencies.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-ribbon
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.github.tomakehurst
+ wiremock
+ 2.27.2
+ test
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.testcontainers
+ testcontainers
+ 1.14.3
+ test
+
+
+
+ org.awaitility
+ awaitility
+ 4.0.3
+ test
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+ 1
+ true
+
+
+
+
+
+
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java
new file mode 100644
index 0000000000..342e7e163b
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.cloud;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@EnableFeignClients
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java
new file mode 100644
index 0000000000..a263624b28
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java
@@ -0,0 +1,16 @@
+package com.baeldung.spring.cloud.client;
+
+import com.baeldung.spring.cloud.model.Book;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.util.List;
+
+@FeignClient("books-service")
+//@FeignClient(value="simple-books-client", url="${book.service.url}")
+public interface BooksClient {
+
+ @RequestMapping("/books")
+ List getBooks();
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java
new file mode 100644
index 0000000000..64492f678d
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.cloud.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Book {
+
+ private String title;
+ private String author;
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BookMocks.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BookMocks.java
new file mode 100644
index 0000000000..2cce72e6cb
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BookMocks.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.cloud.client;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import java.io.IOException;
+
+import static java.nio.charset.Charset.defaultCharset;
+import static org.springframework.util.StreamUtils.copyToString;
+
+public class BookMocks {
+
+ public static void setupMockBooksResponse(WireMockServer mockService) throws IOException {
+ mockService.stubFor(WireMock.get(WireMock.urlEqualTo("/books"))
+ .willReturn(
+ WireMock.aResponse()
+ .withStatus(HttpStatus.OK.value())
+ .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
+ .withBody(
+ copyToString(
+ BookMocks.class.getClassLoader().getResourceAsStream("payload/get-books-response.json"),
+ defaultCharset()))));
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java
new file mode 100644
index 0000000000..2842eef435
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java
@@ -0,0 +1,53 @@
+package com.baeldung.spring.cloud.client;
+
+import com.baeldung.spring.cloud.model.Book;
+import com.github.tomakehurst.wiremock.WireMockServer;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.io.IOException;
+
+import static com.baeldung.spring.cloud.client.BookMocks.setupMockBooksResponse;
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest
+@ActiveProfiles("test")
+@EnableConfigurationProperties
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = { WireMockConfig.class })
+class BooksClientIntegrationTest {
+
+ @Autowired
+ private WireMockServer mockBooksService;
+
+ @Autowired
+ private BooksClient booksClient;
+
+ @BeforeEach
+ void setUp() throws IOException {
+ setupMockBooksResponse(mockBooksService);
+ }
+
+ @Test
+ public void whenGetBooks_thenBooksShouldBeReturned() {
+ assertFalse(booksClient.getBooks().isEmpty());
+ }
+
+ @Test
+ public void whenGetBooks_thenTheCorrectBooksShouldBeReturned() {
+ assertTrue(booksClient.getBooks()
+ .containsAll(asList(
+ new Book("Dune", "Frank Herbert"),
+ new Book("Foundation", "Isaac Asimov"))));
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java
new file mode 100644
index 0000000000..6747d14b88
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java
@@ -0,0 +1,39 @@
+package com.baeldung.spring.cloud.client;
+
+import org.jetbrains.annotations.NotNull;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.test.util.TestPropertyValues;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.context.ActiveProfiles;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.lifecycle.Startables;
+
+import java.util.stream.Stream;
+
+@TestConfiguration
+@ActiveProfiles("eureka-test")
+public class EurekaContainerConfig {
+
+ public static class Initializer implements ApplicationContextInitializer {
+
+ public static GenericContainer eurekaServer
+ = new GenericContainer("springcloud/eureka")
+ .withExposedPorts(8761);
+
+ @Override
+ public void initialize(@NotNull ConfigurableApplicationContext configurableApplicationContext) {
+
+ Startables.deepStart(Stream.of(eurekaServer)).join();
+
+ TestPropertyValues
+ .of("eureka.client.serviceUrl.defaultZone=http://localhost:"
+ + eurekaServer.getFirstMappedPort().toString()
+ + "/eureka")
+ .applyTo(configurableApplicationContext);
+
+ }
+
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java
new file mode 100644
index 0000000000..f05df11ba3
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java
@@ -0,0 +1,65 @@
+package com.baeldung.spring.cloud.client;
+
+import com.baeldung.spring.cloud.model.Book;
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.io.IOException;
+
+import static com.baeldung.spring.cloud.client.BookMocks.setupMockBooksResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.moreThan;
+import static java.util.Arrays.asList;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest
+@ActiveProfiles("ribbon-test")
+@EnableConfigurationProperties
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = { RibbonTestConfig.class })
+class LoadBalancerBooksClientIntegrationTest {
+
+ @Autowired
+ private WireMockServer mockBooksService;
+
+ @Autowired
+ private WireMockServer secondMockBooksService;
+
+ @Autowired
+ private BooksClient booksClient;
+
+ @BeforeEach
+ void setUp() throws IOException {
+ setupMockBooksResponse(mockBooksService);
+ setupMockBooksResponse(secondMockBooksService);
+ }
+
+ @Test
+ void whenGetBooks_thenRequestsAreLoadBalanced() {
+ for (int k = 0; k < 10; k++) {
+ booksClient.getBooks();
+ }
+
+ mockBooksService.verify(
+ moreThan(0), getRequestedFor(WireMock.urlEqualTo("/books")));
+ secondMockBooksService.verify(
+ moreThan(0), getRequestedFor(WireMock.urlEqualTo("/books")));
+ }
+
+ @Test
+ public void whenGetBooks_thenTheCorrectBooksShouldBeReturned() {
+ assertTrue(booksClient.getBooks()
+ .containsAll(asList(
+ new Book("Dune", "Frank Herbert"),
+ new Book("Foundation", "Isaac Asimov"))));
+ }
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java
new file mode 100644
index 0000000000..1fff2ec9c0
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java
@@ -0,0 +1,22 @@
+package com.baeldung.spring.cloud.client;
+
+import com.baeldung.spring.cloud.model.Book;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+
+@Configuration
+@RestController
+@ActiveProfiles("eureka-test")
+public class MockBookServiceConfig {
+
+ @RequestMapping("/books")
+ public List getBooks() {
+ return Collections.singletonList(new Book("Hitchhiker's guide to the galaxy", "Douglas Adams"));
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java
new file mode 100644
index 0000000000..273ba182b1
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java
@@ -0,0 +1,41 @@
+package com.baeldung.spring.cloud.client;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.netflix.loadbalancer.Server;
+import com.netflix.loadbalancer.ServerList;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.cloud.netflix.ribbon.StaticServerList;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.ActiveProfiles;
+
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
+
+@TestConfiguration
+@ActiveProfiles("ribbon-test")
+public class RibbonTestConfig {
+
+ @Autowired
+ private WireMockServer mockBooksService;
+
+ @Autowired
+ private WireMockServer secondMockBooksService;
+
+ @Bean(initMethod = "start", destroyMethod = "stop")
+ public WireMockServer mockBooksService() {
+ return new WireMockServer(options().dynamicPort());
+ }
+
+ @Bean(name="secondMockBooksService", initMethod = "start", destroyMethod = "stop")
+ public WireMockServer secondBooksMockService() {
+ return new WireMockServer(options().dynamicPort());
+ }
+
+ @Bean
+ public ServerList ribbonServerList() {
+ return new StaticServerList<>(
+ new Server("localhost", mockBooksService.port()),
+ new Server("localhost", secondMockBooksService.port()));
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/ServiceDiscoveryBooksClientIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/ServiceDiscoveryBooksClientIntegrationTest.java
new file mode 100644
index 0000000000..027579d20d
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/ServiceDiscoveryBooksClientIntegrationTest.java
@@ -0,0 +1,52 @@
+package com.baeldung.spring.cloud.client;
+
+import com.baeldung.spring.cloud.Application;
+import com.baeldung.spring.cloud.model.Book;
+import com.netflix.discovery.EurekaClient;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.List;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@ActiveProfiles("eureka-test")
+@EnableConfigurationProperties
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ContextConfiguration(classes = { MockBookServiceConfig.class }, initializers = { EurekaContainerConfig.Initializer.class })
+class ServiceDiscoveryBooksClientIntegrationTest {
+
+ @Autowired
+ private BooksClient booksClient;
+
+ @Lazy
+ @Autowired
+ private EurekaClient eurekaClient;
+
+ @BeforeEach
+ void setUp() {
+ await().atMost(60, SECONDS).until(() -> eurekaClient.getApplications().size() > 0);
+ }
+
+ @Test
+ public void whenGetBooks_thenTheCorrectBooksAreReturned() {
+ List books = booksClient.getBooks();
+
+ assertEquals(1, books.size());
+ assertEquals(
+ new Book("Hitchhiker's guide to the galaxy", "Douglas Adams"),
+ books.stream().findFirst().get());
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java
new file mode 100644
index 0000000000..82b7cddede
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java
@@ -0,0 +1,17 @@
+package com.baeldung.spring.cloud.client;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.ActiveProfiles;
+
+@TestConfiguration
+@ActiveProfiles("test")
+public class WireMockConfig {
+
+ @Bean(initMethod = "start", destroyMethod = "stop")
+ public WireMockServer mockBooksService() {
+ return new WireMockServer(9561);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-eureka-test.yml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-eureka-test.yml
new file mode 100644
index 0000000000..6f6af6a080
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-eureka-test.yml
@@ -0,0 +1,3 @@
+spring:
+ application:
+ name: books-service
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml
new file mode 100644
index 0000000000..84a78d0ec7
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml
@@ -0,0 +1,3 @@
+eureka:
+ client:
+ enabled: false
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml
new file mode 100644
index 0000000000..dce11adf69
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml
@@ -0,0 +1,11 @@
+#book:
+# service:
+# url: http://localhost:9561
+
+books-service:
+ ribbon:
+ listOfServers: http://localhost:9561
+
+eureka:
+ client:
+ enabled: false
diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json
new file mode 100644
index 0000000000..b4223ff8f2
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json
@@ -0,0 +1,10 @@
+[
+ {
+ "title": "Dune",
+ "author": "Frank Herbert"
+ },
+ {
+ "title": "Foundation",
+ "author": "Isaac Asimov"
+ }
+]
diff --git a/spring-resttemplate-2/pom.xml b/spring-resttemplate-2/pom.xml
index 2aed154be6..1404a35f33 100644
--- a/spring-resttemplate-2/pom.xml
+++ b/spring-resttemplate-2/pom.xml
@@ -71,16 +71,16 @@
ch.qos.logback
logback-classic
-
+
-
+
-
- org.springframework.boot
- spring-boot-maven-plugin
-
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
-
+
\ No newline at end of file
diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java
new file mode 100644
index 0000000000..751e234e8b
--- /dev/null
+++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java
@@ -0,0 +1,16 @@
+package com.baeldung.resttemplate.json.consumer.service;
+
+import java.util.List;
+
+public interface UserConsumerService {
+
+ List processUserDataFromObjectArray();
+
+ List processUserDataFromUserArray();
+
+ List processUserDataFromUserList();
+
+ List processNestedUserDataFromUserArray();
+
+ List processNestedUserDataFromUserList();
+}
diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java
new file mode 100644
index 0000000000..dc1566d971
--- /dev/null
+++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java
@@ -0,0 +1,90 @@
+package com.baeldung.resttemplate.json.consumer.service;
+
+import com.baeldung.resttemplate.json.model.Address;
+import com.baeldung.resttemplate.json.model.User;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class UserConsumerServiceImpl implements UserConsumerService {
+
+ private static final String BASE_URL = "http://localhost:8080/users";
+ private final RestTemplate restTemplate;
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ public UserConsumerServiceImpl(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public List processUserDataFromObjectArray() {
+ ResponseEntity