diff --git a/core-java-modules/core-java-11-2/pom.xml b/core-java-modules/core-java-11-2/pom.xml
index 3d008f5294..5f76c0bf3b 100644
--- a/core-java-modules/core-java-11-2/pom.xml
+++ b/core-java-modules/core-java-11-2/pom.xml
@@ -50,6 +50,11 @@
${junit.jupiter.version}
test
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
@@ -73,6 +78,7 @@
5.7.0
3.17.2
5.11.1
+ 3.12.0
\ No newline at end of file
diff --git a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java
new file mode 100644
index 0000000000..fb7d5647a5
--- /dev/null
+++ b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java
@@ -0,0 +1,48 @@
+package com.baeldung.version;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+public class VersionUnitTest {
+
+ @Test
+ public void givenJava_whenUsingRuntime_thenGetVersion() {
+ String expectedVersion = "11";
+ Runtime.Version runtimeVersion = Runtime.version();
+ String version = String.valueOf(runtimeVersion.version().get(0));
+ Assertions.assertThat(version).isEqualTo(expectedVersion);
+ }
+
+ @Test
+ @Disabled("Only valid for Java 8 and lower")
+ public void givenJava_whenUsingCommonsLang_thenGetVersion() {
+ int expectedVersion = 8;
+ String[] versionElements = SystemUtils.JAVA_SPECIFICATION_VERSION.split("\\.");
+ int discard = Integer.parseInt(versionElements[0]);
+ int version;
+ if (discard == 1) {
+ version = Integer.parseInt(versionElements[1]);
+ } else {
+ version = discard;
+ }
+ Assertions.assertThat(version).isEqualTo(expectedVersion);
+ }
+
+ @Test
+ @Disabled("Only valid for Java 8 and lower")
+ public void givenJava_whenUsingSystemProp_thenGetVersion() {
+ int expectedVersion = 8;
+ String[] versionElements = System.getProperty("java.version").split("\\.");
+ int discard = Integer.parseInt(versionElements[0]);
+ int version;
+ if (discard == 1) {
+ version = Integer.parseInt(versionElements[1]);
+ } else {
+ version = discard;
+ }
+ Assertions.assertThat(version).isEqualTo(expectedVersion);
+ }
+}
+
diff --git a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml
index 13d0b2d201..774319a067 100644
--- a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml
+++ b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml
@@ -45,4 +45,4 @@
1.0
-
\ No newline at end of file
+
diff --git a/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java
new file mode 100644
index 0000000000..79d2396816
--- /dev/null
+++ b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java
@@ -0,0 +1,91 @@
+package com.baeldung.hash;
+
+import java.util.Objects;
+
+public class Player {
+ private String firstName;
+ private String lastName;
+ private String position;
+
+ public Player() {
+
+ }
+
+ public Player(String firstName, String lastName, String position) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.position = position;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getPosition() {
+ return position;
+ }
+
+ public void setPosition(String position) {
+ this.position = position;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(firstName, lastName, position);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ Player other = (Player) obj;
+
+ if (firstName == null) {
+ if (other.firstName != null) {
+ return false;
+ }
+ } else if (!firstName.equals(other.firstName)) {
+ return false;
+ }
+
+ if (lastName == null) {
+ if (other.lastName != null) {
+ return false;
+ }
+ } else if (!lastName.equals(other.lastName)) {
+ return false;
+ }
+
+ if (position == null) {
+ if (other.position != null) {
+ return false;
+ }
+ } else if (!position.equals(other.position)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java
new file mode 100644
index 0000000000..d1a9e06611
--- /dev/null
+++ b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java
@@ -0,0 +1,67 @@
+package com.baeldung.hash;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class HashCodeUnitTest {
+
+ @Test
+ public void whenCallingObjectsHashCodeOnIndenticalObjects_thenSameHashCodeReturned() {
+ String stringOne = "test";
+ String stringTwo = "test";
+ int hashCode1 = Objects.hashCode(stringOne);
+ int hashCode2 = Objects.hashCode(stringTwo);
+
+ assertEquals(hashCode1, hashCode2);
+ }
+
+ @Test
+ public void whenCallingObjectsHashCodeOnNullObject_thenZeroReturned() {
+ String nullString = null;
+ int hashCode = Objects.hashCode(nullString);
+ assertEquals(0, hashCode);
+ }
+
+ @Test
+ public void whenCallingObjectHashCodeOnIndenticalObjects_thenSameHashCodeReturned() {
+ Double valueOne = Double.valueOf(1.0012);
+ Double valueTwo = Double.valueOf(1.0012);
+
+ int hashCode1 = valueOne.hashCode();
+ int hashCode2 = valueTwo.hashCode();
+
+ assertEquals(hashCode1, hashCode2);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void whenCallingObjectHashCodeOnNullObject_theNullPointerExceptionThrown() {
+ Double value = null;
+ value.hashCode();
+ }
+
+ @Test
+ public void whenCallingObjectsHashOnStrings_thenSameHashCodeReturned() {
+ String strOne = "one";
+ String strTwo = "two";
+ String strOne2 = "one";
+ String strTwo2 = "two";
+
+ int hashCode1 = Objects.hash(strOne, strTwo);
+ int hashCode2 = Objects.hash(strOne2, strTwo2);
+
+ assertEquals(hashCode1, hashCode2);
+ }
+
+ @Test
+ public void whenCallingObjectsHashOnSingleString_thenDifferentHashcodeFromObjectsHashCodeCallReturned() {
+ String testString = "test string";
+ int hashCode1 = Objects.hash(testString);
+ int hashCode2 = Objects.hashCode(testString);
+
+ assertNotEquals(hashCode1, hashCode2);
+ }
+}
diff --git a/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java
new file mode 100644
index 0000000000..fe0ef8a727
--- /dev/null
+++ b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java
@@ -0,0 +1,33 @@
+package com.baeldung.hash;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class PlayerUnitTest {
+
+ @Test
+ public void whenCallingHashCodeOnIdenticalValue_thenSameHashCodeReturned() {
+ Player player = new Player("Eduardo", "Rodriguez", "Pitcher");
+ Player indenticalPlayer = new Player("Eduardo", "Rodriguez", "Pitcher");
+
+ int hashCode1 = player.hashCode();
+ int hashCode2 = player.hashCode();
+ int hashCode3 = indenticalPlayer.hashCode();
+
+ assertEquals(hashCode1, hashCode2);
+ assertEquals(hashCode1, hashCode3);
+ }
+
+ @Test
+ public void whenCallingHashCodeAndArraysHashCode_thenSameHashCodeReturned() {
+ Player player = new Player("Bobby", "Dalbec", "First Base");
+ int hashcode1 = player.hashCode();
+ String[] playerInfo = { "Bobby", "Dalbec", "First Base" };
+ int hashcode2 = Arrays.hashCode(playerInfo);
+
+ assertEquals(hashcode1, hashcode2);
+ }
+}
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java
new file mode 100644
index 0000000000..6f17ecc536
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java
@@ -0,0 +1,42 @@
+package com.baeldung.interfacevsabstractclass;
+
+public class Car extends Vehicle {
+
+ public Car(String vechicleName) {
+ super(vechicleName);
+ }
+
+ public Car(String vechicleName, String vehicleModel) {
+ super(vechicleName, vehicleModel);
+ }
+
+ public Car(String vechicleName, String vehicleModel, Long makeYear) {
+ super(vechicleName, vehicleModel, makeYear);
+ }
+
+ @Override
+ protected void start() {
+ // code implementation details on starting a car.
+ }
+
+ @Override
+ protected void stop() {
+ // code implementation details on stopping a car.
+ }
+
+ @Override
+ protected void drive() {
+ // code implementation details on start driving a car.
+ }
+
+ @Override
+ protected void changeGear() {
+ // code implementation details on changing the car gear.
+ }
+
+ @Override
+ protected void reverse() {
+ // code implementation details on reverse driving a car.
+ }
+
+}
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java
new file mode 100644
index 0000000000..1948cc6583
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java
@@ -0,0 +1,12 @@
+package com.baeldung.interfacevsabstractclass;
+
+import java.io.File;
+
+public class ImageSender implements Sender {
+
+ @Override
+ public void send(File fileToBeSent) {
+ // image sending implementation code.
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java
new file mode 100644
index 0000000000..fde6527ef6
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java
@@ -0,0 +1,8 @@
+package com.baeldung.interfacevsabstractclass;
+
+import java.io.File;
+
+public interface Sender {
+
+ void send(File fileToBeSent);
+}
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java
new file mode 100644
index 0000000000..d98b8ca93b
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java
@@ -0,0 +1,57 @@
+package com.baeldung.interfacevsabstractclass;
+
+public abstract class Vehicle {
+
+ private String vehicleName;
+ private String vehicleModel;
+ private Long makeYear;
+
+ public Vehicle(String vehicleName) {
+ this.vehicleName = vehicleName;
+ }
+
+ public Vehicle(String vehicleName, String vehicleModel) {
+ this(vehicleName);
+ this.vehicleModel = vehicleModel;
+ }
+
+ public Vehicle(String vechicleName, String vehicleModel, Long makeYear) {
+ this(vechicleName, vehicleModel);
+ this.makeYear = makeYear;
+ }
+
+ public String getVehicleName() {
+ return vehicleName;
+ }
+
+ public void setVehicleName(String vehicleName) {
+ this.vehicleName = vehicleName;
+ }
+
+ public String getVehicleModel() {
+ return vehicleModel;
+ }
+
+ public void setVehicleModel(String vehicleModel) {
+ this.vehicleModel = vehicleModel;
+ }
+
+ public Long getMakeYear() {
+ return makeYear;
+ }
+
+ public void setMakeYear(Long makeYear) {
+ this.makeYear = makeYear;
+ }
+
+ protected abstract void start();
+
+ protected abstract void stop();
+
+ protected abstract void drive();
+
+ protected abstract void changeGear();
+
+ protected abstract void reverse();
+
+}
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java
new file mode 100644
index 0000000000..71f8050590
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java
@@ -0,0 +1,12 @@
+package com.baeldung.interfacevsabstractclass;
+
+import java.io.File;
+
+public class VideoSender implements Sender {
+
+ @Override
+ public void send(File fileToBeSent) {
+ // video sending implementation code
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java
new file mode 100644
index 0000000000..6419721b3a
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.interfacevsabstractclass;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.interfacevsabstractclass.ImageSender;
+import com.baeldung.interfacevsabstractclass.Sender;
+
+import java.io.File;
+
+class SenderUnitTest {
+
+ public final static String IMAGE_FILE_PATH = "/sample_image_file_path/photo.jpg";
+
+ @Test
+ void givenImageUploaded_whenButtonClicked_thenSendImage() {
+ File imageFile = new File(IMAGE_FILE_PATH);
+
+ Sender sender = new ImageSender();
+ sender.send(imageFile);
+ }
+
+}
diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java
new file mode 100644
index 0000000000..1650ab9257
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.interfacevsabstractclass;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.interfacevsabstractclass.Car;
+import com.baeldung.interfacevsabstractclass.Vehicle;
+
+class VehicleUnitTest {
+
+ @Test
+ void givenVehicle_whenNeedToDrive_thenStart() {
+ Vehicle car = new Car("BMW");
+
+ car.start();
+ car.drive();
+ car.changeGear();
+ car.stop();
+ }
+
+}
diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java
index 16017ee482..987a69582f 100644
--- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java
+++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java
@@ -17,9 +17,9 @@ import static org.junit.Assert.assertTrue;
public class FileDownloadIntegrationTest {
- static String FILE_URL = "http://ovh.net/files/1Mio.dat";
+ static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson+by+Baeldung.pdf";
static String FILE_NAME = "file.dat";
- static String FILE_MD5_HASH = "6cb91af4ed4c60c11613b75cd1fc6116";
+ static String FILE_MD5_HASH = "c959feb066b37f5c4f0e0f45bbbb4f86";
@Test
public void givenJavaIO_whenDownloadingFile_thenDownloadShouldBeCorrect() throws NoSuchAlgorithmException, IOException {
diff --git a/core-java-modules/core-java-streams-3/pom.xml b/core-java-modules/core-java-streams-3/pom.xml
index 659f1937f2..01b83f229a 100644
--- a/core-java-modules/core-java-streams-3/pom.xml
+++ b/core-java-modules/core-java-streams-3/pom.xml
@@ -27,6 +27,17 @@
${lombok.version}
provided
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+ test
+
org.assertj
@@ -44,11 +55,30 @@
true
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+
+
+
+
+
+ 1.18.20
3.6.1
+ 1.29
\ No newline at end of file
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java
new file mode 100644
index 0000000000..461d728ad0
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java
@@ -0,0 +1,9 @@
+package com.baeldung.streams.parallel;
+
+public class BenchmarkRunner {
+
+ public static void main(String[] args) throws Exception {
+ org.openjdk.jmh.Main.main(args);
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java
new file mode 100644
index 0000000000..9ad569df30
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java
@@ -0,0 +1,54 @@
+package com.baeldung.streams.parallel;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+public class DifferentSourceSplitting {
+
+ private static final List arrayListOfNumbers = new ArrayList<>();
+ private static final List linkedListOfNumbers = new LinkedList<>();
+
+ static {
+ IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
+ arrayListOfNumbers.add(i);
+ linkedListOfNumbers.add(i);
+ });
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void differentSourceArrayListSequential() {
+ arrayListOfNumbers.stream().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void differentSourceArrayListParallel() {
+ arrayListOfNumbers.parallelStream().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void differentSourceLinkedListSequential() {
+ linkedListOfNumbers.stream().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void differentSourceLinkedListParallel() {
+ linkedListOfNumbers.parallelStream().reduce(0, Integer::sum);
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java
new file mode 100644
index 0000000000..bc5cbf491b
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java
@@ -0,0 +1,52 @@
+package com.baeldung.streams.parallel;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+public class MemoryLocalityCosts {
+
+ private static final int[] intArray = new int[1_000_000];
+ private static final Integer[] integerArray = new Integer[1_000_000];
+
+ static {
+ IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
+ intArray[i-1] = i;
+ integerArray[i-1] = i;
+ });
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void localityIntArraySequential() {
+ Arrays.stream(intArray).reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void localityIntArrayParallel() {
+ Arrays.stream(intArray).parallel().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void localityIntegerArraySequential() {
+ Arrays.stream(integerArray).reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void localityIntegerArrayParallel() {
+ Arrays.stream(integerArray).parallel().reduce(0, Integer::sum);
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java
new file mode 100644
index 0000000000..a9919dbe72
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java
@@ -0,0 +1,52 @@
+package com.baeldung.streams.parallel;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class MergingCosts {
+
+ private static final List arrayListOfNumbers = new ArrayList<>();
+
+ static {
+ IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
+ arrayListOfNumbers.add(i);
+ });
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void mergingCostsSumSequential() {
+ arrayListOfNumbers.stream().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void mergingCostsSumParallel() {
+ arrayListOfNumbers.stream().parallel().reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void mergingCostsGroupingSequential() {
+ arrayListOfNumbers.stream().collect(Collectors.toSet());
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void mergingCostsGroupingParallel() {
+ arrayListOfNumbers.stream().parallel().collect(Collectors.toSet());
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java
new file mode 100644
index 0000000000..f236f418e8
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java
@@ -0,0 +1,15 @@
+package com.baeldung.streams.parallel;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ParallelStream {
+
+ public static void main(String[] args) {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ listOfNumbers.parallelStream().forEach(number ->
+ System.out.println(number + " " + Thread.currentThread().getName())
+ );
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java
new file mode 100644
index 0000000000..01379130fa
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java
@@ -0,0 +1,15 @@
+package com.baeldung.streams.parallel;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class SequentialStream {
+
+ public static void main(String[] args) {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ listOfNumbers.stream().forEach(number ->
+ System.out.println(number + " " + Thread.currentThread().getName())
+ );
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java
new file mode 100644
index 0000000000..d1e878df1f
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java
@@ -0,0 +1,27 @@
+package com.baeldung.streams.parallel;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+public class SplittingCosts {
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void sourceSplittingIntStreamSequential() {
+ IntStream.rangeClosed(1, 100).reduce(0, Integer::sum);
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static void sourceSplittingIntStreamParallel() {
+ IntStream.rangeClosed(1, 100).parallel().reduce(0, Integer::sum);
+ }
+
+}
diff --git a/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java b/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java
new file mode 100644
index 0000000000..f9aab8ed6c
--- /dev/null
+++ b/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.streams.parallel;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ForkJoinUnitTest {
+
+ @Test
+ void givenSequentialStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsCorrect() {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ int sum = listOfNumbers.stream().reduce(5, Integer::sum);
+ assertThat(sum).isEqualTo(15);
+ }
+
+ @Test
+ void givenParallelStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsNotCorrect() {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ int sum = listOfNumbers.parallelStream().reduce(5, Integer::sum);
+ assertThat(sum).isNotEqualTo(15);
+ }
+
+ @Test
+ void givenParallelStreamOfNumbers_whenReducingSumWithIdentityZero_thenResultIsCorrect() {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ int sum = listOfNumbers.parallelStream().reduce(0, Integer::sum) + 5;
+ assertThat(sum).isEqualTo(15);
+ }
+
+ @Test
+ public void givenParallelStreamOfNumbers_whenUsingCustomThreadPool_thenResultIsCorrect()
+ throws InterruptedException, ExecutionException {
+ List listOfNumbers = Arrays.asList(1, 2, 3, 4);
+ ForkJoinPool customThreadPool = new ForkJoinPool(4);
+ int sum = customThreadPool.submit(
+ () -> listOfNumbers.parallelStream().reduce(0, Integer::sum)).get();
+ customThreadPool.shutdown();
+ assertThat(sum).isEqualTo(10);
+ }
+
+}
diff --git a/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java
new file mode 100644
index 0000000000..ede8be4c05
--- /dev/null
+++ b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java
@@ -0,0 +1,59 @@
+package com.baeldung.splitkeepdelimiters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.base.Splitter;
+
+public class SplitAndKeepDelimitersUnitTest {
+
+ private final String positivelookAheadRegex = "((?=@))";
+ private final String positivelookBehindRegex = "((?<=@))";
+ private final String positivelookAroundRegex = "((?=@)|(?<=@))";
+ private final String positiveLookAroundMultiDelimiterRegex = "((?=:|#|@)|(?<=:|#|@))";
+
+ private String text = "Hello@World@This@Is@A@Java@Program";
+ private String textMixed = "@HelloWorld@This:Is@A#Java#Program";
+ private String textMixed2 = "pg@no;10@hello;world@this;is@a#10words;Java#Program";
+
+ @Test
+ public void givenString_splitAndKeepDelimiters_using_javaLangString() {
+
+ assertThat(text.split(positivelookAheadRegex)).containsExactly("Hello", "@World", "@This", "@Is", "@A", "@Java", "@Program");
+
+ assertThat(text.split(positivelookBehindRegex)).containsExactly("Hello@", "World@", "This@", "Is@", "A@", "Java@", "Program");
+
+ assertThat(text.split(positivelookAroundRegex)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program");
+
+ assertThat(textMixed.split(positiveLookAroundMultiDelimiterRegex)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program");
+
+ }
+
+ @Test
+ public void givenString_splitAndKeepDelimiters_using_ApacheCommonsLang3StringUtils() {
+
+ assertThat(StringUtils.splitByCharacterType(textMixed2)).containsExactly("pg", "@", "no", ";", "10", "@", "hello", ";", "world", "@", "this", ";", "is", "@", "a", "#", "10", "words", ";", "J", "ava", "#", "P", "rogram");
+
+ }
+
+ @Test
+ public void givenString_splitAndKeepDelimiters_using_GuavaSplitter() {
+
+ assertThat(Splitter.onPattern(positivelookAroundRegex)
+ .splitToList(text)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program");
+
+ assertThat(Splitter.on(Pattern.compile(positivelookAroundRegex))
+ .splitToList(text)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program");
+
+ assertThat(Splitter.onPattern(positiveLookAroundMultiDelimiterRegex)
+ .splitToList(textMixed)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program");
+
+ assertThat(Splitter.on(Pattern.compile(positiveLookAroundMultiDelimiterRegex))
+ .splitToList(textMixed)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program");
+
+ }
+}
diff --git a/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java b/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java
index 2df0cf81af..801d7966a5 100644
--- a/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java
+++ b/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java
@@ -1,18 +1,17 @@
package com.baeldung.javaxval.bigdecimal;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.math.BigDecimal;
-import java.util.Set;
-
-import javax.validation.ConstraintViolation;
-import javax.validation.Validation;
-import javax.validation.Validator;
-
import com.baeldung.javaxval.LocaleAwareUnitTest;
import org.junit.BeforeClass;
import org.junit.Test;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.math.BigDecimal;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
public class InvoiceUnitTest extends LocaleAwareUnitTest {
private static Validator validator;
@@ -24,41 +23,67 @@ public class InvoiceUnitTest extends LocaleAwareUnitTest {
}
@Test
- public void whenPriceIntegerDigitLessThanThreeWithDecimalValue_thenShouldGiveConstraintViolations() {
- Invoice invoice = new Invoice(new BigDecimal(10.21), "Book purchased");
+ public void whenLessThanThreeIntegerDigits_thenShouldNotGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("10.21"), "Book purchased");
Set> violations = validator.validate(invoice);
- assertThat(violations.size()).isEqualTo(1);
- violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)"));
+ assertThat(violations).isEmpty();
}
@Test
- public void whenPriceIntegerDigitLessThanThreeWithIntegerValue_thenShouldNotGiveConstraintViolations() {
- Invoice invoice = new Invoice(new BigDecimal(10), "Book purchased");
+ public void whenThreeIntegerDigits_thenShouldNotGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("102.21"), "Book purchased");
Set> violations = validator.validate(invoice);
- assertThat(violations.size()).isEqualTo(0);
+ assertThat(violations).isEmpty();
}
@Test
- public void whenPriceIntegerDigitGreaterThanThree_thenShouldGiveConstraintViolations() {
- Invoice invoice = new Invoice(new BigDecimal(1021.21), "Book purchased");
+ public void whenMoreThanThreeIntegerDigits_thenShouldGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("1021.21"), "Book purchased");
Set> violations = validator.validate(invoice);
- assertThat(violations.size()).isEqualTo(1);
- violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)"));
+ assertThat(violations).hasSize(1);
+ assertThat(violations)
+ .extracting("message")
+ .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)");
+ }
+
+ @Test
+ public void whenLessThanTwoFractionDigits_thenShouldNotGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("99.9"), "Book purchased");
+ Set> violations = validator.validate(invoice);
+ assertThat(violations).isEmpty();
+ }
+
+ @Test
+ public void whenTwoFractionDigits_thenShouldNotGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("99.99"), "Book purchased");
+ Set> violations = validator.validate(invoice);
+ assertThat(violations).isEmpty();
+ }
+
+ @Test
+ public void whenMoreThanTwoFractionDigits_thenShouldGiveConstraintViolations() {
+ Invoice invoice = new Invoice(new BigDecimal("99.999"), "Book purchased");
+ Set> violations = validator.validate(invoice);
+ assertThat(violations).hasSize(1);
+ assertThat(violations)
+ .extracting("message")
+ .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)");
}
@Test
public void whenPriceIsZero_thenShouldGiveConstraintViolations() {
- Invoice invoice = new Invoice(new BigDecimal(000.00), "Book purchased");
+ Invoice invoice = new Invoice(new BigDecimal("0.00"), "Book purchased");
Set> violations = validator.validate(invoice);
- assertThat(violations.size()).isEqualTo(1);
- violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("must be greater than 0.0"));
+ assertThat(violations).hasSize(1);
+ assertThat(violations)
+ .extracting("message")
+ .containsOnly("must be greater than 0.0");
}
@Test
public void whenPriceIsGreaterThanZero_thenShouldNotGiveConstraintViolations() {
- Invoice invoice = new Invoice(new BigDecimal(100.50), "Book purchased");
+ Invoice invoice = new Invoice(new BigDecimal("100.50"), "Book purchased");
Set> violations = validator.validate(invoice);
- assertThat(violations.size()).isEqualTo(0);
+ assertThat(violations).isEmpty();
}
-
}
diff --git a/kubernetes/k8s-intro/README.md b/kubernetes/k8s-intro/README.md
index 83cbcca4db..6ac593452c 100644
--- a/kubernetes/k8s-intro/README.md
+++ b/kubernetes/k8s-intro/README.md
@@ -16,3 +16,4 @@ If you get a valid response, then you're good to go.
- [Paging and Async Calls with the Kubernetes API](https://www.baeldung.com/java-kubernetes-paging-async)
- [Using Watch with the Kubernetes API](https://www.baeldung.com/java-kubernetes-watch)
+- [Using Namespaces and Selectors With the Kubernetes Java API](https://www.baeldung.com/java-kubernetes-namespaces-selectors)
diff --git a/kubernetes/k8s-intro/src/k8s/create-http-server.yml b/kubernetes/k8s-intro/src/k8s/create-http-server.yml
new file mode 100644
index 0000000000..59ef344de3
--- /dev/null
+++ b/kubernetes/k8s-intro/src/k8s/create-http-server.yml
@@ -0,0 +1,58 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: ns1
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: ns2
+---
+ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+ name: httpd
+ namespace: ns1
+ labels:
+ app: httpd
+ version: "1"
+ spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: httpd
+ template:
+ metadata:
+ labels:
+ app: httpd
+ spec:
+ containers:
+ - name: main
+ image: httpd:alpine
+ ports:
+ - containerPort: 80
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: httpd
+ namespace: ns2
+ labels:
+ app: httpd
+ version: "2"
+ foo: bar
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: httpd
+ template:
+ metadata:
+ labels:
+ app: httpd
+ spec:
+ containers:
+ - name: main
+ image: httpd:alpine
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java
new file mode 100644
index 0000000000..459f61099c
--- /dev/null
+++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java
@@ -0,0 +1,68 @@
+/**
+ *
+ */
+package com.baeldung.kubernetes.intro;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.kubernetes.client.openapi.ApiClient;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1NodeList;
+import io.kubernetes.client.openapi.models.V1PodList;
+import io.kubernetes.client.util.Config;
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+
+/**
+ * @author Philippe
+ *
+ */
+public class ListPodsWithFieldSelectors {
+
+ private static final Logger log = LoggerFactory.getLogger(ListPodsWithFieldSelectors.class);
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+
+ ApiClient client = Config.defaultClient();
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message));
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ OkHttpClient newClient = client.getHttpClient()
+ .newBuilder()
+ .addInterceptor(interceptor)
+ .readTimeout(0, TimeUnit.SECONDS)
+ .build();
+
+ client.setHttpClient(newClient);
+ CoreV1Api api = new CoreV1Api(client);
+
+ String fs = createSelector(args);
+ V1PodList items = api.listPodForAllNamespaces(null, null, fs, null, null, null, null, null, 10, false);
+ items.getItems()
+ .stream()
+ .map((pod) -> pod.getMetadata().getName() )
+ .forEach((name) -> System.out.println("name=" + name));
+
+ }
+
+ private static String createSelector(String[] args) {
+
+ StringBuilder b = new StringBuilder();
+ for( int i = 0 ; i < args.length; i++ ) {
+ if( b.length() > 0 ) {
+ b.append(',');
+ }
+
+ b.append(args[i]);
+ }
+
+ return b.toString();
+ }
+
+}
diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java
new file mode 100644
index 0000000000..2e7c8b6a1f
--- /dev/null
+++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java
@@ -0,0 +1,68 @@
+/**
+ *
+ */
+package com.baeldung.kubernetes.intro;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.kubernetes.client.openapi.ApiClient;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1NodeList;
+import io.kubernetes.client.openapi.models.V1PodList;
+import io.kubernetes.client.util.Config;
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+
+/**
+ * @author Philippe
+ *
+ */
+public class ListPodsWithLabelSelectors {
+
+ private static final Logger log = LoggerFactory.getLogger(ListPodsWithLabelSelectors.class);
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+
+ ApiClient client = Config.defaultClient();
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message));
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ OkHttpClient newClient = client.getHttpClient()
+ .newBuilder()
+ .addInterceptor(interceptor)
+ .readTimeout(0, TimeUnit.SECONDS)
+ .build();
+
+ client.setHttpClient(newClient);
+ CoreV1Api api = new CoreV1Api(client);
+
+ String selector = createSelector(args);
+ V1PodList items = api.listPodForAllNamespaces(null, null, null, selector, null, null, null, null, 10, false);
+ items.getItems()
+ .stream()
+ .map((pod) -> pod.getMetadata().getName() )
+ .forEach((name) -> System.out.println("name=" + name));
+
+ }
+
+ private static String createSelector(String[] args) {
+
+ StringBuilder b = new StringBuilder();
+ for( int i = 0 ; i < args.length; i++ ) {
+ if( b.length() > 0 ) {
+ b.append(',');
+ }
+
+ b.append(args[i]);
+ }
+
+ return b.toString();
+ }
+
+}
diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java
new file mode 100644
index 0000000000..68a951f394
--- /dev/null
+++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java
@@ -0,0 +1,52 @@
+/**
+ *
+ */
+package com.baeldung.kubernetes.intro;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.kubernetes.client.openapi.ApiClient;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1NodeList;
+import io.kubernetes.client.openapi.models.V1PodList;
+import io.kubernetes.client.util.Config;
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+
+/**
+ * @author Philippe
+ *
+ */
+public class ListPodsWithNamespaces {
+
+ private static final Logger log = LoggerFactory.getLogger(ListPodsWithNamespaces.class);
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+
+ ApiClient client = Config.defaultClient();
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message));
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ OkHttpClient newClient = client.getHttpClient()
+ .newBuilder()
+ .addInterceptor(interceptor)
+ .readTimeout(0, TimeUnit.SECONDS)
+ .build();
+
+ client.setHttpClient(newClient);
+ CoreV1Api api = new CoreV1Api(client);
+ String namespace = "ns1";
+ V1PodList items = api.listNamespacedPod(namespace,null, null, null, null, null, null, null, null, 10, false);
+ items.getItems()
+ .stream()
+ .map((pod) -> pod.getMetadata().getName() )
+ .forEach((name) -> System.out.println("name=" + name));
+
+ }
+}
diff --git a/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java
new file mode 100644
index 0000000000..9413fe1460
--- /dev/null
+++ b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.kubernetes.intro;
+
+import org.junit.jupiter.api.Test;
+
+class ListPodsWithFieldSelectorsLiveTest {
+ @Test
+ void givenEqualitySelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception {
+ ListPodsWithFieldSelectors.main(new String[] {
+ "metadata.namespace=ns1"
+ });
+ }
+
+ @Test
+ void givenInequalitySelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception {
+ ListPodsWithFieldSelectors.main(new String[] {
+ "metadata.namespace!=ns1"
+ });
+ }
+
+ @Test
+ void givenChainedSelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception {
+ ListPodsWithFieldSelectors.main(new String[] {
+ "metadata.namespace=ns1",
+ "status.phase=Running"
+ });
+ }
+}
diff --git a/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java
new file mode 100644
index 0000000000..eb64853225
--- /dev/null
+++ b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.kubernetes.intro;
+
+import org.junit.jupiter.api.Test;
+
+class ListPodsWithLabelSelectorsLiveTest {
+ @Test
+ void givenEqualitySelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app=httpd"
+ });
+ }
+
+ @Test
+ void givenInqualitySelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app!=httpd"
+ });
+ }
+
+ @Test
+ void givenInSetSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app in (httpd,test)"
+ });
+ }
+
+ @Test
+ void givenNotInSetSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app notin (httpd)"
+ });
+ }
+
+ @Test
+ void givenLabelPresentSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app"
+ });
+ }
+
+ @Test
+ void givenLabelNotPresentSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "!app"
+ });
+ }
+
+ @Test
+ void givenChainedSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception {
+ ListPodsWithLabelSelectors.main(new String[] {
+ "app=httpd",
+ "!foo"
+ });
+ }
+}
diff --git a/libraries-http-2/README.md b/libraries-http-2/README.md
index f3fdf1becb..4085d98ea5 100644
--- a/libraries-http-2/README.md
+++ b/libraries-http-2/README.md
@@ -8,5 +8,6 @@ This module contains articles about HTTP libraries.
- [Decode an OkHttp JSON Response](https://www.baeldung.com/okhttp-json-response)
- [Retrofit 2 – Dynamic URL](https://www.baeldung.com/retrofit-dynamic-url)
- [Adding Interceptors in OkHTTP](https://www.baeldung.com/java-okhttp-interceptors)
+- [A Guide to Events in OkHTTP](https://www.baeldung.com/java-okhttp-events)
- More articles [[<-- prev]](/libraries-http)
diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java
new file mode 100644
index 0000000000..356dea9fc6
--- /dev/null
+++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java
@@ -0,0 +1,156 @@
+package com.baeldung.okhttp.events;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.util.List;
+
+import okhttp3.Call;
+import okhttp3.Connection;
+import okhttp3.EventListener;
+import okhttp3.Handshake;
+import okhttp3.HttpUrl;
+import okhttp3.Protocol;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class EventTimer extends EventListener {
+
+ private long start;
+
+ private void logTimedEvent(String name) {
+ long now = System.nanoTime();
+ if (name.equals("callStart")) {
+ start = now;
+ }
+ long elapsedNanos = now - start;
+ System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);
+ }
+
+ @Override
+ public void callStart(Call call) {
+ logTimedEvent("callStart");
+ }
+
+ @Override
+ public void proxySelectStart(Call call, HttpUrl url) {
+ logTimedEvent("proxySelectStart");
+ }
+
+ @Override
+ public void proxySelectEnd(Call call, HttpUrl url, List proxies) {
+ logTimedEvent("proxySelectEnd");
+ }
+
+ @Override
+ public void dnsStart(Call call, String domainName) {
+ logTimedEvent("dnsStart");
+ }
+
+ @Override
+ public void dnsEnd(Call call, String domainName, List inetAddressList) {
+ logTimedEvent("dnsEnd");
+ }
+
+ @Override
+ public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
+ logTimedEvent("connectStart");
+ }
+
+ @Override
+ public void secureConnectStart(Call call) {
+ logTimedEvent("secureConnectStart");
+ }
+
+ @Override
+ public void secureConnectEnd(Call call, Handshake handshake) {
+ logTimedEvent("secureConnectEnd");
+ }
+
+ @Override
+ public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) {
+ logTimedEvent("connectEnd");
+ }
+
+ @Override
+ public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {
+ logTimedEvent("connectFailed");
+ }
+
+ @Override
+ public void connectionAcquired(Call call, Connection connection) {
+ logTimedEvent("connectionAcquired");
+ }
+
+ @Override
+ public void connectionReleased(Call call, Connection connection) {
+ logTimedEvent("connectionReleased");
+ }
+
+ @Override
+ public void requestHeadersStart(Call call) {
+ logTimedEvent("requestHeadersStart");
+ }
+
+ @Override
+ public void requestHeadersEnd(Call call, Request request) {
+ logTimedEvent("requestHeadersEnd");
+ }
+
+ @Override
+ public void requestBodyStart(Call call) {
+ logTimedEvent("requestBodyStart");
+ }
+
+ @Override
+ public void requestBodyEnd(Call call, long byteCount) {
+ logTimedEvent("requestBodyEnd");
+ }
+
+ @Override
+ public void requestFailed(Call call, IOException ioe) {
+ logTimedEvent("requestFailed");
+ }
+
+ @Override
+ public void responseHeadersStart(Call call) {
+ logTimedEvent("responseHeadersStart");
+ }
+
+ @Override
+ public void responseHeadersEnd(Call call, Response response) {
+ logTimedEvent("responseHeadersEnd");
+ }
+
+ @Override
+ public void responseBodyStart(Call call) {
+ logTimedEvent("responseBodyStart");
+ }
+
+ @Override
+ public void responseBodyEnd(Call call, long byteCount) {
+ logTimedEvent("responseBodyEnd");
+ }
+
+ @Override
+ public void responseFailed(Call call, IOException ioe) {
+ logTimedEvent("responseFailed");
+ }
+
+ @Override
+ public void callEnd(Call call) {
+ logTimedEvent("callEnd");
+ }
+
+ @Override
+ public void callFailed(Call call, IOException ioe) {
+ logTimedEvent("callFailed");
+ }
+
+ @Override
+ public void canceled(Call call) {
+ logTimedEvent("canceled");
+ }
+
+}
diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java
new file mode 100644
index 0000000000..93e3eb6308
--- /dev/null
+++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java
@@ -0,0 +1,37 @@
+package com.baeldung.okhttp.events;
+
+import java.time.LocalDateTime;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import okhttp3.Call;
+import okhttp3.EventListener;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class SimpleLogEventsListener extends EventListener {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLogEventsListener.class);
+
+ @Override
+ public void callStart(Call call) {
+ LOGGER.info("callStart at {}", LocalDateTime.now());
+ }
+
+ @Override
+ public void requestHeadersEnd(Call call, Request request) {
+ LOGGER.info("requestHeadersEnd at {} with headers {}", LocalDateTime.now(), request.headers());
+ }
+
+ @Override
+ public void responseHeadersEnd(Call call, Response response) {
+ LOGGER.info("responseHeadersEnd at {} with headers {}", LocalDateTime.now(), response.headers());
+ }
+
+ @Override
+ public void callEnd(Call call) {
+ LOGGER.info("callEnd at {}", LocalDateTime.now());
+ }
+
+}
diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java
new file mode 100644
index 0000000000..ebf4cd1404
--- /dev/null
+++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java
@@ -0,0 +1,31 @@
+package com.baeldung.okhttp.events;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class EventTimerLiveTest {
+
+ @Test
+ public void givenSimpleEventTimer_whenRequestSent_thenCallsLogged() throws IOException {
+
+ OkHttpClient client = new OkHttpClient.Builder()
+ .eventListener(new EventTimer())
+ .build();
+
+ Request request = new Request.Builder()
+ .url("https://www.baeldung.com/")
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ assertEquals("Response code should be: ", 200, response.code());
+ }
+ }
+
+}
diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java
new file mode 100644
index 0000000000..c5884e8a12
--- /dev/null
+++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java
@@ -0,0 +1,53 @@
+package com.baeldung.okhttp.events;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+
+public class LogEventsListenerIntegrationTest {
+
+ @Rule
+ public MockWebServer server = new MockWebServer();
+
+ @Test
+ public void givenSimpleEventLogger_whenRequestSent_thenCallsLogged() throws IOException {
+ server.enqueue(new MockResponse().setBody("Hello Baeldung Readers!"));
+
+ OkHttpClient client = new OkHttpClient.Builder()
+ .eventListener(new SimpleLogEventsListener())
+ .build();
+
+ Request request = new Request.Builder()
+ .url(server.url("/"))
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ assertEquals("Response code should be: ", 200, response.code());
+ assertEquals("Body should be: ", "Hello Baeldung Readers!", response.body().string());
+ }
+ }
+
+ @Test (expected = SocketTimeoutException.class)
+ public void givenConnectionError_whenRequestSent_thenFailedCallsLogged() throws IOException {
+ OkHttpClient client = new OkHttpClient.Builder()
+ .eventListener(new EventTimer())
+ .build();
+
+ Request request = new Request.Builder()
+ .url(server.url("/"))
+ .build();
+
+ client.newCall(request).execute();
+ }
+
+}
diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml b/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml
new file mode 100644
index 0000000000..24a7c48499
--- /dev/null
+++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml
@@ -0,0 +1,92 @@
+
+
+ 4.0.0
+
+ maven-copy-files
+ com.baeldung
+ 1.0-SNAPSHOT
+
+ org.baeldung
+ copy-rename-maven-plugin
+ 1.0-SNAPSHOT
+ copy-rename-maven-plugin
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
+
+
+ com.coderplus.maven.plugins
+ copy-rename-maven-plugin
+ 1.0
+
+
+ copy-file
+ generate-sources
+
+ copy
+
+
+ source-files/foo.txt
+ target/destination-folder/foo.txt
+
+
+
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.8.0
+
+
+ maven-surefire-plugin
+ 2.22.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+ maven-site-plugin
+ 3.7.1
+
+
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+
+
diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt
new file mode 100644
index 0000000000..b2fa85b97f
--- /dev/null
+++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt
@@ -0,0 +1 @@
+Copy File Example
diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
new file mode 100644
index 0000000000..a98db61fa9
--- /dev/null
+++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
@@ -0,0 +1,16 @@
+package org.baeldung;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+
+public class CopyFileUnitTest {
+
+ @Test
+ public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() {
+ File destinationFile = new File("target/destination-folder/foo.txt");
+ assertEquals(true, destinationFile.exists());
+ }
+}
diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml b/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml
new file mode 100644
index 0000000000..61017dd18a
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml
@@ -0,0 +1,94 @@
+
+
+ 4.0.0
+
+ maven-copy-files
+ com.baeldung
+ 1.0-SNAPSHOT
+
+ org.baeldung
+ maven-antrun-plugin
+ 1.0-SNAPSHOT
+ maven-antrun-plugin
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
+
+
+ maven-antrun-plugin
+ 3.0.0
+
+
+ generate-sources
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.8.0
+
+
+ maven-surefire-plugin
+ 2.22.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+ maven-site-plugin
+ 3.7.1
+
+
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+
+
diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt
new file mode 100644
index 0000000000..b2fa85b97f
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt
@@ -0,0 +1 @@
+Copy File Example
diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
new file mode 100644
index 0000000000..a98db61fa9
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
@@ -0,0 +1,16 @@
+package org.baeldung;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+
+public class CopyFileUnitTest {
+
+ @Test
+ public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() {
+ File destinationFile = new File("target/destination-folder/foo.txt");
+ assertEquals(true, destinationFile.exists());
+ }
+}
diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml b/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml
new file mode 100644
index 0000000000..7dbe851f95
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml
@@ -0,0 +1,92 @@
+
+
+ 4.0.0
+
+ maven-copy-files
+ com.baeldung
+ 1.0-SNAPSHOT
+
+ org.baeldung
+ maven-resources-plugin
+ 1.0-SNAPSHOT
+ maven-resoures-plugin
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ copy-resource-one
+ generate-sources
+
+ copy-resources
+
+
+ ${basedir}/target/destination-folder
+
+
+ source-files
+
+ foo.txt
+
+
+
+
+
+
+
+
+ maven-compiler-plugin
+ 3.8.0
+
+
+ maven-surefire-plugin
+ 2.22.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+ maven-site-plugin
+ 3.7.1
+
+
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+
+
diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt
new file mode 100644
index 0000000000..b2fa85b97f
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt
@@ -0,0 +1 @@
+Copy File Example
diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
new file mode 100644
index 0000000000..a98db61fa9
--- /dev/null
+++ b/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java
@@ -0,0 +1,16 @@
+package org.baeldung;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+
+public class CopyFileUnitTest {
+
+ @Test
+ public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() {
+ File destinationFile = new File("target/destination-folder/foo.txt");
+ assertEquals(true, destinationFile.exists());
+ }
+}
diff --git a/maven-modules/maven-copy-files/pom.xml b/maven-modules/maven-copy-files/pom.xml
new file mode 100644
index 0000000000..b7b67286bc
--- /dev/null
+++ b/maven-modules/maven-copy-files/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+
+ maven-modules
+ com.baeldung
+ 0.0.1-SNAPSHOT
+
+ com.baeldung
+ maven-copy-files
+ 1.0-SNAPSHOT
+ pom
+ maven-copy-files
+
+ http://www.example.com
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.8.0
+
+
+ maven-surefire-plugin
+ 2.22.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+ maven-site-plugin
+ 3.7.1
+
+
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+
+
+ maven-resources-plugin
+ maven-antrun-plugin
+ copy-rename-maven-plugin
+
+
diff --git a/maven-modules/maven-printing-plugins/.gitignore b/maven-modules/maven-printing-plugins/.gitignore
new file mode 100644
index 0000000000..333c1e910a
--- /dev/null
+++ b/maven-modules/maven-printing-plugins/.gitignore
@@ -0,0 +1 @@
+logs/
diff --git a/maven-modules/maven-printing-plugins/pom.xml b/maven-modules/maven-printing-plugins/pom.xml
new file mode 100644
index 0000000000..6ea1ab2a84
--- /dev/null
+++ b/maven-modules/maven-printing-plugins/pom.xml
@@ -0,0 +1,85 @@
+
+
+ 4.0.0
+ maven-printing-plugins
+ maven-printing-plugins
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../..
+
+
+
+
+
+ maven-antrun-plugin
+ 3.0.0
+
+
+ antrun-plugin
+ validate
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.github.ekryd.echo-maven-plugin
+ echo-maven-plugin
+ 1.3.2
+
+
+ echo-maven-plugin-1
+ package
+
+ echo
+
+
+ Hello, world
+ Embed a line break: ${line.separator}
+ ArtifactId is ${project.artifactId}
+ INFO
+ /logs/log-echo.txt
+ true
+
+
+
+
+
+ org.codehaus.gmaven
+ groovy-maven-plugin
+ 2.1.1
+
+
+ validate
+
+ execute
+
+
+
+ log.info('Test message: {}', 'Hello, World!')
+ log.info('Embed a line break {}', System.lineSeparator())
+ log.info('ArtifactId is: ${project.artifactId}')
+ log.warn('Message only in debug mode')
+
+
+
+
+
+
+
+
diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml
index 08a8f05631..0f146e26da 100644
--- a/maven-modules/pom.xml
+++ b/maven-modules/pom.xml
@@ -16,6 +16,7 @@
+ maven-copy-files
maven-custom-plugin
maven-exec-plugin
maven-integration-test
@@ -30,6 +31,7 @@
version-collision
version-overriding-plugins
versions-maven-plugin
+ maven-printing-plugins
-
\ No newline at end of file
+
diff --git a/netflix-modules/mantis/pom.xml b/netflix-modules/mantis/pom.xml
index 474b8f6dbf..1f8b377b94 100644
--- a/netflix-modules/mantis/pom.xml
+++ b/netflix-modules/mantis/pom.xml
@@ -19,7 +19,6 @@
org.springframework.boot
spring-boot-starter
- 2.1.3.RELEASE
io.mantisrx
@@ -35,36 +34,31 @@
com.fasterxml.jackson.core
jackson-databind
- 2.10.2
net.andreinc.mockneat
mockneat
- 0.3.8
+ 0.4.2
org.projectlombok
lombok
- 1.18.12
org.springframework
spring-webflux
- 5.0.9.RELEASE
test
io.projectreactor.netty
reactor-netty
- 0.9.12.RELEASE
test
-
- SpringLibReleaseRepo
- https://repo.spring.io/libs-release/
+ jcenter
+ https://jcenter.bintray.com/
diff --git a/parent-boot-1/pom.xml b/parent-boot-1/pom.xml
index 2e9c767aa2..96f4b1cbe3 100644
--- a/parent-boot-1/pom.xml
+++ b/parent-boot-1/pom.xml
@@ -1,6 +1,5 @@
-
4.0.0
diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml
index f5bf8784a9..c67842e313 100644
--- a/parent-boot-2/pom.xml
+++ b/parent-boot-2/pom.xml
@@ -1,6 +1,5 @@
-
4.0.0
diff --git a/parent-java/pom.xml b/parent-java/pom.xml
index ce79b34f57..c1abe79b2e 100644
--- a/parent-java/pom.xml
+++ b/parent-java/pom.xml
@@ -1,8 +1,7 @@
-
+
4.0.0
parent-java
0.0.1-SNAPSHOT
diff --git a/parent-spring-4/pom.xml b/parent-spring-4/pom.xml
index 931cad374b..e0e91cec9a 100644
--- a/parent-spring-4/pom.xml
+++ b/parent-spring-4/pom.xml
@@ -1,6 +1,5 @@
-
4.0.0
diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml
index 3219c504d5..b70ca2bd0f 100644
--- a/parent-spring-5/pom.xml
+++ b/parent-spring-5/pom.xml
@@ -1,6 +1,5 @@
-
4.0.0
diff --git a/patterns/design-patterns-behavioral/pom.xml b/patterns/design-patterns-behavioral/pom.xml
index 93e07bb477..bc032a0f8f 100644
--- a/patterns/design-patterns-behavioral/pom.xml
+++ b/patterns/design-patterns-behavioral/pom.xml
@@ -26,6 +26,11 @@
${lombok.version}
provided
+
+ com.google.code.findbugs
+ annotations
+ ${findbugs.annotations.version}
+
org.apache.commons
commons-lang3
@@ -41,6 +46,7 @@
16.0.2
+ 3.0.1
3.9.1
diff --git a/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java b/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java
index 697d5e4959..594516e3f2 100644
--- a/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java
+++ b/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java
@@ -1,12 +1,12 @@
package com.baeldung.nulls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import edu.umd.cs.findbugs.annotations.NonNull;
+import edu.umd.cs.findbugs.annotations.Nullable;
public class FindBugsAnnotations {
- public void accept(@NotNull Object param) {
+ public void accept(@NonNull Object param) {
System.out.println(param.toString());
}
@@ -14,7 +14,7 @@ public class FindBugsAnnotations {
System.out.println("Printing " + param);
}
- @NotNull
+ @NonNull
public Object process() throws Exception {
Object result = doSomething();
if (result == null) {
diff --git a/persistence-modules/hibernate-mapping/README.md b/persistence-modules/hibernate-mapping/README.md
index b5d0cb2f99..984f49bb70 100644
--- a/persistence-modules/hibernate-mapping/README.md
+++ b/persistence-modules/hibernate-mapping/README.md
@@ -13,3 +13,4 @@ This module contains articles about Object-relational Mapping (ORM) with Hiberna
- [Hibernate – Mapping Date and Time](https://www.baeldung.com/hibernate-date-time)
- [Mapping LOB Data in Hibernate](https://www.baeldung.com/hibernate-lob)
- [FetchMode in Hibernate](https://www.baeldung.com/hibernate-fetchmode)
+- [Mapping PostgreSQL Array With Hibernate](https://www.baeldung.com/java-hibernate-map-postgresql-array)
diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml
index 1c0c3eb159..0248f0cb04 100644
--- a/persistence-modules/hibernate-mapping/pom.xml
+++ b/persistence-modules/hibernate-mapping/pom.xml
@@ -13,11 +13,22 @@
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ test
+
org.hibernate
hibernate-core
${hibernate.version}
+
+ com.vladmihalcea
+ hibernate-types-52
+ ${hibernate-types.version}
+
org.assertj
assertj-core
@@ -64,7 +75,9 @@
+ 42.2.20
5.4.12.Final
+ 2.10.4
3.8.0
6.0.16.Final
3.0.1-b11
diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java
new file mode 100644
index 0000000000..233bb95dc1
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java
@@ -0,0 +1,85 @@
+package com.baeldung.hibernate.arraymapping;
+
+import java.io.Serializable;
+import java.sql.Array;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.usertype.UserType;
+
+public class CustomIntegerArrayType implements UserType {
+
+ @Override
+ public int[] sqlTypes() {
+ return new int[]{Types.ARRAY};
+ }
+
+ @Override
+ public Class returnedClass() {
+ return Integer[].class;
+ }
+
+ @Override
+ public boolean equals(Object x, Object y) throws HibernateException {
+ if (x instanceof Integer[] && y instanceof Integer[]) {
+ return Arrays.deepEquals((Integer[])x, (Integer[])y);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode(Object x) throws HibernateException {
+ return Arrays.hashCode((Integer[])x);
+ }
+
+ @Override
+ public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
+ throws HibernateException, SQLException {
+ Array array = rs.getArray(names[0]);
+ return array != null ? array.getArray() : null;
+ }
+
+ @Override
+ public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
+ throws HibernateException, SQLException {
+ if (value != null && st != null) {
+ Array array = session.connection().createArrayOf("int", (Integer[])value);
+ st.setArray(index, array);
+ } else {
+ st.setNull(index, sqlTypes()[0]);
+ }
+ }
+
+ @Override
+ public Object deepCopy(Object value) throws HibernateException {
+ Integer[] a = (Integer[])value;
+ return Arrays.copyOf(a, a.length);
+ }
+
+ @Override
+ public boolean isMutable() {
+ return false;
+ }
+
+ @Override
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) value;
+ }
+
+ @Override
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return cached;
+ }
+
+ @Override
+ public Object replace(Object original, Object target, Object owner) throws HibernateException {
+ return original;
+ }
+
+}
diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java
new file mode 100644
index 0000000000..7bd284def7
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java
@@ -0,0 +1,85 @@
+package com.baeldung.hibernate.arraymapping;
+
+import java.io.Serializable;
+import java.sql.Array;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.usertype.UserType;
+
+public class CustomStringArrayType implements UserType {
+
+ @Override
+ public int[] sqlTypes() {
+ return new int[]{Types.ARRAY};
+ }
+
+ @Override
+ public Class returnedClass() {
+ return String[].class;
+ }
+
+ @Override
+ public boolean equals(Object x, Object y) throws HibernateException {
+ if (x instanceof String[] && y instanceof String[]) {
+ return Arrays.deepEquals((String[])x, (String[])y);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode(Object x) throws HibernateException {
+ return Arrays.hashCode((String[])x);
+ }
+
+ @Override
+ public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
+ throws HibernateException, SQLException {
+ Array array = rs.getArray(names[0]);
+ return array != null ? array.getArray() : null;
+ }
+
+ @Override
+ public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
+ throws HibernateException, SQLException {
+ if (value != null && st != null) {
+ Array array = session.connection().createArrayOf("text", (String[])value);
+ st.setArray(index, array);
+ } else {
+ st.setNull(index, sqlTypes()[0]);
+ }
+ }
+
+ @Override
+ public Object deepCopy(Object value) throws HibernateException {
+ String[] a = (String[])value;
+ return Arrays.copyOf(a, a.length);
+ }
+
+ @Override
+ public boolean isMutable() {
+ return false;
+ }
+
+ @Override
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) value;
+ }
+
+ @Override
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return cached;
+ }
+
+ @Override
+ public Object replace(Object original, Object target, Object owner) throws HibernateException {
+ return original;
+ }
+
+}
diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java
new file mode 100644
index 0000000000..dc3ec93a9d
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java
@@ -0,0 +1,61 @@
+package com.baeldung.hibernate.arraymapping;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.Metadata;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.service.ServiceRegistry;
+
+import com.baeldung.hibernate.arraymapping.User;
+
+public class HibernateSessionUtil {
+
+ private static SessionFactory sessionFactory;
+ private static String PROPERTY_FILE_NAME;
+
+ public static SessionFactory getSessionFactory() throws IOException {
+ return getSessionFactory(null);
+ }
+
+ public static SessionFactory getSessionFactory(String propertyFileName) throws IOException {
+ PROPERTY_FILE_NAME = propertyFileName;
+ if (sessionFactory == null) {
+ ServiceRegistry serviceRegistry = configureServiceRegistry();
+ sessionFactory = makeSessionFactory(serviceRegistry);
+ }
+ return sessionFactory;
+ }
+
+ private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(User.class);
+
+ Metadata metadata = metadataSources.buildMetadata();
+ return metadata.getSessionFactoryBuilder()
+ .build();
+
+ }
+
+ private static ServiceRegistry configureServiceRegistry() throws IOException {
+ Properties properties = getProperties();
+ return new StandardServiceRegistryBuilder().applySettings(properties)
+ .build();
+ }
+
+ private static Properties getProperties() throws IOException {
+ Properties properties = new Properties();
+ URL propertiesURL = Thread.currentThread()
+ .getContextClassLoader()
+ .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate_postgres.properties"));
+ try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
+ properties.load(inputStream);
+ }
+ return properties;
+ }
+}
diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java
new file mode 100644
index 0000000000..018bedc349
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java
@@ -0,0 +1,82 @@
+package com.baeldung.hibernate.arraymapping;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+import org.hibernate.annotations.Type;
+
+import com.vladmihalcea.hibernate.type.array.StringArrayType;
+
+import org.hibernate.annotations.*;
+
+@TypeDefs({
+ @TypeDef(
+ name = "string-array",
+ typeClass = StringArrayType.class
+ )
+})
+@Entity
+public class User {
+
+ @Id
+ private Long id;
+
+ private String name;
+
+ @Column(columnDefinition = "text[]")
+ @Type(type = "com.baeldung.hibernate.arraymapping.CustomStringArrayType")
+ private String[] roles;
+
+ @Column(columnDefinition = "int[]")
+ @Type(type = "com.baeldung.hibernate.arraymapping.CustomIntegerArrayType")
+ private Integer[] locations;
+
+ @Type(type = "string-array")
+ @Column(
+ name = "phone_numbers",
+ columnDefinition = "text[]"
+ )
+ private String[] phoneNumbers;
+
+ 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;
+ }
+
+ public String[] getRoles() {
+ return roles;
+ }
+
+ public void setRoles(String[] roles) {
+ this.roles = roles;
+ }
+
+ public Integer[] getLocations() {
+ return locations;
+ }
+
+ public void setLocations(Integer[] locations) {
+ this.locations = locations;
+ }
+
+ public String[] getPhoneNumbers() {
+ return phoneNumbers;
+ }
+
+ public void setPhoneNumbers(String[] phoneNumbers) {
+ this.phoneNumbers = phoneNumbers;
+ }
+
+}
diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java
new file mode 100644
index 0000000000..ba0ccc2aa2
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java
@@ -0,0 +1,133 @@
+package com.baeldung.hibernate.arraymapping;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+
+public class ArrayMappingIntegrationTest {
+
+ private Session session;
+ private Transaction transaction;
+
+ @BeforeEach
+ public void setup() throws IOException {
+ try {
+ session = HibernateSessionUtil.getSessionFactory().openSession();
+ transaction = session.beginTransaction();
+
+ bootstrapData();
+
+ } catch (HibernateException | IOException e) {
+ System.out.println("Can't connect to a PostgreSQL DB");
+ }
+ }
+
+ @AfterEach
+ public void cleanup() {
+ if (null != session) {
+ transaction.rollback();
+ session.close();
+ }
+ }
+
+ @Test
+ public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() throws HibernateException, IOException {
+ if (null != session) {
+ User user = session.find(User.class, 1L);
+
+ assertEquals("john", user.getName());
+ assertEquals("superuser", user.getRoles()[0]);
+ assertEquals("admin", user.getRoles()[1]);
+ assertEquals(100, user.getLocations()[0]);
+ assertEquals(389, user.getLocations()[1]);
+ assertEquals("7000000000", user.getPhoneNumbers()[0]);
+ assertEquals("8000000000", user.getPhoneNumbers()[1]);
+ }
+ }
+
+ @Test
+ public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() throws HibernateException, IOException {
+ if (null != session) {
+ transaction = session.beginTransaction();
+
+ User user = new User();
+ user.setId(2L);
+ user.setName("smith");
+
+ String[] roles = {"admin", "employee"};
+ user.setRoles(roles);
+
+ Integer[] locations = {190, 578};
+ user.setLocations(locations);
+
+ session.persist(user);
+ session.flush();
+ session.clear();
+
+ transaction.commit();
+
+ User userDBObj = session.find(User.class, 2L);
+
+ assertEquals("smith", userDBObj.getName());
+ assertEquals("admin", userDBObj.getRoles()[0]);
+ assertEquals(578, userDBObj.getLocations()[1]);
+ }
+ }
+
+ @Test
+ public void givenArrayMapping_whenArrayIsUpdated_thenPersistInDB() throws HibernateException, IOException {
+ if (null != session) {
+ transaction = session.beginTransaction();
+
+ User user = session.find(User.class, 1L);
+
+ String[] updatedRoles = {"superuser", "superadmin"};
+ String[] updatedPhoneNumbers = {"9000000000"};
+
+ user.setRoles(updatedRoles);
+ user.setPhoneNumbers(updatedPhoneNumbers);
+
+ session.persist(user);
+ session.flush();
+ session.clear();
+
+ User userDBObj = session.find(User.class, 1L);
+
+ assertEquals("john", userDBObj.getName());
+ assertEquals("superadmin", userDBObj.getRoles()[1]);
+ assertEquals("9000000000", userDBObj.getPhoneNumbers()[0]);
+ }
+ }
+
+ public void bootstrapData() {
+ session.createQuery("delete from User").executeUpdate();
+
+ User user = new User();
+ user.setId(1L);
+ user.setName("john");
+
+ String[] roles = {"superuser", "admin"};
+ user.setRoles(roles);
+
+ Integer[] locations = {100, 389};
+ user.setLocations(locations);
+
+ String[] phoneNumbers = {"7000000000", "8000000000"};
+ user.setPhoneNumbers(phoneNumbers);
+
+ session.persist(user);
+ session.flush();
+ session.clear();
+
+ transaction.commit();
+ }
+
+}
diff --git a/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties
new file mode 100644
index 0000000000..72e3dcd781
--- /dev/null
+++ b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties
@@ -0,0 +1,14 @@
+hibernate.connection.driver_class=org.postgresql.Driver
+hibernate.connection.url=jdbc:postgresql://localhost:5432/postgres
+hibernate.connection.username=web
+hibernate.connection.autocommit=true
+jdbc.password=
+
+hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
+hibernate.show_sql=true
+hibernate.hbm2ddl.auto=none
+
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.acquire_increment=5
+hibernate.c3p0.timeout=1800
diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml
index 11673935b1..d81bfca5bd 100644
--- a/persistence-modules/java-jpa-3/pom.xml
+++ b/persistence-modules/java-jpa-3/pom.xml
@@ -68,6 +68,12 @@
${assertj.version}
test
+
+ junit
+ junit
+ ${junit.version}
+ test
+
diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java
new file mode 100644
index 0000000000..88e742adce
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java
@@ -0,0 +1,41 @@
+package com.baeldung.jpa.IdGeneration;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class User {
+
+ @Id
+// @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+ private String username;
+ private String password;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java
new file mode 100644
index 0000000000..9c34ef9bb4
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java
@@ -0,0 +1,19 @@
+package com.baeldung.jpa.IdGeneration;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Transactional;
+
+public class UserService {
+
+ EntityManager entityManager;
+
+ public UserService(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ @Transactional
+ public long saveUser(User user){
+ entityManager.persist(user);
+ return user.getId();
+ }
+}
diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
index 19ecae8491..bc41f35c01 100644
--- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
+++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
@@ -97,4 +97,20 @@
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+ com.baeldung.jpa.IdGeneration.User
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java
new file mode 100644
index 0000000000..941ad52344
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java
@@ -0,0 +1,47 @@
+package com.baeldung.jpa.IdGeneration;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import java.util.UUID;
+
+public class IdGenerationIntegrationTest {
+
+ private static EntityManager entityManager;
+ private static UserService service;
+
+ @BeforeClass
+ public static void setup() {
+ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-id-generation");
+ entityManager = factory.createEntityManager();
+ service = new UserService(entityManager);
+ }
+
+ @Test
+ public void whenNewUserIsPersisted_thenEntityHasNoId() {
+ User user = new User();
+ user.setUsername("test");
+ user.setPassword(UUID.randomUUID().toString());
+
+ long index = service.saveUser(user);
+ Assert.assertEquals(0L, index);
+ }
+
+ @Test
+ public void whenTransactionIsControlled_thenEntityHasId() {
+ User user = new User();
+ user.setUsername("test");
+ user.setPassword(UUID.randomUUID().toString());
+
+ entityManager.getTransaction().begin();
+ long index = service.saveUser(user);
+ entityManager.getTransaction().commit();
+
+ Assert.assertEquals(2L, index);
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java
new file mode 100644
index 0000000000..95a3708173
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java
@@ -0,0 +1,25 @@
+package com.baeldung.attribute.override.entity;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Address {
+ private String name;
+ private String city;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java
new file mode 100644
index 0000000000..9918cbaa70
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java
@@ -0,0 +1,29 @@
+package com.baeldung.attribute.override.entity;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import java.time.LocalDate;
+
+@Embeddable
+public class Brand {
+ private String name;
+ private LocalDate foundationDate;
+ @Embedded
+ private Address address;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public LocalDate getFoundationDate() {
+ return foundationDate;
+ }
+
+ public void setFoundationDate(LocalDate foundationDate) {
+ this.foundationDate = foundationDate;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java
new file mode 100644
index 0000000000..5421090e58
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java
@@ -0,0 +1,54 @@
+package com.baeldung.attribute.override.entity;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import java.util.Map;
+
+@Entity
+@AttributeOverride(name = "identifier", column = @Column(name = "VIN"))
+public class Car extends Vehicle {
+
+ private String model;
+ private String name;
+ @Embedded
+ @AttributeOverrides({
+ @AttributeOverride(name = "name", column = @Column(name = "BRAND_NAME", length = 5)),
+ @AttributeOverride(name = "address.name", column = @Column(name = "ADDRESS_NAME"))
+ })
+ private Brand brand;
+ @ElementCollection
+ @AttributeOverrides({
+ @AttributeOverride(name = "key.name", column = @Column(name = "OWNER_NAME")),
+ @AttributeOverride(name = "key.surname", column = @Column(name = "OWNER_SURNAME")),
+ @AttributeOverride(name = "value.name", column = @Column(name = "ADDRESS_NAME")),
+ })
+ Map owners;
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Brand getBrand() {
+ return brand;
+ }
+
+ public void setBrand(Brand brand) {
+ this.brand = brand;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java
new file mode 100644
index 0000000000..28ef6c7974
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java
@@ -0,0 +1,25 @@
+package com.baeldung.attribute.override.entity;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Owner {
+ private String name;
+ private String surname;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java
new file mode 100644
index 0000000000..2d4c0c04b3
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java
@@ -0,0 +1,38 @@
+package com.baeldung.attribute.override.entity;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+@MappedSuperclass
+public class Vehicle {
+ @Id
+ @GeneratedValue
+ private Integer id;
+ private String identifier;
+ private Integer numberOfWheels;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public Integer getNumberOfWheels() {
+ return numberOfWheels;
+ }
+
+ public void setNumberOfWheels(Integer numberOfWheels) {
+ this.numberOfWheels = numberOfWheels;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java
new file mode 100644
index 0000000000..17cea77d89
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java
@@ -0,0 +1,7 @@
+package com.baeldung.attribute.override.repository;
+
+import com.baeldung.attribute.override.entity.Car;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface CarRepository extends JpaRepository {
+}
diff --git a/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java b/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java
new file mode 100644
index 0000000000..4cc599c7de
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java
@@ -0,0 +1,56 @@
+package com.baeldung.attribute.override;
+
+import com.baeldung.Application;
+import com.baeldung.attribute.override.entity.Address;
+import com.baeldung.attribute.override.entity.Brand;
+import com.baeldung.attribute.override.entity.Car;
+import com.baeldung.attribute.override.repository.CarRepository;
+import org.assertj.core.api.Assertions;
+import org.jetbrains.annotations.NotNull;
+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 org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { Application.class })
+public class AttributeOverrideIntegrationTest {
+
+ private static final LocalDate FORD_FOUNDATION_DATE = LocalDate.parse("1903-06-16");
+ @Autowired
+ CarRepository carRepository;
+
+ @Test
+ @Transactional
+ public void whenInsertingCar_thenEmbeddedAndMappedFieldsArePopulated() {
+
+ Car fordMustang = createMustang();
+
+ carRepository.save(fordMustang);
+ Car actualCar = carRepository.getOne(fordMustang.getId());
+
+ Assertions.assertThat(actualCar).isEqualTo(fordMustang);
+ }
+
+ @NotNull
+ private Car createMustang() {
+ Address address = new Address();
+ address.setName("Ford United States");
+ address.setCity("Dearborn");
+
+ Brand ford = new Brand();
+ ford.setName("Ford");
+ ford.setFoundationDate(FORD_FOUNDATION_DATE);
+
+ Car fordMustang = new Car();
+ fordMustang.setIdentifier("WP1AB29P88LA47599");
+ fordMustang.setModel("Ford");
+ fordMustang.setName("My car");
+ fordMustang.setBrand(ford);
+ return fordMustang;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java
new file mode 100644
index 0000000000..ef06f77c45
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java
@@ -0,0 +1,68 @@
+package com.baeldung.softdelete;
+
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.Filter;
+import org.hibernate.annotations.FilterDef;
+import org.hibernate.annotations.ParamDef;
+import org.hibernate.annotations.SQLDelete;
+
+@Entity
+@Table(name = "tbl_products")
+@SQLDelete(sql = "UPDATE tbl_products SET deleted = true WHERE id=?")
+@FilterDef(name = "deletedProductFilter", parameters = @ParamDef(name = "isDeleted", type = "boolean"))
+@Filter(name = "deletedProductFilter", condition = "deleted = :isDeleted")
+public class Product implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String name;
+
+ private double price;
+
+ private boolean deleted = Boolean.FALSE;
+
+ 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;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+
+ public boolean isDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(boolean deleted) {
+ this.deleted = deleted;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java
new file mode 100644
index 0000000000..ebfdfbb2e7
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java
@@ -0,0 +1,34 @@
+package com.baeldung.softdelete;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/products")
+public class ProductController {
+
+ @Autowired
+ private ProductService productService;
+
+ @PostMapping
+ public Product createOne(@RequestBody Product product) {
+ return productService.create(product);
+ }
+
+ @DeleteMapping("/{id}")
+ public void removeOne(@PathVariable("id") Long id) {
+ productService.remove(id);
+ }
+
+ @GetMapping
+ public Iterable findAll(@RequestParam(value = "isDeleted", required = false, defaultValue = "false") boolean isDeleted) {
+ return productService.findAll(isDeleted);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java
new file mode 100644
index 0000000000..a305a142aa
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java
@@ -0,0 +1,7 @@
+package com.baeldung.softdelete;
+
+import org.springframework.data.repository.CrudRepository;
+
+public interface ProductRepository extends CrudRepository{
+
+}
diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java
new file mode 100644
index 0000000000..82d02fa87c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java
@@ -0,0 +1,35 @@
+package com.baeldung.softdelete;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.Filter;
+import org.hibernate.Session;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ProductService {
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Autowired
+ private EntityManager entityManager;
+
+ public Product create(Product product) {
+ return productRepository.save(product);
+ }
+
+ public void remove(Long id){
+ productRepository.deleteById(id);
+ }
+
+ public Iterable findAll(boolean isDeleted){
+ Session session = entityManager.unwrap(Session.class);
+ Filter filter = session.enableFilter("deletedProductFilter");
+ filter.setParameter("isDeleted", isDeleted);
+ Iterable products = productRepository.findAll();
+ session.disableFilter("deletedProductFilter");
+ return products;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties
index af0df308cd..18ef8d4e60 100644
--- a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties
+++ b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties
@@ -5,10 +5,5 @@ spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.generate_statistics=true
-# JPA-Schema-Generation
-# Use below configuration to generate database schema create commands based on the entity models
-# and export them into the create.sql file
-#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
-#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
-#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-source=metadata
-#spring.jpa.properties.hibernate.format_sql=true
\ No newline at end of file
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
+
diff --git a/pom.xml b/pom.xml
index ab3c73ff8a..d8bf527184 100644
--- a/pom.xml
+++ b/pom.xml
@@ -623,6 +623,7 @@
spring-boot-rest-2
spring-caching
+ spring-caching-2
spring-cloud
spring-cloud-bus
@@ -1079,6 +1080,7 @@
spring-boot-rest-2
spring-caching
+ spring-caching-2
spring-cloud
spring-cloud-bus
@@ -1274,6 +1276,7 @@
+ spring-boot-modules/spring-boot-cassandre
core-java-modules/core-java-9
core-java-modules/core-java-9-improvements
core-java-modules/core-java-9-jigsaw
diff --git a/reactor-core/README.md b/reactor-core/README.md
index 0214aa26fd..08dac354ab 100644
--- a/reactor-core/README.md
+++ b/reactor-core/README.md
@@ -8,3 +8,4 @@ This module contains articles about Reactor Core.
- [Combining Publishers in Project Reactor](https://www.baeldung.com/reactor-combine-streams)
- [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor)
- [How to Extract a Mono’s Content in Java](https://www.baeldung.com/java-string-from-mono)
+- [How to Convert Mono> Into Flux](https://www.baeldung.com/java-mono-list-to-flux)
diff --git a/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java b/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java
index f9e67b0a2f..0c6e0c07ef 100644
--- a/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java
+++ b/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java
@@ -1,10 +1,14 @@
package com.baeldung.mono;
import org.junit.Test;
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertEquals;
@@ -40,4 +44,40 @@ public class MonoUnitTest {
// blocking
return Mono.just("Hello world!");
}
+
+ @Test
+ public void whenMonoProducesListOfElements_thenConvertToFluxofElements() {
+
+ Mono> monoList = monoOfList();
+
+ StepVerifier.create(monoTofluxUsingFlatMapIterable(monoList))
+ .expectNext("one", "two", "three", "four")
+ .verifyComplete();
+
+ StepVerifier.create(monoTofluxUsingFlatMapMany(monoList))
+ .expectNext("one", "two", "three", "four")
+ .verifyComplete();
+ }
+
+ private Flux monoTofluxUsingFlatMapIterable(Mono> monoList) {
+ return monoList
+ .flatMapIterable(list -> list)
+ .log();
+ }
+
+ private Flux monoTofluxUsingFlatMapMany(Mono> monoList) {
+ return monoList
+ .flatMapMany(Flux::fromIterable)
+ .log();
+ }
+
+ private Mono> monoOfList() {
+ List list = new ArrayList<>();
+ list.add("one");
+ list.add("two");
+ list.add("three");
+ list.add("four");
+
+ return Mono.just(list);
+ }
}
diff --git a/spring-boot-modules/spring-boot-cassandre/README.md b/spring-boot-modules/spring-boot-cassandre/README.md
new file mode 100644
index 0000000000..14ffbb7d6b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/README.md
@@ -0,0 +1,11 @@
+# Cassandre trading bot example
+
+This project is an example of a trading bot developed with Cassandre
+
+## Running the examples
+
+* `mvn test` - Run strategy backtesting
+* `mvn spring-boot:run` - Run the bot
+
+## Relevant Articles
+- [Build a Trading Bot with Cassandre Spring Boot Starter](https://www.baeldung.com/build-a-trading-bot-with-cassandre-spring-boot-starter/)
diff --git a/spring-boot-modules/spring-boot-cassandre/pom.xml b/spring-boot-modules/spring-boot-cassandre/pom.xml
new file mode 100644
index 0000000000..75163d2c2b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.5
+
+
+ com.example
+ demo
+ 0.0.1-SNAPSHOT
+ Cassandre trading bot tutorial
+ Cassandre trading bot tutorial
+
+ 11
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ tech.cassandre.trading.bot
+ cassandre-trading-bot-spring-boot-starter
+ 4.2.1
+
+
+ org.knowm.xchange
+ xchange-kucoin
+ 5.0.7
+
+
+ org.hsqldb
+ hsqldb
+ 2.5.1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ tech.cassandre.trading.bot
+ cassandre-trading-bot-spring-boot-starter-test
+ 4.2.1
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.4.5
+
+
+
+
+
diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java
new file mode 100644
index 0000000000..094d95b93f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java
@@ -0,0 +1,13 @@
+package com.example.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DemoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java
new file mode 100644
index 0000000000..ea8ae74aa6
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java
@@ -0,0 +1,66 @@
+package com.example.demo;
+
+import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.CLOSED;
+import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.OPENED;
+import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.BTC;
+import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.USDT;
+
+import java.math.BigDecimal;
+import java.util.Optional;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import tech.cassandre.trading.bot.dto.market.TickerDTO;
+import tech.cassandre.trading.bot.dto.position.PositionDTO;
+import tech.cassandre.trading.bot.dto.position.PositionRulesDTO;
+import tech.cassandre.trading.bot.dto.user.AccountDTO;
+import tech.cassandre.trading.bot.dto.util.CurrencyPairDTO;
+import tech.cassandre.trading.bot.strategy.BasicCassandreStrategy;
+import tech.cassandre.trading.bot.strategy.CassandreStrategy;
+
+@CassandreStrategy
+public class MyFirstStrategy extends BasicCassandreStrategy {
+
+ private final Logger logger = LoggerFactory.getLogger(MyFirstStrategy.class);
+
+ @Override
+ public Set getRequestedCurrencyPairs() {
+ return Set.of(new CurrencyPairDTO(BTC, USDT));
+ }
+
+ @Override
+ public Optional getTradeAccount(Set accounts) {
+ return accounts.stream()
+ .filter(a -> "trade".equals(a.getName()))
+ .findFirst();
+ }
+
+ @Override
+ public void onTickerUpdate(TickerDTO ticker) {
+ logger.info("Received a new ticker : {}", ticker);
+
+ if (new BigDecimal("56000").compareTo(ticker.getLast()) == -1) {
+
+ if (canBuy(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"))) {
+ PositionRulesDTO rules = PositionRulesDTO.builder()
+ .stopGainPercentage(4f)
+ .stopLossPercentage(25f)
+ .build();
+ createLongPosition(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"), rules);
+ }
+
+ }
+ }
+
+ @Override
+ public void onPositionStatusUpdate(PositionDTO position) {
+ if (position.getStatus() == OPENED) {
+ logger.info("> New position opened : {}", position.getPositionId());
+ }
+ if (position.getStatus() == CLOSED) {
+ logger.info("> Position closed : {}", position.getDescription());
+ }
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties b/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties
new file mode 100644
index 0000000000..5ecdabd47a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties
@@ -0,0 +1,22 @@
+#
+# Exchange configuration.
+cassandre.trading.bot.exchange.name=kucoin
+cassandre.trading.bot.exchange.username=kucoin.cassandre.test@gmail.com
+cassandre.trading.bot.exchange.passphrase=cassandre
+cassandre.trading.bot.exchange.key=6054ad25365ac6000689a998
+cassandre.trading.bot.exchange.secret=af080d55-afe3-47c9-8ec1-4b479fbcc5e7
+#
+# Modes
+cassandre.trading.bot.exchange.modes.sandbox=true
+cassandre.trading.bot.exchange.modes.dry=false
+#
+# Exchange API calls rates (ms or standard ISO 8601 duration like 'PT5S').
+cassandre.trading.bot.exchange.rates.account=2000
+cassandre.trading.bot.exchange.rates.ticker=2000
+cassandre.trading.bot.exchange.rates.trade=2000
+#
+# Database configuration.
+cassandre.trading.bot.database.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
+cassandre.trading.bot.database.datasource.url=jdbc:hsqldb:mem:cassandre
+cassandre.trading.bot.database.datasource.username=sa
+cassandre.trading.bot.database.datasource.password=
diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java
new file mode 100644
index 0000000000..eaa99696e2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.demo;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class DemoApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java
new file mode 100644
index 0000000000..bf7c353821
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java
@@ -0,0 +1,55 @@
+package com.example.demo;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.OPENED;
+import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.USDT;
+
+import java.util.HashMap;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+
+import tech.cassandre.trading.bot.dto.util.CurrencyDTO;
+import tech.cassandre.trading.bot.dto.util.GainDTO;
+import tech.cassandre.trading.bot.test.mock.TickerFluxMock;
+
+@SpringBootTest
+@Import(TickerFluxMock.class)
+@DisplayName("Simple strategy test")
+public class MyFirstStrategyUnitTest {
+
+ private final Logger logger = LoggerFactory.getLogger(MyFirstStrategyUnitTest.class);
+
+ @Autowired
+ private MyFirstStrategy strategy;
+
+ @Autowired
+ private TickerFluxMock tickerFluxMock;
+
+ @Test
+ @DisplayName("Check gains")
+ public void whenTickersArrives_thenCheckGains() {
+ await().forever().until(() -> tickerFluxMock.isFluxDone());
+
+ final HashMap gains = strategy.getGains();
+
+ logger.info("Cumulated gains:");
+ gains.forEach((currency, gain) -> logger.info(currency + " : " + gain.getAmount()));
+
+ logger.info("Position still opened :");
+ strategy.getPositions()
+ .values()
+ .stream()
+ .filter(p -> p.getStatus().equals(OPENED))
+ .forEach(p -> logger.info(" - {} " + p.getDescription()));
+
+ assertTrue(gains.get(USDT).getPercentage() > 0);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties b/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties
new file mode 100644
index 0000000000..3d6feb09d7
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties
@@ -0,0 +1,22 @@
+#
+# Exchange configuration.
+cassandre.trading.bot.exchange.name=kucoin
+cassandre.trading.bot.exchange.username=kucoin.cassandre.test@gmail.com
+cassandre.trading.bot.exchange.passphrase=cassandre
+cassandre.trading.bot.exchange.key=6054ad25365ac6000689a998
+cassandre.trading.bot.exchange.secret=af080d55-afe3-47c9-8ec1-4b479fbcc5e7
+#
+# Modes
+cassandre.trading.bot.exchange.modes.sandbox=true
+cassandre.trading.bot.exchange.modes.dry=true
+#
+# Exchange API calls rates (ms or standard ISO 8601 duration like 'PT5S').
+cassandre.trading.bot.exchange.rates.account=2000
+cassandre.trading.bot.exchange.rates.ticker=2000
+cassandre.trading.bot.exchange.rates.trade=2000
+#
+# Database configuration.
+cassandre.trading.bot.database.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
+cassandre.trading.bot.database.datasource.url=jdbc:hsqldb:mem:cassandre
+cassandre.trading.bot.database.datasource.username=sa
+cassandre.trading.bot.database.datasource.password=
diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv b/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv
new file mode 100644
index 0000000000..b89bd96bdc
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv
@@ -0,0 +1,89 @@
+1612569600 38294.4 39195.5 40964.2 38217.5 3882.29460938 153897343.463150723
+1612656000 39195.4 38807.6 39623.6 37341.4 2389.96820017 91972455.834535369
+1612742400 38807.6 46373.5 46767.9 38010 4971.54731481 212132648.426718929
+1612828800 46374.6 46434.8 48139.3 44961 4330.72854712 201891604.027160303
+1612915200 46430 44812.2 47300 43687.5 4351.84907778 198189685.592028516
+1613001600 44806.1 47941.5 48647.6 44005.8 4045.91883504 188171651.974437139
+1613088000 47963.1 47310.7 48958.8 46181.2 3356.01832119 159561721.419695848
+1613174400 47305.4 47152.6 48120.5 46225.5 2740.99221759 129227867.922246174
+1613260800 47152.5 48591.9 49686.9 47026.3 3359.4690565 163299915.839307312
+1613347200 48587.2 47904.4 49003.6 42841.6 3974.98461358 188990056.26923591
+1613433600 47913.1 49147.7 50619.3 47023.9 3599.85370182 176084748.845657596
+1613520000 49147.7 52118.1 52609.6 48931.1 3356.85082847 170893567.530348564
+1613606400 52114.3 51568.9 52522.9 50906.4 2183.18379408 113272339.172174965
+1613692800 51561.1 55890.5 56317.7 50727 3749.6920105 200656740.865959032
+1613779200 55893.6 55851.5 57622.6 53463.3 3394.87226216 190744601.429330887
+1613865600 55851.4 57423 58336.3 55489.6 2514.02340013 143658132.671448082
+1613952000 57420.6 54096.6 57517.8 44160 6125.32442907 330513978.457310237
+1614038400 54085.9 48908.3 54174.2 44900 8048.96505298 389277314.445372085
+1614124800 48902.9 49685.2 51361.9 47003.2 4816.75027676 239303706.844272809
+1614211200 49676.5 47082.7 52019.6 46624.4 3701.80236678 184044004.383578525
+1614297600 47082 46289.6 48408.8 44135 5329.77125908 247604118.914146591
+1614384000 46290.2 46114.4 48381.9 44836.5 2872.64640734 134946360.020429589
+1614470400 46111.3 45141.6 46626.1 43004.3 3940.17863714 175990962.484551548
+1614556800 45136.5 49590.3 49771.3 44958.9 3548.51026561 169389196.772247159
+1614643200 49590.3 48441.2 50201.6 47052.8 2936.94454126 142575425.463057812
+1614729600 48440.6 50345.5 52623.9 48100 3177.38943911 160801620.821885745
+1614816000 50347.6 48374.5 51762.1 47505.7 3624.17683614 178873453.27515484
+1614902400 48374.5 48758.9 49450 46189.8 3697.34556922 176318969.507294567
+1614988800 48746.9 48871.9 49255.1 47001 1949.15311354 94201823.810314647
+1615075200 48885 50930.4 51424.7 48885 2444.3584982 122962479.787996993
+1615161600 50956.6 52377 52387.5 49287.5 2710.99151191 137751640.241286989
+1615248000 52376.9 54867.6 54867.6 51833.8 3070.93581512 165487483.114064122
+1615334400 54867.5 55865.5 57364 52911.4 4049.50553851 224565244.752334892
+1615420800 55863.7 57781.1 58150 54238 3403.69441456 191915265.020541521
+1615507200 57781 57238.5 58057.5 55013.7 4031.0376629 228810606.091302364
+1615593600 57220.7 61180.9 61815.3 56059.3 4394.62318443 259602986.875738328
+1615680000 61174.3 59000 61700 59000 3084.33952274 186155667.656432156
+1615766400 59000 55607.1 60632.9 54525.6 5910.33518227 338468393.188725572
+1615852800 55607.1 56880.3 56918.9 53240.3 7410.49057723 409052587.523700888
+1615939200 56880.3 58875.8 58951.8 54147.5 5828.79026943 328135601.648660052
+1616025600 58882.9 57648.9 60107.7 57000 5073.7458698 297279816.540519693
+1616112000 57648.9 58024.2 59450.1 56071 3727.09434161 217005823.723994618
+1616198400 58024.3 58113.5 59874.6 57825.6 2746.52973805 161565114.165299707
+1616284800 58113.5 57350.2 58591.6 55501 3265.35649781 186845535.507151609
+1616371200 57345.3 54096.1 58415.5 53667 4219.99501831 237141977.003568352
+1616457600 54086.8 54348.4 55823.1 52986.3 4374.34046303 239135883.538398977
+1616544000 54348.4 52307.4 57200 51499.6 6416.76024581 351202326.218690674
+1616630400 52307.1 51301.7 53239.1 50455 7242.6466396 375950351.557038048
+1616716800 51301.7 55032 55062.5 51225.3 4609.48192944 245299757.451540308
+1616803200 55031.9 55820.4 56628.6 53967.5 3634.73588532 200758048.816804103
+1616889600 55820.3 55772.9 56541 54666.6 3158.20452681 176119911.151714842
+1616976000 55772.8 57628.9 58400.5 54926.5 4413.63121553 251384747.301649587
+1617062400 57630.8 58754.6 59351.9 57072.8 3563.87315049 208118726.050535887
+1617148800 58753.2 58745.9 59800 56357.5 4921.45848213 288469053.074870873
+1617235200 58745.5 58735.7 59487.1 57879 3163.98213108 186078130.901422269
+1617321600 58735.7 58963.6 60179.1 58460.7 2553.76427314 151446539.609794648
+1617408000 58963.6 57058.3 59795 56721.2 2512.19109578 147434403.06515736
+1617494400 57052.5 58201.4 58481.2 56432.6 2069.14670128 119228330.17272614
+1617580800 58201.4 59116.2 59254.1 56501 3003.76043377 174821106.684799505
+1617667200 59116.2 57988.3 59497.5 57304.8 2964.86183859 173169186.845682699
+1617753600 57988.3 55958.2 58668.6 55439 5277.04906389 299996660.411940246
+1617840000 55958.2 58076.7 58141 55700.6 3175.60482079 181817013.517575328
+1617926400 58076.7 58131.6 58900 57666.9 3516.19104669 204849717.059779284
+1618012800 58138.2 59770.2 61350 57902.1 5533.50675561 332014577.538990658
+1618099200 59770.2 60007.6 60687.4 59247.6 3896.37426019 233158562.799039154
+1618185600 60007.6 59863.4 61270.7 59417.4 4611.409014 277430208.743380477
+1618272000 59863.4 63578.7 63759.7 59815 6906.310253 430518557.569547626
+1618358400 63578.7 62958.7 64840 61000 7696.509177 487298143.928065301
+1618444800 62954.4 63152.6 63772.1 62023.9 4709.82427144 296178401.81115496
+1618531200 63152.6 61342.6 63509.7 59930.8 8295.32523869 510423835.691643255
+1618617600 61342.7 59995.2 62497.8 59599.6 5367.42979289 328364887.709585395
+1618704000 59995.3 56150.6 60409.5 49001 11485.97101449 637797282.448645379
+1618790400 56152.7 55618.8 57583.4 54205.2 7721.306905 432634348.931871989
+1618876800 55618.7 56427.8 57061.6 53328 8677.75606016 480164200.559836543
+1618963200 56426.1 53793.6 56761.7 53602 6240.82191836 345339357.806167462
+1619049600 53793.5 51696.4 55474.7 50400 8879.16016304 475394174.249706678
+1619136000 51691.2 51102.7 52112.1 47502.1 8885.07060366 441295812.644904319
+1619222400 51109.8 50033 51157.9 48676.5 4833.41744745 241336360.887795675
+1619308800 50041.5 49086.9 50554.6 46966.2 4805.34664069 237153315.222670555
+1619395200 49069 54000.2 54336.4 48775.8 6695.12934907 353727728.269533971
+1619481600 53997.1 55014.3 55439 53240.8 4344.22291318 237020455.905144335
+1619568000 55014.2 54833.2 56399.1 53808.3 4801.04618634 262912695.604761319
+1619654400 54833.1 53558.4 55181.2 52340.1 4356.05177188 234153663.397444462
+1619740800 53558.5 57697.3 57936.4 53042.6 5000.47557303 277531927.921795199
+1619827200 57697.3 57794.7 58471.4 57006.3 3639.78966647 210179438.189007639
+1619913600 57794.7 56568.5 57903.7 56044.3 3508.52428767 199206958.05741809
+1620000000 56568.5 57159.7 58977.9 56451.3 4780.43387226 276554749.540429296
+1620086400 57159.7 53196.3 57188.2 53083.3 7079.55804728 390469293.396018923
+1620172800 53196.3 57834.5 57979.7 52888 4224.63060355 233779565.506303973
diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv b/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv
new file mode 100644
index 0000000000..d0fa4e9767
--- /dev/null
+++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv
@@ -0,0 +1,3 @@
+BTC 1
+USDT 100000
+ETH 10
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java
new file mode 100644
index 0000000000..b1e6badd43
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java
@@ -0,0 +1,11 @@
+package com.baeldung.filtersinterceptors;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication(scanBasePackages = "com.baeldung.filtersinterceptors")
+public class FilterInterceptorApp {
+ public static void main(String[] args) {
+ SpringApplication.run(FilterInterceptorApp.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java
new file mode 100644
index 0000000000..db2da63d43
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java
@@ -0,0 +1,19 @@
+package com.baeldung.filtersinterceptors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class HelloConroller {
+
+ private Logger logger = LoggerFactory.getLogger(HelloConroller.class);
+
+ @GetMapping("/hello")
+ public String hello() {
+ logger.info("Hello from the controller");
+ return "hello";
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java
new file mode 100644
index 0000000000..dc78cfbbb9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java
@@ -0,0 +1,26 @@
+package com.baeldung.filtersinterceptors;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LogFilter implements Filter {
+
+ private Logger logger = LoggerFactory.getLogger(LogFilter.class);
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ logger.info("Hello from: " + request.getLocalAddr());
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java
new file mode 100644
index 0000000000..b43b69415a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java
@@ -0,0 +1,32 @@
+package com.baeldung.filtersinterceptors;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+public class LogInterceptor implements HandlerInterceptor {
+
+ private Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ logger.info("preHandle");
+ return true;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ logger.info("postHandle");
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ logger.info("afterCompletion");
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java
new file mode 100644
index 0000000000..9f4c1c2166
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java
@@ -0,0 +1,15 @@
+package com.baeldung.filtersinterceptors;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new LogInterceptor());
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html
new file mode 100644
index 0000000000..9a9b0e707b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html
@@ -0,0 +1,10 @@
+
+
+
+Spring Filters vs Interceptors
+
+
+
+ Hello
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml b/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml
index 10570bb738..0f048ffa14 100644
--- a/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml
+++ b/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml
@@ -15,6 +15,7 @@ spring:
username: SA
bael:
property: stagingValue
+ stagingProperty: stagingPropertyValue
---
application:
servers:
diff --git a/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java b/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java
index e02d1de272..851d5e0432 100644
--- a/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java
+++ b/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java
@@ -17,14 +17,18 @@ public class StagingMultidocumentFilesIntegrationTest {
@Value("${bael.property}")
private String baelCustomProperty;
-
+
+ @Value("${bael.stagingProperty}")
+ private String baelStagingProperty;
+
@Value("${bael.root-level-property}")
private String baelRootProperty;
@Test
- @Disabled("Fix and update https://www.baeldung.com/spring-boot-yaml-vs-properties article")
public void givenProductionProfileActive_whenApplicationStarts_thenDefaultPropertiesUser() {
- assertThat(baelCustomProperty).isEqualTo("stagingValue");
+ assertThat(baelStagingProperty).isEqualTo("stagingPropertyValue");
+ // application.properties is loaded after the application.yml file and overrides the values
+ assertThat(baelCustomProperty).isEqualTo("defaultValue");
assertThat(baelRootProperty).isEqualTo("defaultRootLevelValue");
}
}
diff --git a/spring-boot-modules/spring-boot-testing/README.md b/spring-boot-modules/spring-boot-testing/README.md
index 1b7ad661c6..058c78c9bb 100644
--- a/spring-boot-modules/spring-boot-testing/README.md
+++ b/spring-boot-modules/spring-boot-testing/README.md
@@ -15,3 +15,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Testing Spring Boot @ConfigurationProperties](https://www.baeldung.com/spring-boot-testing-configurationproperties)
- [Prevent ApplicationRunner or CommandLineRunner Beans From Executing During Junit Testing](https://www.baeldung.com/spring-junit-prevent-runner-beans-testing-execution)
- [Testing in Spring Boot](https://www.baeldung.com/spring-boot-testing)
+- [Fixing the NoSuchMethodError JUnit Error](https://www.baeldung.com/junit-nosuchmethoderror)
diff --git a/spring-boot-rest-2/README.md b/spring-boot-rest-2/README.md
index f09159198c..41270d58ea 100644
--- a/spring-boot-rest-2/README.md
+++ b/spring-boot-rest-2/README.md
@@ -1,3 +1,4 @@
### Relevant Article:
- [Get All Endpoints in Spring Boot](https://www.baeldung.com/spring-boot-get-all-endpoints)
+- [HTTP PUT vs. POST in REST API](https://www.baeldung.com/rest-http-put-vs-post)
diff --git a/spring-boot-rest-2/pom.xml b/spring-boot-rest-2/pom.xml
index 32eff262dd..0560d6c9c7 100644
--- a/spring-boot-rest-2/pom.xml
+++ b/spring-boot-rest-2/pom.xml
@@ -30,6 +30,15 @@
springfox-boot-starter
3.0.0
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+ runtime
+
diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java
new file mode 100644
index 0000000000..5c005c70f0
--- /dev/null
+++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java
@@ -0,0 +1,57 @@
+package com.baeldung.putvspost;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class Address {
+
+ private @Id @GeneratedValue Long id;
+ private String name;
+ private String city;
+ private String postalCode;
+
+ Address() {
+ }
+
+ public Address(String name, String city, String postalCode) {
+ this.name = name;
+ this.city = city;
+ this.postalCode = postalCode;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getPostalCode() {
+ return postalCode;
+ }
+
+ public void setPostalCode(String postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ @Override
+ public String toString() {
+ return "Address [id=" + id + ", name=" + name + ", city=" + city + ", postalCode=" + postalCode + "]";
+ }
+
+}
diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java
new file mode 100644
index 0000000000..f989d5c211
--- /dev/null
+++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java
@@ -0,0 +1,57 @@
+package com.baeldung.putvspost;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class AddressController {
+
+ private final AddressRepository repository;
+
+ AddressController(AddressRepository repository) {
+ this.repository = repository;
+ }
+
+ @GetMapping("/addresses")
+ List getAllAddresses() {
+ return repository.findAll();
+ }
+
+ @GetMapping("/addresses/{id}")
+ Optional getAddressesById(@PathVariable Long id) {
+ return repository.findById(id);
+ }
+
+ @PostMapping("/addresses")
+ Address createNewAddress(@RequestBody Address newAddress) {
+ return repository.save(newAddress);
+ }
+
+ @PutMapping("/addresses/{id}")
+ Address replaceEmployee(@RequestBody Address newAddress, @PathVariable Long id) {
+
+ return repository.findById(id)
+ .map(address -> {
+ address.setCity(newAddress.getCity());
+ address.setPostalCode(newAddress.getPostalCode());
+ return repository.save(address);
+ })
+ .orElseGet(() -> {
+ return repository.save(newAddress);
+ });
+ }
+
+ @DeleteMapping("/addresses/{id}")
+ void deleteEmployee(@PathVariable Long id) {
+ repository.deleteById(id);
+ }
+
+}
diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java
new file mode 100644
index 0000000000..415a3c9030
--- /dev/null
+++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java
@@ -0,0 +1,7 @@
+package com.baeldung.putvspost;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface AddressRepository extends JpaRepository {
+
+}
diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java
new file mode 100644
index 0000000000..8cea53d269
--- /dev/null
+++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.putvspost;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class PutVsPostApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PutVsPostApplication.class, args);
+ }
+
+}
diff --git a/spring-caching-2/README.md b/spring-caching-2/README.md
new file mode 100644
index 0000000000..1375b5e8e4
--- /dev/null
+++ b/spring-caching-2/README.md
@@ -0,0 +1,3 @@
+### Relevant articles:
+
+- [Spring Boot Cache with Redis](https://www.baeldung.com/spring-boot-redis-cache)
diff --git a/spring-caching-2/pom.xml b/spring-caching-2/pom.xml
new file mode 100644
index 0000000000..6bb828e8bf
--- /dev/null
+++ b/spring-caching-2/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+ spring-caching-2
+ 0.1-SNAPSHOT
+ spring-caching-2
+ war
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+ 0.7.3
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.data
+ spring-data-commons
+
+
+ com.h2database
+ h2
+ runtime
+
+
+ org.projectlombok
+ lombok
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ it.ozimov
+ embedded-redis
+ ${embedded.redis.version}
+
+
+ org.slf4j
+ slf4j-simple
+
+
+ test
+
+
+
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java
new file mode 100644
index 0000000000..89bdc2779d
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java
@@ -0,0 +1,33 @@
+package com.baeldung.caching.redis;
+
+import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+
+import java.time.Duration;
+
+import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
+
+@Configuration
+public class CacheConfig {
+
+ @Bean
+ public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
+ return (builder) -> builder
+ .withCacheConfiguration("itemCache",
+ RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)))
+ .withCacheConfiguration("customerCache",
+ RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)));
+ }
+
+ @Bean
+ public RedisCacheConfiguration cacheConfiguration() {
+ return RedisCacheConfiguration.defaultCacheConfig()
+ .entryTtl(Duration.ofMinutes(60))
+ .disableCachingNullValues()
+ .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
+ }
+
+}
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java
new file mode 100644
index 0000000000..d6115a4833
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java
@@ -0,0 +1,21 @@
+package com.baeldung.caching.redis;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+public class Item implements Serializable {
+
+ @Id
+ String id;
+
+ String description;
+}
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java
new file mode 100644
index 0000000000..63122c5938
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java
@@ -0,0 +1,19 @@
+package com.baeldung.caching.redis;
+
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class ItemController {
+
+ private final ItemService itemService;
+
+ @GetMapping("/item/{id}")
+ public Item getItemById(@PathVariable String id) {
+ return itemService.getItemForId(id);
+ }
+
+}
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java
new file mode 100644
index 0000000000..d6222de621
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.caching.redis;
+
+import org.springframework.data.repository.CrudRepository;
+
+public interface ItemRepository extends CrudRepository- {
+}
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java
new file mode 100644
index 0000000000..6a59c7d74e
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java
@@ -0,0 +1,19 @@
+package com.baeldung.caching.redis;
+
+import lombok.AllArgsConstructor;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class ItemService {
+
+ private final ItemRepository itemRepository;
+
+ @Cacheable(value = "itemCache")
+ public Item getItemForId(String id) {
+ return itemRepository.findById(id)
+ .orElseThrow(RuntimeException::new);
+ }
+
+}
diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java
new file mode 100644
index 0000000000..3b337def01
--- /dev/null
+++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java
@@ -0,0 +1,14 @@
+package com.baeldung.caching.redis;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+
+@SpringBootApplication
+@EnableCaching
+public class RedisCacheApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RedisCacheApplication.class, args);
+ }
+}
diff --git a/spring-caching-2/src/main/resources/application.properties b/spring-caching-2/src/main/resources/application.properties
new file mode 100644
index 0000000000..080185b620
--- /dev/null
+++ b/spring-caching-2/src/main/resources/application.properties
@@ -0,0 +1,12 @@
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
+
+# Enabling H2 Console
+spring.h2.console.enabled=true
+spring.h2.console.path=/h2
+
+# Connection details
+#spring.redis.host=localhost
+#spring.redis.port=6379
diff --git a/spring-caching-2/src/main/resources/data.sql b/spring-caching-2/src/main/resources/data.sql
new file mode 100644
index 0000000000..74e359b877
--- /dev/null
+++ b/spring-caching-2/src/main/resources/data.sql
@@ -0,0 +1 @@
+INSERT INTO ITEM VALUES('abc','ITEM1');
\ No newline at end of file
diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java
new file mode 100644
index 0000000000..71a9729efd
--- /dev/null
+++ b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java
@@ -0,0 +1,84 @@
+package com.baeldung.caching.redis;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import redis.embedded.RedisServer;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@Import({ CacheConfig.class, ItemService.class })
+@ExtendWith(SpringExtension.class)
+@ImportAutoConfiguration(classes = { CacheAutoConfiguration.class, RedisAutoConfiguration.class })
+@EnableCaching
+class ItemServiceCachingIntegrationTest {
+
+ private static final String AN_ID = "id-1";
+ private static final String A_DESCRIPTION = "an item";
+
+ @MockBean
+ private ItemRepository mockItemRepository;
+
+ @Autowired
+ private ItemService itemService;
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @Test
+ void givenRedisCaching_whenFindItemById_thenItemReturnedFromCache() {
+ Item anItem = new Item(AN_ID, A_DESCRIPTION);
+ given(mockItemRepository.findById(AN_ID))
+ .willReturn(Optional.of(anItem));
+
+ Item itemCacheMiss = itemService.getItemForId(AN_ID);
+ Item itemCacheHit = itemService.getItemForId(AN_ID);
+
+ assertThat(itemCacheMiss).isEqualTo(anItem);
+ assertThat(itemCacheHit).isEqualTo(anItem);
+
+ verify(mockItemRepository, times(1)).findById(AN_ID);
+ assertThat(itemFromCache()).isEqualTo(anItem);
+ }
+
+ private Object itemFromCache() {
+ return cacheManager.getCache("itemCache").get(AN_ID).get();
+ }
+
+ @TestConfiguration
+ static class EmbeddedRedisConfiguration {
+
+ private final RedisServer redisServer;
+
+ public EmbeddedRedisConfiguration() {
+ this.redisServer = new RedisServer();
+ }
+
+ @PostConstruct
+ public void startRedis() {
+ redisServer.start();
+ }
+
+ @PreDestroy
+ public void stopRedis() {
+ this.redisServer.stop();
+ }
+ }
+
+}
diff --git a/spring-caching-2/src/test/resources/logback-test.xml b/spring-caching-2/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..215403c6a5
--- /dev/null
+++ b/spring-caching-2/src/test/resources/logback-test.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/spring-cloud/spring-cloud-circuit-breaker/pom.xml b/spring-cloud/spring-cloud-circuit-breaker/pom.xml
index f30c764d9b..ebf89d671c 100644
--- a/spring-cloud/spring-cloud-circuit-breaker/pom.xml
+++ b/spring-cloud/spring-cloud-circuit-breaker/pom.xml
@@ -14,20 +14,6 @@
..
-
-
- spring-release
- Spring Release
- https://repo.spring.io/release
-
- false
-
-
- true
-
-
-
-
diff --git a/spring-mobile/pom.xml b/spring-mobile/pom.xml
index 8b98e6d429..1593de27a8 100644
--- a/spring-mobile/pom.xml
+++ b/spring-mobile/pom.xml
@@ -32,19 +32,8 @@
-
-
- spring-milestones
- Spring Milestones
- https://repo.spring.io/libs-milestone
-
- false
-
-
-
-
- 2.0.0.M3
+ 1.1.5.RELEASE
\ No newline at end of file
diff --git a/spring-roo/pom.xml b/spring-roo/pom.xml
index 2c5d5590fa..d1cf3e6412 100644
--- a/spring-roo/pom.xml
+++ b/spring-roo/pom.xml
@@ -391,18 +391,6 @@
-
-
- maven-snapshot-repository
- Maven Snapshot Repository
- https://oss.sonatype.org/content/repositories/snapshots
-
- false
-
-
- true
-
-
spring-roo-repository
diff --git a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java
index d8fc58319f..687203d21a 100644
--- a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java
+++ b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java
@@ -14,7 +14,7 @@ import org.springframework.web.client.RestTemplate;
public class LargeFileDownloadIntegrationTest {
- static String FILE_URL = "http://ovh.net/files/1Mio.dat";
+ static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson+by+Baeldung.pdf";
RestTemplate restTemplate;
diff --git a/testing-modules/testing-libraries-2/pom.xml b/testing-modules/testing-libraries-2/pom.xml
index e7016a2387..5a57dc0958 100644
--- a/testing-modules/testing-libraries-2/pom.xml
+++ b/testing-modules/testing-libraries-2/pom.xml
@@ -72,6 +72,36 @@
testing-libraries-2
+
+
+ maven-war-plugin
+ 2.4
+
+ false
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco.version}
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-site
+ package
+
+ report
+
+
+
+
+
src/test/resources
@@ -81,11 +111,12 @@
+ 0.8.6
1.19.0
1.0.0
1.1.0
5.6.2
3.16.1
-
-
\ No newline at end of file
+
+
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java
new file mode 100644
index 0000000000..42f103a317
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java
@@ -0,0 +1,54 @@
+package com.baeldung.sonarqubeandjacoco.product;
+
+public class Product {
+
+ private int id;
+ private String name;
+ private int units;
+ private double price;
+
+ public Product() {
+ super();
+ }
+
+ public Product(int id, String name, int units, double price) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.units = units;
+ this.price = price;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getUnits() {
+ return units;
+ }
+
+ public void setUnits(int units) {
+ this.units = units;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+
+}
\ No newline at end of file
diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java
new file mode 100644
index 0000000000..da649851e0
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.sonarqubeandjacoco.product;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+import com.baeldung.sonarqubeandjacoco.product.Product;
+
+public class ProductUnitTest {
+
+ @Test
+ public void test() {
+ Product product = new Product();
+ product.setId(1);
+ assertNull(product.getName());
+ assert (product.getId() == 1);
+ }
+
+ @Test
+ public void testProduct() {
+ Product product = new Product(1, "product", 1, 2.0);
+ assertNotNull(product.getName());
+ }
+
+}