diff --git a/.gitignore b/.gitignore
index 180462a32f..7fe2778755 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,5 @@ jmeter/src/main/resources/*-JMeter.csv
**/dist
**/tmp
**/out-tsc
+**/nbproject/
+**/nb-configuration.xml
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 5e2d690b4e..683422dc97 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,7 @@ before_install:
- echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:+CMSClassUnloadingEnabled -XX:+UseG1GC -XX:-UseGCOverheadLimit'" > ~/.mavenrc
install: skip
-script: travis_wait 60 mvn -q install -Pdefault
+script: travis_wait 60 mvn -q install -Pdefault-first,default-second
sudo: required
diff --git a/README.md b/README.md
index adb17ca7e5..8e0a5eb9ee 100644
--- a/README.md
+++ b/README.md
@@ -21,3 +21,8 @@ In additional to Spring, the following technologies are in focus: `core Java`, `
Building the project
====================
To do the full build, do: `mvn install -Pdefault -Dgib.enabled=false`
+
+
+Building a single module
+====================
+To build a specific module run the command: `mvn clean install -Dgib.enabled=false` in the module directory
diff --git a/algorithms/README.md b/algorithms/README.md
index 9b3bbcdee5..9d347869bd 100644
--- a/algorithms/README.md
+++ b/algorithms/README.md
@@ -28,3 +28,6 @@
- [Calculate the Distance Between Two Points in Java](https://www.baeldung.com/java-distance-between-two-points)
- [Find the Intersection of Two Lines in Java](https://www.baeldung.com/java-intersection-of-two-lines)
- [Check If a String Contains All The Letters of The Alphabet](https://www.baeldung.com/java-string-contains-all-letters)
+- [Round Up to the Nearest Hundred](https://www.baeldung.com/java-round-up-nearest-hundred)
+- [Merge Sort in Java](https://www.baeldung.com/java-merge-sort)
+- [Calculate Percentage in Java](https://www.baeldung.com/java-calculate-percentage)
diff --git a/algorithms/pom.xml b/algorithms/pom.xml
index eda87d6c75..db4a1c2eff 100644
--- a/algorithms/pom.xml
+++ b/algorithms/pom.xml
@@ -17,6 +17,11 @@
commons-math3
${commons-math3.version}
+
+ commons-codec
+ commons-codec
+ ${commons-codec.version}
+
org.projectlombok
lombok
@@ -85,6 +90,7 @@
3.7.0
1.0.1
3.9.0
+ 1.11
\ No newline at end of file
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java b/algorithms/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java
new file mode 100644
index 0000000000..d3e251d3fd
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java
@@ -0,0 +1,110 @@
+package com.baeldung.algorithms.conversion;
+
+import java.math.BigInteger;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+
+import com.google.common.io.BaseEncoding;
+
+public class HexStringConverter {
+
+ /**
+ * Create a byte Array from String of hexadecimal digits using Character conversion
+ * @param hexString - Hexadecimal digits as String
+ * @return Desired byte Array
+ */
+ public byte[] decodeHexString(String hexString) {
+ if (hexString.length() % 2 == 1) {
+ throw new IllegalArgumentException("Invalid hexadecimal String supplied.");
+ }
+ byte[] bytes = new byte[hexString.length() / 2];
+
+ for (int i = 0; i < hexString.length(); i += 2) {
+ bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
+ }
+ return bytes;
+ }
+
+ /**
+ * Create a String of hexadecimal digits from a byte Array using Character conversion
+ * @param byteArray - The byte Array
+ * @return Desired String of hexadecimal digits in lower case
+ */
+ public String encodeHexString(byte[] byteArray) {
+ StringBuffer hexStringBuffer = new StringBuffer();
+ for (int i = 0; i < byteArray.length; i++) {
+ hexStringBuffer.append(byteToHex(byteArray[i]));
+ }
+ return hexStringBuffer.toString();
+ }
+
+ public String byteToHex(byte num) {
+ char[] hexDigits = new char[2];
+ hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
+ hexDigits[1] = Character.forDigit((num & 0xF), 16);
+ return new String(hexDigits);
+ }
+
+ public byte hexToByte(String hexString) {
+ int firstDigit = toDigit(hexString.charAt(0));
+ int secondDigit = toDigit(hexString.charAt(1));
+ return (byte) ((firstDigit << 4) + secondDigit);
+ }
+
+ private int toDigit(char hexChar) {
+ int digit = Character.digit(hexChar, 16);
+ if(digit == -1) {
+ throw new IllegalArgumentException("Invalid Hexadecimal Character: "+ hexChar);
+ }
+ return digit;
+ }
+
+ public String encodeUsingBigIntegerToString(byte[] bytes) {
+ BigInteger bigInteger = new BigInteger(1, bytes);
+ return bigInteger.toString(16);
+ }
+
+ public String encodeUsingBigIntegerStringFormat(byte[] bytes) {
+ BigInteger bigInteger = new BigInteger(1, bytes);
+ return String.format("%0" + (bytes.length << 1) + "x", bigInteger);
+ }
+
+ public byte[] decodeUsingBigInteger(String hexString) {
+ byte[] byteArray = new BigInteger(hexString, 16).toByteArray();
+ if (byteArray[0] == 0) {
+ byte[] output = new byte[byteArray.length - 1];
+ System.arraycopy(byteArray, 1, output, 0, output.length);
+ return output;
+ }
+ return byteArray;
+ }
+
+ public String encodeUsingDataTypeConverter(byte[] bytes) {
+ return DatatypeConverter.printHexBinary(bytes);
+ }
+
+ public byte[] decodeUsingDataTypeConverter(String hexString) {
+ return DatatypeConverter.parseHexBinary(hexString);
+ }
+
+ public String encodeUsingApacheCommons(byte[] bytes) throws DecoderException {
+ return Hex.encodeHexString(bytes);
+ }
+
+ public byte[] decodeUsingApacheCommons(String hexString) throws DecoderException {
+ return Hex.decodeHex(hexString);
+ }
+
+ public String encodeUsingGuava(byte[] bytes) {
+ return BaseEncoding.base16()
+ .encode(bytes);
+ }
+
+ public byte[] decodeUsingGuava(String hexString) {
+ return BaseEncoding.base16()
+ .decode(hexString.toUpperCase());
+ }
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/heapsort/Heap.java b/algorithms/src/main/java/com/baeldung/algorithms/heapsort/Heap.java
new file mode 100644
index 0000000000..8c98e4fc5c
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/heapsort/Heap.java
@@ -0,0 +1,136 @@
+package com.baeldung.algorithms.heapsort;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Heap> {
+
+ private List elements = new ArrayList<>();
+
+ public static > List sort(Iterable elements) {
+ Heap heap = of(elements);
+
+ List result = new ArrayList<>();
+
+ while (!heap.isEmpty()) {
+ result.add(heap.pop());
+ }
+
+ return result;
+ }
+
+ public static > Heap of(E... elements) {
+ return of(Arrays.asList(elements));
+ }
+
+ public static > Heap of(Iterable elements) {
+ Heap result = new Heap<>();
+ for (E element : elements) {
+ result.add(element);
+ }
+ return result;
+ }
+
+ public void add(E e) {
+ elements.add(e);
+ int elementIndex = elements.size() - 1;
+ while (!isRoot(elementIndex) && !isCorrectChild(elementIndex)) {
+ int parentIndex = parentIndex(elementIndex);
+ swap(elementIndex, parentIndex);
+ elementIndex = parentIndex;
+ }
+ }
+
+ public E pop() {
+ if (isEmpty()) {
+ throw new IllegalStateException("You cannot pop from an empty heap");
+ }
+
+ E result = elementAt(0);
+
+ int lasElementIndex = elements.size() - 1;
+ swap(0, lasElementIndex);
+ elements.remove(lasElementIndex);
+
+ int elementIndex = 0;
+ while (!isLeaf(elementIndex) && !isCorrectParent(elementIndex)) {
+ int smallerChildIndex = smallerChildIndex(elementIndex);
+ swap(elementIndex, smallerChildIndex);
+ elementIndex = smallerChildIndex;
+ }
+
+ return result;
+ }
+
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ private boolean isRoot(int index) {
+ return index == 0;
+ }
+
+ private int smallerChildIndex(int index) {
+ int leftChildIndex = leftChildIndex(index);
+ int rightChildIndex = rightChildIndex(index);
+
+ if (!isValidIndex(rightChildIndex)) {
+ return leftChildIndex;
+ }
+
+ if (elementAt(leftChildIndex).compareTo(elementAt(rightChildIndex)) < 0) {
+ return leftChildIndex;
+ }
+
+ return rightChildIndex;
+ }
+
+ private boolean isLeaf(int index) {
+ return !isValidIndex(leftChildIndex(index));
+ }
+
+ private boolean isCorrectParent(int index) {
+ return isCorrect(index, leftChildIndex(index)) && isCorrect(index, rightChildIndex(index));
+ }
+
+ private boolean isCorrectChild(int index) {
+ return isCorrect(parentIndex(index), index);
+ }
+
+ private boolean isCorrect(int parentIndex, int childIndex) {
+ if (!isValidIndex(parentIndex) || !isValidIndex(childIndex)) {
+ return true;
+ }
+
+ return elementAt(parentIndex).compareTo(elementAt(childIndex)) < 0;
+ }
+
+ private boolean isValidIndex(int index) {
+ return index < elements.size();
+ }
+
+ private void swap(int index1, int index2) {
+ E element1 = elementAt(index1);
+ E element2 = elementAt(index2);
+ elements.set(index1, element2);
+ elements.set(index2, element1);
+ }
+
+ private E elementAt(int index) {
+ return elements.get(index);
+ }
+
+ private int parentIndex(int index) {
+ return (index - 1) / 2;
+ }
+
+ private int leftChildIndex(int index) {
+ return 2 * index + 1;
+ }
+
+ private int rightChildIndex(int index) {
+ return 2 * index + 2;
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/insertionsort/InsertionSort.java b/algorithms/src/main/java/com/baeldung/algorithms/insertionsort/InsertionSort.java
new file mode 100644
index 0000000000..02dd485cf1
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/insertionsort/InsertionSort.java
@@ -0,0 +1,41 @@
+package com.baeldung.algorithms.insertionsort;
+
+public class InsertionSort {
+
+ public static void insertionSortImperative(int[] input) {
+ for (int i = 1; i < input.length; i++) {
+ int key = input[i];
+ int j = i - 1;
+ while (j >= 0 && input[j] > key) {
+ input[j + 1] = input[j];
+ j = j - 1;
+ }
+ input[j + 1] = key;
+ }
+ }
+
+ public static void insertionSortRecursive(int[] input) {
+ insertionSortRecursive(input, input.length);
+ }
+
+ private static void insertionSortRecursive(int[] input, int i) {
+ // base case
+ if (i <= 1) {
+ return;
+ }
+
+ // sort the first i - 1 elements of the array
+ insertionSortRecursive(input, i - 1);
+
+ // then find the correct position of the element at position i
+ int key = input[i - 1];
+ int j = i - 2;
+ // shifting the elements from their position by 1
+ while (j >= 0 && input[j] > key) {
+ input[j + 1] = input[j];
+ j = j - 1;
+ }
+ // inserting the key at the appropriate position
+ input[j + 1] = key;
+ }
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java b/algorithms/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java
new file mode 100644
index 0000000000..be61802705
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java
@@ -0,0 +1,127 @@
+package com.baeldung.algorithms.conversion;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.apache.commons.codec.DecoderException;
+import org.hamcrest.text.IsEqualIgnoringCase;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.algorithms.conversion.HexStringConverter;
+
+public class ByteArrayConverterUnitTest {
+
+ private HexStringConverter hexStringConverter;
+
+ @Before
+ public void setup() {
+ hexStringConverter = new HexStringConverter();
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringUsingBigIntegerToString() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ if(hexString.charAt(0) == '0') {
+ hexString = hexString.substring(1);
+ }
+ String output = hexStringConverter.encodeUsingBigIntegerToString(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringUsingBigIntegerStringFormat() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ String output = hexStringConverter.encodeUsingBigIntegerStringFormat(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldDecodeHexStringToByteArrayUsingBigInteger() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ byte[] output = hexStringConverter.decodeUsingBigInteger(hexString);
+ assertArrayEquals(bytes, output);
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringUsingCharacterConversion() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ String output = hexStringConverter.encodeHexString(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldDecodeHexStringToByteArrayUsingCharacterConversion() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ byte[] output = hexStringConverter.decodeHexString(hexString);
+ assertArrayEquals(bytes, output);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void shouldDecodeHexToByteWithInvalidHexCharacter() {
+ hexStringConverter.hexToByte("fg");
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringDataTypeConverter() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ String output = hexStringConverter.encodeUsingDataTypeConverter(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldDecodeHexStringToByteArrayUsingDataTypeConverter() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ byte[] output = hexStringConverter.decodeUsingDataTypeConverter(hexString);
+ assertArrayEquals(bytes, output);
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringUsingGuava() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ String output = hexStringConverter.encodeUsingGuava(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldDecodeHexStringToByteArrayUsingGuava() {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ byte[] output = hexStringConverter.decodeUsingGuava(hexString);
+ assertArrayEquals(bytes, output);
+ }
+
+ @Test
+ public void shouldEncodeByteArrayToHexStringUsingApacheCommons() throws DecoderException {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ String output = hexStringConverter.encodeUsingApacheCommons(bytes);
+ assertThat(output, IsEqualIgnoringCase.equalToIgnoringCase(hexString));
+ }
+
+ @Test
+ public void shouldDecodeHexStringToByteArrayUsingApacheCommons() throws DecoderException {
+ byte[] bytes = getSampleBytes();
+ String hexString = getSampleHexString();
+ byte[] output = hexStringConverter.decodeUsingApacheCommons(hexString);
+ assertArrayEquals(bytes, output);
+ }
+
+ private String getSampleHexString() {
+ return "0af50c0e2d10";
+ }
+
+ private byte[] getSampleBytes() {
+ return new byte[] { 10, -11, 12, 14, 45, 16 };
+ }
+
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java b/algorithms/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java
new file mode 100644
index 0000000000..96e4936eaf
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java
@@ -0,0 +1,36 @@
+package com.baeldung.algorithms.heapsort;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class HeapUnitTest {
+
+ @Test
+ public void givenNotEmptyHeap_whenPopCalled_thenItShouldReturnSmallestElement() {
+ // given
+ Heap heap = Heap.of(3, 5, 1, 4, 2);
+
+ // when
+ int head = heap.pop();
+
+ // then
+ assertThat(head).isEqualTo(1);
+ }
+
+ @Test
+ public void givenNotEmptyIterable_whenSortCalled_thenItShouldReturnElementsInSortedList() {
+ // given
+ List elements = Arrays.asList(3, 5, 1, 4, 2);
+
+ // when
+ List sortedElements = Heap.sort(elements);
+
+ // then
+ assertThat(sortedElements).isEqualTo(Arrays.asList(1, 2, 3, 4, 5));
+ }
+
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java b/algorithms/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java
new file mode 100644
index 0000000000..b3d7e8c534
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java
@@ -0,0 +1,25 @@
+package com.baeldung.algorithms.insertionsort;
+
+import com.baeldung.algorithms.insertionsort.InsertionSort;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+public class InsertionSortUnitTest {
+
+ @Test
+ public void givenUnsortedArray_whenInsertionSortImperative_thenSortedAsc() {
+ int[] input = {6, 2, 3, 4, 5, 1};
+ InsertionSort.insertionSortImperative(input);
+ int[] expected = {1, 2, 3, 4, 5, 6};
+ assertArrayEquals("the two arrays are not equal", expected, input);
+ }
+
+ @Test
+ public void givenUnsortedArray_whenInsertionSortRecursive_thenSortedAsc() {
+ int[] input = {6, 4, 5, 2, 3, 1};
+ InsertionSort.insertionSortRecursive(input);
+ int[] expected = {1, 2, 3, 4, 5, 6};
+ assertArrayEquals("the two arrays are not equal", expected, input);
+ }
+}
diff --git a/aws/README.md b/aws/README.md
index d23937a419..2c61928095 100644
--- a/aws/README.md
+++ b/aws/README.md
@@ -9,4 +9,4 @@
- [Integration Testing with a Local DynamoDB Instance](http://www.baeldung.com/dynamodb-local-integration-tests)
- [Using the JetS3t Java Client With Amazon S3](http://www.baeldung.com/jets3t-amazon-s3)
- [Managing Amazon SQS Queues in Java](http://www.baeldung.com/aws-queues-java)
-
+- [Guide to AWS Aurora RDS with Java](https://www.baeldung.com/aws-aurora-rds-java)
diff --git a/core-java-8/src/test/java/com/baeldung/internationalization/DateTimeFormatterUnitTest.java b/core-java-8/src/test/java/com/baeldung/internationalization/DateTimeFormatterUnitTest.java
deleted file mode 100644
index 4d95bc82e1..0000000000
--- a/core-java-8/src/test/java/com/baeldung/internationalization/DateTimeFormatterUnitTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.baeldung.internationalization;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.FormatStyle;
-import java.util.Locale;
-import java.util.TimeZone;
-
-public class DateTimeFormatterUnitTest {
-
- @Test
- public void givenDefaultUsLocaleAndDateTimeAndPattern_whenFormatWithDifferentLocales_thenGettingLocalizedDateTimes() {
- Locale.setDefault(Locale.US);
- LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
- String pattern = "dd-MMMM-yyyy HH:mm:ss.SSS";
-
- DateTimeFormatter defaultTimeFormatter = DateTimeFormatter.ofPattern(pattern);
- DateTimeFormatter plTimeFormatter = DateTimeFormatter.ofPattern(pattern, new Locale("pl", "PL"));
- DateTimeFormatter deTimeFormatter = DateTimeFormatter.ofPattern(pattern).withLocale(Locale.GERMANY);
-
- Assert.assertEquals("01-January-2018 10:15:50.000", defaultTimeFormatter.format(localDateTime));
- Assert.assertEquals("01-stycznia-2018 10:15:50.000", plTimeFormatter.format(localDateTime));
- Assert.assertEquals("01-Januar-2018 10:15:50.000", deTimeFormatter.format(localDateTime));
- }
-
- @Test
- public void givenDateTimeAndTimeZone_whenFormatWithDifferentLocales_thenGettingLocalizedZonedDateTimes() {
- Locale.setDefault(Locale.US);
- LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
- ZoneId losAngelesTimeZone = TimeZone.getTimeZone("America/Los_Angeles").toZoneId();
-
- DateTimeFormatter localizedFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
- DateTimeFormatter frLocalizedFormatter =
- DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(Locale.FRANCE);
- String formattedDateTime = localizedFormatter.format(ZonedDateTime.of(localDateTime, losAngelesTimeZone));
- String frFormattedDateTime = frLocalizedFormatter.format(ZonedDateTime.of(localDateTime, losAngelesTimeZone));
-
- Assert.assertEquals("Monday, January 1, 2018 10:15:50 AM PST", formattedDateTime);
- Assert.assertEquals("lundi 1 janvier 2018 10 h 15 PST", frFormattedDateTime);
- }
-}
diff --git a/core-java-9/README.md b/core-java-9/README.md
index bf07cfcc86..38816471aa 100644
--- a/core-java-9/README.md
+++ b/core-java-9/README.md
@@ -26,3 +26,4 @@
- [Iterate Through a Range of Dates in Java](https://www.baeldung.com/java-iterate-date-range)
- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
- [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api)
+- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api)
diff --git a/core-java-collections/README.md b/core-java-collections/README.md
index d9d768961c..aef640634e 100644
--- a/core-java-collections/README.md
+++ b/core-java-collections/README.md
@@ -52,3 +52,6 @@
- [Performance of contains() in a HashSet vs ArrayList](https://www.baeldung.com/java-hashset-arraylist-contains-performance)
- [Get the Key for a Value from a Java Map](https://www.baeldung.com/java-map-key-from-value)
- [Time Complexity of Java Collections](https://www.baeldung.com/java-collections-complexity)
+- [Sort a HashMap in Java](https://www.baeldung.com/java-hashmap-sort)
+- [Finding the Highest Value in a Java Map](https://www.baeldung.com/java-find-map-max)
+- [Operating on and Removing an Item from Stream](https://www.baeldung.com/java-use-remove-item-stream)
diff --git a/core-java-collections/pom.xml b/core-java-collections/pom.xml
index 06b79fff22..b4a6e26d13 100644
--- a/core-java-collections/pom.xml
+++ b/core-java-collections/pom.xml
@@ -1,90 +1,88 @@
-
- 4.0.0
- com.baeldung
- core-java-collections
- 0.1.0-SNAPSHOT
- jar
- core-java-collections
-
-
- com.baeldung
- parent-java
- 0.0.1-SNAPSHOT
- ../parent-java
-
-
-
-
- net.sourceforge.collections
- collections-generic
- ${collections-generic.version}
-
-
- org.apache.commons
- commons-collections4
- ${commons-collections4.version}
-
-
- com.jayway.awaitility
- awaitility
- ${avaitility.version}
- test
-
-
- org.apache.commons
- commons-lang3
- ${commons-lang3.version}
-
-
- org.eclipse.collections
- eclipse-collections
- ${eclipse.collections.version}
-
-
- org.assertj
- assertj-core
- ${assertj.version}
- test
-
-
- org.junit.platform
- junit-platform-runner
- ${junit.platform.version}
- test
-
-
- org.openjdk.jmh
- jmh-core
- ${openjdk.jmh.version}
-
-
- org.openjdk.jmh
- jmh-generator-annprocess
- ${openjdk.jmh.version}
-
-
- org.apache.commons
- commons-exec
- 1.3
-
-
- one.util
- streamex
- 0.6.5
-
-
-
-
-
-
- 1.19
- 1.2.0
- 3.5
- 4.1
- 4.01
- 1.7.0
- 3.6.1
- 7.1.0
-
-
+
+ 4.0.0
+ core-java-collections
+ 0.1.0-SNAPSHOT
+ jar
+ core-java-collections
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
+
+
+ net.sourceforge.collections
+ collections-generic
+ ${collections-generic.version}
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ com.jayway.awaitility
+ awaitility
+ ${avaitility.version}
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ org.eclipse.collections
+ eclipse-collections
+ ${eclipse.collections.version}
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+ org.junit.platform
+ junit-platform-runner
+ ${junit.platform.version}
+ test
+
+
+ org.openjdk.jmh
+ jmh-core
+ ${openjdk.jmh.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${openjdk.jmh.version}
+
+
+ org.apache.commons
+ commons-exec
+ 1.3
+
+
+
+ one.util
+ streamex
+ 0.6.5
+
+
+
+
+ 1.19
+ 1.2.0
+ 3.5
+ 4.1
+ 4.01
+ 1.7.0
+ 3.6.1
+ 7.1.0
+
+
diff --git a/core-java-collections/src/main/java/com/baeldung/convertcollectiontoarraylist/Foo.java b/core-java-collections/src/main/java/com/baeldung/convertcollectiontoarraylist/Foo.java
new file mode 100644
index 0000000000..5c9464182e
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/convertcollectiontoarraylist/Foo.java
@@ -0,0 +1,52 @@
+package com.baeldung.convertcollectiontoarraylist;
+
+/**
+ * This POJO is the element type of our collection. It has a deepCopy() method.
+ *
+ * @author chris
+ */
+public class Foo {
+
+ private int id;
+ private String name;
+ private Foo parent;
+
+ public Foo() {
+ }
+
+ public Foo(int id, String name, Foo parent) {
+ this.id = id;
+ this.name = name;
+ this.parent = parent;
+ }
+
+ 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 Foo getParent() {
+ return parent;
+ }
+
+ public void setParent(Foo parent) {
+ this.parent = parent;
+ }
+
+ public Foo deepCopy() {
+ return new Foo(
+ this.id, this.name, this.parent != null ? this.parent.deepCopy() : null);
+ }
+
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/enumset/EnumSets.java b/core-java-collections/src/main/java/com/baeldung/enumset/EnumSets.java
new file mode 100644
index 0000000000..7b93ed8737
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/enumset/EnumSets.java
@@ -0,0 +1,45 @@
+package com.baeldung.enumset;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+public class EnumSets {
+
+ public enum Color {
+ RED, YELLOW, GREEN, BLUE, BLACK, WHITE
+ }
+
+ public static void main(String[] args) {
+ EnumSet allColors = EnumSet.allOf(Color.class);
+ System.out.println(allColors);
+
+ EnumSet noColors = EnumSet.noneOf(Color.class);
+ System.out.println(noColors);
+
+ EnumSet blackAndWhite = EnumSet.of(Color.BLACK, Color.WHITE);
+ System.out.println(blackAndWhite);
+
+ EnumSet noBlackOrWhite = EnumSet.complementOf(blackAndWhite);
+ System.out.println(noBlackOrWhite);
+
+ EnumSet range = EnumSet.range(Color.YELLOW, Color.BLUE);
+ System.out.println(range);
+
+ EnumSet blackAndWhiteCopy = EnumSet.copyOf(EnumSet.of(Color.BLACK, Color.WHITE));
+ System.out.println(blackAndWhiteCopy);
+
+ List colorsList = new ArrayList<>();
+ colorsList.add(Color.RED);
+ EnumSet listCopy = EnumSet.copyOf(colorsList);
+ System.out.println(listCopy);
+
+ EnumSet set = EnumSet.noneOf(Color.class);
+ set.add(Color.RED);
+ set.add(Color.YELLOW);
+ set.contains(Color.RED);
+ set.forEach(System.out::println);
+ set.remove(Color.RED);
+ }
+
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/removal/CollectionRemoveIf.java b/core-java-collections/src/main/java/com/baeldung/removal/CollectionRemoveIf.java
new file mode 100644
index 0000000000..2f5e91596f
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/removal/CollectionRemoveIf.java
@@ -0,0 +1,19 @@
+package com.baeldung.removal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class CollectionRemoveIf {
+
+ public static void main(String args[]) {
+ Collection names = new ArrayList<>();
+ names.add("John");
+ names.add("Ana");
+ names.add("Mary");
+ names.add("Anthony");
+ names.add("Mark");
+
+ names.removeIf(e -> e.startsWith("A"));
+ System.out.println(String.join(",", names));
+ }
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/removal/Iterators.java b/core-java-collections/src/main/java/com/baeldung/removal/Iterators.java
new file mode 100644
index 0000000000..86b91b3fdc
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/removal/Iterators.java
@@ -0,0 +1,28 @@
+package com.baeldung.removal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class Iterators {
+
+ public static void main(String args[]) {
+ Collection names = new ArrayList<>();
+ names.add("John");
+ names.add("Ana");
+ names.add("Mary");
+ names.add("Anthony");
+ names.add("Mark");
+
+ Iterator i = names.iterator();
+
+ while (i.hasNext()) {
+ String e = i.next();
+ if (e.startsWith("A")) {
+ i.remove();
+ }
+ }
+
+ System.out.println(String.join(",", names));
+ }
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/removal/StreamFilterAndCollector.java b/core-java-collections/src/main/java/com/baeldung/removal/StreamFilterAndCollector.java
new file mode 100644
index 0000000000..bf6db68bae
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/removal/StreamFilterAndCollector.java
@@ -0,0 +1,23 @@
+package com.baeldung.removal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+public class StreamFilterAndCollector {
+
+ public static void main(String args[]) {
+ Collection names = new ArrayList<>();
+ names.add("John");
+ names.add("Ana");
+ names.add("Mary");
+ names.add("Anthony");
+ names.add("Mark");
+
+ Collection filteredCollection = names
+ .stream()
+ .filter(e -> !e.startsWith("A"))
+ .collect(Collectors.toList());
+ System.out.println(String.join(",", filteredCollection));
+ }
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/removal/StreamPartitioningBy.java b/core-java-collections/src/main/java/com/baeldung/removal/StreamPartitioningBy.java
new file mode 100644
index 0000000000..c77e996616
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/removal/StreamPartitioningBy.java
@@ -0,0 +1,28 @@
+package com.baeldung.removal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class StreamPartitioningBy {
+
+ public static void main(String args[]) {
+ Collection names = new ArrayList<>();
+ names.add("John");
+ names.add("Ana");
+ names.add("Mary");
+ names.add("Anthony");
+ names.add("Mark");
+
+ Map> classifiedElements = names
+ .stream()
+ .collect(Collectors.partitioningBy((String e) -> !e.startsWith("A")));
+
+ String matching = String.join(",", classifiedElements.get(Boolean.TRUE));
+ String nonMatching = String.join(",", classifiedElements.get(Boolean.FALSE));
+ System.out.println("Matching elements: " + matching);
+ System.out.println("Non matching elements: " + nonMatching);
+ }
+}
diff --git a/core-java-collections/src/main/java/com/baeldung/synchronizedcollections/application/Application.java b/core-java-collections/src/main/java/com/baeldung/synchronizedcollections/application/Application.java
new file mode 100644
index 0000000000..1840c125d0
--- /dev/null
+++ b/core-java-collections/src/main/java/com/baeldung/synchronizedcollections/application/Application.java
@@ -0,0 +1,18 @@
+package com.baeldung.synchronizedcollections.application;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+public class Application {
+
+ private static final Logger LOGGER = Logger.getLogger(Application.class.getName());
+
+ public static void main(String[] args) throws InterruptedException {
+ List syncCollection = Collections.synchronizedList(Arrays.asList(1, 2, 3, 4, 5, 6));
+ synchronized (syncCollection) {
+ syncCollection.forEach((e) -> {LOGGER.info(e.toString());});
+ }
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java b/core-java-collections/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java
new file mode 100644
index 0000000000..5be4121bc7
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java
@@ -0,0 +1,148 @@
+package com.baeldung.convertcollectiontoarraylist;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import static java.util.stream.Collectors.toCollection;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author chris
+ */
+public class FooUnitTest {
+ private static Collection srcCollection = new HashSet<>();
+
+ public FooUnitTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ int i = 0;
+ Foo john = new Foo(i++, "John", null);
+ Foo mary = new Foo(i++, "Mary", null);
+ Foo sam = new Foo(i++, "Sam", john);
+ Foo alice = new Foo(i++, "Alice", john);
+ Foo buffy = new Foo(i++, "Buffy", sam);
+ srcCollection.add(john);
+ srcCollection.add(mary);
+ srcCollection.add(sam);
+ srcCollection.add(alice);
+ srcCollection.add(buffy);
+
+ // make sure the collection isn't sorted accidentally
+ assertFalse("Oops: source collection is already sorted!", isSorted(srcCollection));
+ }
+
+ /**
+ * Section 3. Using the ArrayList Constructor
+ */
+ @Test
+ public void whenUsingConstructor_thenVerifyShallowCopy() {
+ ArrayList newList = new ArrayList<>(srcCollection);
+ verifyShallowCopy(srcCollection, newList);
+ }
+
+ /**
+ * Section 4. Using the Streams API
+ */
+ @Test
+ public void whenUsingStream_thenVerifyShallowCopy() {
+ ArrayList newList = srcCollection.stream().collect(toCollection(ArrayList::new));
+
+ verifyShallowCopy(srcCollection, newList);
+ }
+
+ /**
+ * Section 5. Deep Copy
+ */
+ @Test
+ public void whenUsingDeepCopy_thenVerifyDeepCopy() {
+ ArrayList newList = srcCollection.stream()
+ .map(foo -> foo.deepCopy())
+ .collect(toCollection(ArrayList::new));
+
+ verifyDeepCopy(srcCollection, newList);
+ }
+
+ /**
+ * Section 6. Controlling the List Order
+ */
+ @Test
+ public void whenUsingSortedStream_thenVerifySortOrder() {
+ ArrayList newList = srcCollection.stream()
+ .sorted(Comparator.comparing(Foo::getName))
+ .collect(toCollection(ArrayList::new));
+
+ assertTrue("ArrayList is not sorted by name", isSorted(newList));
+ }
+
+ /**
+ * Verify that the contents of the two collections are the same
+ * @param a
+ * @param b
+ */
+ private void verifyShallowCopy(Collection a, Collection b) {
+ assertEquals("Collections have different lengths", a.size(), b.size());
+ Iterator iterA = a.iterator();
+ Iterator iterB = b.iterator();
+ while (iterA.hasNext()) {
+ // use '==' to test instance identity
+ assertTrue("Foo instances differ!", iterA.next() == iterB.next());
+ }
+ }
+
+ /**
+ * Verify that the contents of the two collections are the same
+ * @param a
+ * @param b
+ */
+ private void verifyDeepCopy(Collection a, Collection b) {
+ assertEquals("Collections have different lengths", a.size(), b.size());
+ Iterator iterA = a.iterator();
+ Iterator iterB = b.iterator();
+ while (iterA.hasNext()) {
+ Foo nextA = iterA.next();
+ Foo nextB = iterB.next();
+ // should not be same instance
+ assertFalse("Foo instances are the same!", nextA == nextB);
+ // but should have same content
+ assertFalse("Foo instances have different content!", fooDiff(nextA, nextB));
+ }
+ }
+
+ /**
+ * Return true if the contents of a and b differ. Test parent recursively
+ * @param a
+ * @param b
+ * @return False if the two items are the same
+ */
+ private boolean fooDiff(Foo a, Foo b) {
+ if (a != null && b != null) {
+ return a.getId() != b.getId()
+ || !a.getName().equals(b.getName())
+ || fooDiff(a.getParent(), b.getParent());
+ }
+ return !(a == null && b == null);
+ }
+
+ /**
+ * @param c collection of Foo
+ * @return true if the collection is sorted by name
+ */
+ private static boolean isSorted(Collection c) {
+ String prevName = null;
+ for (Foo foo : c) {
+ if (prevName == null || foo.getName().compareTo(prevName) > 0) {
+ prevName = foo.getName();
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/findItems/FindItemsBasedOnOtherStreamUnitTest.java b/core-java-collections/src/test/java/com/baeldung/findItems/FindItemsBasedOnOtherStreamUnitTest.java
new file mode 100644
index 0000000000..326ea9fbe4
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/findItems/FindItemsBasedOnOtherStreamUnitTest.java
@@ -0,0 +1,89 @@
+package com.baeldung.findItems;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+public class FindItemsBasedOnOtherStreamUnitTest {
+
+ private List employeeList = new ArrayList();
+
+ private List departmentList = new ArrayList();
+
+ @Test
+ public void givenDepartmentList_thenEmployeeListIsFilteredCorrectly() {
+ Integer expectedId = 1002;
+
+ populate(employeeList, departmentList);
+
+ List filteredList = employeeList.stream()
+ .filter(empl -> departmentList.stream()
+ .anyMatch(dept -> dept.getDepartment()
+ .equals("sales") && empl.getEmployeeId()
+ .equals(dept.getEmployeeId())))
+ .collect(Collectors.toList());
+
+ assertEquals(expectedId, filteredList.get(0)
+ .getEmployeeId());
+ }
+
+ private void populate(List EmplList, List deptList) {
+ Employee employee1 = new Employee(1001, "empl1");
+ Employee employee2 = new Employee(1002, "empl2");
+ Employee employee3 = new Employee(1003, "empl3");
+
+ Collections.addAll(EmplList, employee1, employee2, employee3);
+
+ Department department1 = new Department(1002, "sales");
+ Department department2 = new Department(1003, "marketing");
+ Department department3 = new Department(1004, "sales");
+
+ Collections.addAll(deptList, department1, department2, department3);
+ }
+}
+
+class Employee {
+ private Integer employeeId;
+ private String employeeName;
+
+ Employee(Integer employeeId, String employeeName) {
+ super();
+ this.employeeId = employeeId;
+ this.employeeName = employeeName;
+ }
+
+ Integer getEmployeeId() {
+ return employeeId;
+ }
+
+ public String getEmployeeName() {
+ return employeeName;
+ }
+
+}
+
+class Department {
+ private Integer employeeId;
+ private String department;
+
+ Department(Integer employeeId, String department) {
+ super();
+ this.employeeId = employeeId;
+ this.department = department;
+ }
+
+ Integer getEmployeeId() {
+ return employeeId;
+ }
+
+ String getDepartment() {
+ return department;
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckTest.java b/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckTest.java
deleted file mode 100644
index 024b2973d2..0000000000
--- a/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.baeldung.java.map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.collections4.MultiMap;
-import org.apache.commons.collections4.MultiMapUtils;
-import org.apache.commons.collections4.MultiValuedMap;
-import org.apache.commons.collections4.map.MultiValueMap;
-import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
-import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.TreeMultimap;
-
-
-public class KeyCheckTest {
-
- @Test
- public void whenKeyIsPresent_thenContainsKeyReturnsTrue() {
- Map map = Collections.singletonMap("key", "value");
-
- assertTrue(map.containsKey("key"));
- assertFalse(map.containsKey("missing"));
- }
-
- @Test
- public void whenKeyHasNullValue_thenGetStillWorks() {
- Map map = Collections.singletonMap("nothing", null);
-
- assertTrue(map.containsKey("nothing"));
- assertNull(map.get("nothing"));
- }
-}
\ No newline at end of file
diff --git a/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckUnitTest.java b/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckUnitTest.java
new file mode 100644
index 0000000000..2c97a97690
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/java/map/KeyCheckUnitTest.java
@@ -0,0 +1,29 @@
+package com.baeldung.java.map;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class KeyCheckUnitTest {
+
+ @Test
+ public void whenKeyIsPresent_thenContainsKeyReturnsTrue() {
+ Map map = Collections.singletonMap("key", "value");
+
+ assertTrue(map.containsKey("key"));
+ assertFalse(map.containsKey("missing"));
+ }
+
+ @Test
+ public void whenKeyHasNullValue_thenGetStillWorks() {
+ Map map = Collections.singletonMap("nothing", null);
+
+ assertTrue(map.containsKey("nothing"));
+ assertNull(map.get("nothing"));
+ }
+}
\ No newline at end of file
diff --git a/core-java-collections/src/test/java/com/baeldung/removal/RemovalUnitTest.java b/core-java-collections/src/test/java/com/baeldung/removal/RemovalUnitTest.java
new file mode 100644
index 0000000000..1b379f32de
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/removal/RemovalUnitTest.java
@@ -0,0 +1,77 @@
+package com.baeldung.removal;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class RemovalUnitTest {
+
+ Collection names;
+ Collection expected;
+ Collection removed;
+
+ @Before
+ public void setupTestData() {
+ names = new ArrayList<>();
+ expected = new ArrayList<>();
+ removed = new ArrayList<>();
+
+ names.add("John");
+ names.add("Ana");
+ names.add("Mary");
+ names.add("Anthony");
+ names.add("Mark");
+
+ expected.add("John");
+ expected.add("Mary");
+ expected.add("Mark");
+
+ removed.add("Ana");
+ removed.add("Anthony");
+ }
+
+ @Test
+ public void givenCollectionOfNames_whenUsingIteratorToRemoveAllNamesStartingWithLetterA_finalListShouldContainNoNamesStartingWithLetterA() {
+ Iterator i = names.iterator();
+
+ while (i.hasNext()) {
+ String e = i.next();
+ if (e.startsWith("A")) {
+ i.remove();
+ }
+ }
+
+ assertThat(names, is(expected));
+ }
+
+ @Test
+ public void givenCollectionOfNames_whenUsingRemoveIfToRemoveAllNamesStartingWithLetterA_finalListShouldContainNoNamesStartingWithLetterA() {
+ names.removeIf(e -> e.startsWith("A"));
+ assertThat(names, is(expected));
+ }
+
+ @Test
+ public void givenCollectionOfNames_whenUsingStreamToFilterAllNamesStartingWithLetterA_finalListShouldContainNoNamesStartingWithLetterA() {
+ Collection filteredCollection = names
+ .stream()
+ .filter(e -> !e.startsWith("A"))
+ .collect(Collectors.toList());
+ assertThat(filteredCollection, is(expected));
+ }
+
+ @Test
+ public void givenCollectionOfNames_whenUsingStreamAndPartitioningByToFindNamesThatStartWithLetterA_shouldFind3MatchingAnd2NonMatching() {
+ Map> classifiedElements = names
+ .stream()
+ .collect(Collectors.partitioningBy((String e) -> !e.startsWith("A")));
+
+ assertThat(classifiedElements.get(Boolean.TRUE), is(expected));
+ assertThat(classifiedElements.get(Boolean.FALSE), is(removed));
+ }
+
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedCollectionUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedCollectionUnitTest.java
new file mode 100644
index 0000000000..84feeb6eaa
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedCollectionUnitTest.java
@@ -0,0 +1,28 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+
+public class SynchronizedCollectionUnitTest {
+
+ @Test
+ public void givenSynchronizedCollection_whenTwoThreadsAddElements_thenCorrectCollectionSize() throws InterruptedException {
+ Collection syncCollection = Collections.synchronizedCollection(new ArrayList<>());
+
+ Runnable listOperations = () -> {
+ syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
+ };
+ Thread thread1 = new Thread(listOperations);
+ Thread thread2 = new Thread(listOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncCollection.size()).isEqualTo(12);
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedListUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedListUnitTest.java
new file mode 100644
index 0000000000..68fc3becd4
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedListUnitTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import static org.assertj.core.api.Assertions.*;
+
+public class SynchronizedListUnitTest {
+
+ @Test
+ public void givenSynchronizedList_whenTwoThreadsAddElements_thenCorrectListSize() throws InterruptedException {
+ List syncList = Collections.synchronizedList(new ArrayList<>());
+
+ Runnable listOperations = () -> {
+ syncList.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
+ };
+ Thread thread1 = new Thread(listOperations);
+ Thread thread2 = new Thread(listOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncList.size()).isEqualTo(12);
+ }
+
+ @Test
+ public void givenStringList_whenTwoThreadsIterateOnSynchronizedList_thenCorrectResult() throws InterruptedException {
+ List syncCollection = Collections.synchronizedList(Arrays.asList("a", "b", "c"));
+ List uppercasedCollection = new ArrayList<>();
+
+ Runnable listOperations = () -> {
+ synchronized (syncCollection) {
+ syncCollection.forEach((e) -> {
+ uppercasedCollection.add(e.toUpperCase());
+ });
+ }
+ };
+
+ Thread thread1 = new Thread(listOperations);
+ Thread thread2 = new Thread(listOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(uppercasedCollection.get(0)).isEqualTo("A");
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedMapUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedMapUnitTest.java
new file mode 100644
index 0000000000..abfb866e9c
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedMapUnitTest.java
@@ -0,0 +1,30 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import static org.assertj.core.api.Assertions.*;
+
+public class SynchronizedMapUnitTest {
+
+ @Test
+ public void givenSynchronizedMap_whenTwoThreadsAddElements_thenCorrectMapSize() throws InterruptedException {
+ Map syncMap = Collections.synchronizedMap(new HashMap<>());
+
+ Runnable mapOperations = () -> {
+ syncMap.put(1, "one");
+ syncMap.put(2, "two");
+ syncMap.put(3, "three");
+
+ };
+ Thread thread1 = new Thread(mapOperations);
+ Thread thread2 = new Thread(mapOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncMap.size()).isEqualTo(3);
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSetUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSetUnitTest.java
new file mode 100644
index 0000000000..58a33b207d
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSetUnitTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import static org.assertj.core.api.Assertions.*;
+
+public class SynchronizedSetUnitTest {
+
+ @Test
+ public void givenSynchronizedSet_whenTwoThreadsAddElements_thenCorrectSetSize() throws InterruptedException {
+ Set syncSet = Collections.synchronizedSet(new HashSet<>());
+
+ Runnable setOperations = () -> {syncSet.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));};
+ Thread thread1 = new Thread(setOperations);
+ Thread thread2 = new Thread(setOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncSet.size()).isEqualTo(6);
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedMapUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedMapUnitTest.java
new file mode 100644
index 0000000000..4b0ed6d8c8
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedMapUnitTest.java
@@ -0,0 +1,29 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+
+public class SynchronizedSortedMapUnitTest {
+
+ @Test
+ public void givenSynchronizedSorteMap_whenTwoThreadsAddElements_thenCorrectSortedMapSize() throws InterruptedException {
+ Map syncSortedMap = Collections.synchronizedSortedMap(new TreeMap<>());
+
+ Runnable sortedMapOperations = () -> {
+ syncSortedMap.put(1, "One");
+ syncSortedMap.put(2, "Two");
+ syncSortedMap.put(3, "Three");
+ };
+ Thread thread1 = new Thread(sortedMapOperations);
+ Thread thread2 = new Thread(sortedMapOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncSortedMap.size()).isEqualTo(3);
+ }
+}
diff --git a/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedSetUnitTest.java b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedSetUnitTest.java
new file mode 100644
index 0000000000..0e26c6eb1c
--- /dev/null
+++ b/core-java-collections/src/test/java/com/baeldung/synchronizedcollections/test/SynchronizedSortedSetUnitTest.java
@@ -0,0 +1,28 @@
+package com.baeldung.synchronizedcollections.test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+
+public class SynchronizedSortedSetUnitTest {
+
+ @Test
+ public void givenSynchronizedSortedSet_whenTwoThreadsAddElements_thenCorrectSortedSetSize() throws InterruptedException {
+ SortedSet syncSortedSet = Collections.synchronizedSortedSet(new TreeSet<>());
+
+ Runnable sortedSetOperations = () -> {syncSortedSet.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));};
+ sortedSetOperations.run();
+ sortedSetOperations.run();
+ Thread thread1 = new Thread(sortedSetOperations);
+ Thread thread2 = new Thread(sortedSetOperations);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ assertThat(syncSortedSet.size()).isEqualTo(6);
+ }
+}
diff --git a/core-java-concurrency/README.md b/core-java-concurrency/README.md
index d775d24dff..eeb9a83748 100644
--- a/core-java-concurrency/README.md
+++ b/core-java-concurrency/README.md
@@ -29,3 +29,4 @@
- [A Custom Spring SecurityConfigurer](http://www.baeldung.com/spring-security-custom-configurer)
- [Life Cycle of a Thread in Java](http://www.baeldung.com/java-thread-lifecycle)
- [Runnable vs. Callable in Java](http://www.baeldung.com/java-runnable-callable)
+- [Brief Introduction to Java Thread.yield()](https://www.baeldung.com/java-thread-yield)
diff --git a/core-java-concurrency/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java b/core-java-concurrency/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java
index 45d2ec68e4..d9cf8ae019 100644
--- a/core-java-concurrency/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java
+++ b/core-java-concurrency/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java
@@ -184,5 +184,25 @@ public class CompletableFutureLongRunningUnitTest {
assertEquals("Hello World", future.get());
}
+
+ @Test
+ public void whenPassingTransformation_thenFunctionExecutionWithThenApply() throws InterruptedException, ExecutionException {
+ CompletableFuture finalResult = compute().thenApply(s -> s + 1);
+ assertTrue(finalResult.get() == 11);
+ }
+
+ @Test
+ public void whenPassingPreviousStage_thenFunctionExecutionWithThenCompose() throws InterruptedException, ExecutionException {
+ CompletableFuture finalResult = compute().thenCompose(this::computeAnother);
+ assertTrue(finalResult.get() == 20);
+ }
+
+ public CompletableFuture compute(){
+ return CompletableFuture.supplyAsync(() -> 10);
+ }
+
+ public CompletableFuture computeAnother(Integer i){
+ return CompletableFuture.supplyAsync(() -> 10 + i);
+ }
}
\ No newline at end of file
diff --git a/core-java-io/src/main/resources/zipTest/test1.txt b/core-java-io/src/main/resources/zipTest/test1.txt
new file mode 100644
index 0000000000..e88ded96ab
--- /dev/null
+++ b/core-java-io/src/main/resources/zipTest/test1.txt
@@ -0,0 +1 @@
+Test1
\ No newline at end of file
diff --git a/core-java-io/src/main/resources/zipTest/test2.txt b/core-java-io/src/main/resources/zipTest/test2.txt
new file mode 100644
index 0000000000..da8f209890
--- /dev/null
+++ b/core-java-io/src/main/resources/zipTest/test2.txt
@@ -0,0 +1 @@
+Test2
\ No newline at end of file
diff --git a/core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesTest.java b/core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesUnitTest.java
similarity index 98%
rename from core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesTest.java
rename to core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesUnitTest.java
index 4ae1ce9aa7..aa949259a0 100644
--- a/core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesTest.java
+++ b/core-java-io/src/test/java/com/baeldung/stream/OutputStreamExamplesUnitTest.java
@@ -8,7 +8,7 @@ import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
-public class OutputStreamExamplesTest {
+public class OutputStreamExamplesUnitTest {
StringBuilder filePath = new StringBuilder();
diff --git a/core-java/README.md b/core-java/README.md
index 65263e4d8a..8537b4e0d0 100644
--- a/core-java/README.md
+++ b/core-java/README.md
@@ -151,3 +151,9 @@
- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string)
- [Synthetic Constructs in Java](https://www.baeldung.com/java-synthetic)
- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root)
+- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string)
+- [Different Ways to Capture Java Heap Dumps](https://www.baeldung.com/java-heap-dump-capture)
+- [How to Separate Double into Integer and Decimal Parts](https://www.baeldung.com/java-separate-double-into-integer-decimal-parts)
+- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset)
+- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing)
+- [Java Switch Statement](https://www.baeldung.com/java-switch)
diff --git a/core-java/src/main/java/com/baeldung/array/ArrayReferenceGuide.java b/core-java/src/main/java/com/baeldung/array/ArrayReferenceGuide.java
new file mode 100644
index 0000000000..7d7dec85b0
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/array/ArrayReferenceGuide.java
@@ -0,0 +1,159 @@
+package com.baeldung.array;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class ArrayReferenceGuide {
+
+ public static void main(String[] args) {
+ declaration();
+
+ initialization();
+
+ access();
+
+ iterating();
+
+ varargs();
+
+ transformIntoList();
+
+ transformIntoStream();
+
+ sort();
+
+ search();
+
+ merge();
+ }
+
+ private static void declaration() {
+ int[] anArray;
+ int anotherArray[];
+ }
+
+ private static void initialization() {
+ int[] anArray = new int[10];
+ anArray[0] = 10;
+ anArray[5] = 4;
+
+ int[] anotherArray = new int[] {1, 2, 3, 4, 5};
+ }
+
+ private static void access() {
+ int[] anArray = new int[10];
+ anArray[0] = 10;
+ anArray[5] = 4;
+
+ System.out.println(anArray[0]);
+ }
+
+ private static void iterating() {
+ int[] anArray = new int[] {1, 2, 3, 4, 5};
+ for (int i = 0; i < anArray.length; i++) {
+ System.out.println(anArray[i]);
+ }
+
+ for (int element : anArray) {
+ System.out.println(element);
+ }
+ }
+
+ private static void varargs() {
+ String[] groceries = new String[] {"Milk", "Tomato", "Chips"};
+ varargMethod(groceries);
+ varargMethod("Milk", "Tomato", "Chips");
+ }
+
+ private static void varargMethod(String... varargs) {
+ for (String element : varargs) {
+ System.out.println(element);
+ }
+ }
+
+ private static void transformIntoList() {
+ Integer[] anArray = new Integer[] {1, 2, 3, 4, 5};
+
+ // Naïve implementation
+ List aList = new ArrayList<>(); // We create an empty list
+ for (int element : anArray) {
+ // We iterate over array's elements and add them to the list
+ aList.add(element);
+ }
+
+ // Pretty implementation
+ aList = Arrays.asList(anArray);
+
+ // Drawbacks
+ try {
+ aList.remove(0);
+ } catch (UnsupportedOperationException e) {
+ System.out.println(e.getMessage());
+ }
+
+ try {
+ aList.add(6);
+ } catch (UnsupportedOperationException e) {
+ System.out.println(e.getMessage());
+ }
+
+ int[] anotherArray = new int[] {1, 2, 3, 4, 5};
+// List anotherList = Arrays.asList(anotherArray);
+ }
+
+ private static void transformIntoStream() {
+ int[] anArray = new int[] {1, 2, 3, 4, 5};
+ IntStream aStream = Arrays.stream(anArray);
+
+ Integer[] anotherArray = new Integer[] {1, 2, 3, 4, 5};
+ Stream anotherStream = Arrays.stream(anotherArray, 2, 4);
+ }
+
+ private static void sort() {
+ int[] anArray = new int[] {5, 2, 1, 4, 8};
+ Arrays.sort(anArray); // anArray is now {1, 2, 4, 5, 8}
+
+ Integer[] anotherArray = new Integer[] {5, 2, 1, 4, 8};
+ Arrays.sort(anotherArray); // anArray is now {1, 2, 4, 5, 8}
+
+ String[] yetAnotherArray = new String[] {"A", "E", "Z", "B", "C"};
+ Arrays.sort(yetAnotherArray, 1, 3, Comparator.comparing(String::toString).reversed()); // yetAnotherArray is now {"A", "Z", "E", "B", "C"}
+ }
+
+ private static void search() {
+ int[] anArray = new int[] {5, 2, 1, 4, 8};
+ for (int i = 0; i < anArray.length; i++) {
+ if (anArray[i] == 4) {
+ System.out.println("Found at index " + i);
+ break;
+ }
+ }
+
+ Arrays.sort(anArray);
+ int index = Arrays.binarySearch(anArray, 4);
+ System.out.println("Found at index " + index);
+ }
+
+ private static void merge() {
+ int[] anArray = new int[] {5, 2, 1, 4, 8};
+ int[] anotherArray = new int[] {10, 4, 9, 11, 2};
+
+ int[] resultArray = new int[anArray.length + anotherArray.length];
+ for (int i = 0; i < resultArray.length; i++) {
+ resultArray[i] = (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]);
+ }
+ for (int element : resultArray) {
+ System.out.println(element);
+ }
+
+ Arrays.setAll(resultArray, i -> (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]));
+ for (int element : resultArray) {
+ System.out.println(element);
+ }
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java
index c44e863776..532adce1ab 100644
--- a/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java
+++ b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java
@@ -1,11 +1,14 @@
package com.baeldung.classloader;
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
public class CustomClassLoader extends ClassLoader {
-
- public Class getClass(String name) throws ClassNotFoundException {
+ @Override
+ public Class findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
diff --git a/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderUnitTest.java b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderUnitTest.java
index ec35885b84..cabf9f7bdb 100644
--- a/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderUnitTest.java
+++ b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderUnitTest.java
@@ -11,7 +11,7 @@ public class CustomClassLoaderUnitTest {
public void customLoader() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
CustomClassLoader customClassLoader = new CustomClassLoader();
- Class> c = customClassLoader.getClass(PrintClassLoader.class.getName());
+ Class> c = customClassLoader.findClass(PrintClassLoader.class.getName());
Object ob = c.newInstance();
diff --git a/core-java/src/test/java/com/baeldung/modulo/ModuloUnitTest.java b/core-java/src/test/java/com/baeldung/modulo/ModuloUnitTest.java
new file mode 100644
index 0000000000..8b3685adf3
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/modulo/ModuloUnitTest.java
@@ -0,0 +1,54 @@
+package com.baeldung.modulo;
+
+import org.junit.Test;
+import static org.assertj.core.api.Java6Assertions.*;
+
+public class ModuloUnitTest {
+
+ @Test
+ public void whenIntegerDivision_thenLosesRemainder(){
+ assertThat(11 / 4).isEqualTo(2);
+ }
+
+ @Test
+ public void whenDoubleDivision_thenKeepsRemainder(){
+ assertThat(11 / 4.0).isEqualTo(2.75);
+ }
+
+ @Test
+ public void whenModulo_thenReturnsRemainder(){
+ assertThat(11 % 4).isEqualTo(3);
+ }
+
+ @Test(expected = ArithmeticException.class)
+ public void whenDivisionByZero_thenArithmeticException(){
+ double result = 1 / 0;
+ }
+
+ @Test(expected = ArithmeticException.class)
+ public void whenModuloByZero_thenArithmeticException(){
+ double result = 1 % 0;
+ }
+
+ @Test
+ public void whenDivisorIsOddAndModulusIs2_thenResultIs1(){
+ assertThat(3 % 2).isEqualTo(1);
+ }
+
+ @Test
+ public void whenDivisorIsEvenAndModulusIs2_thenResultIs0(){
+ assertThat(4 % 2).isEqualTo(0);
+ }
+
+ @Test
+ public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds(){
+ int QUEUE_CAPACITY= 10;
+ int[] circularQueue = new int[QUEUE_CAPACITY];
+ int itemsInserted = 0;
+ for (int value = 0; value < 1000; value++) {
+ int writeIndex = ++itemsInserted % QUEUE_CAPACITY;
+ circularQueue[writeIndex] = value;
+ }
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java b/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java
index 388bceef49..286dffb56a 100644
--- a/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java
+++ b/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java
@@ -1,11 +1,11 @@
package com.baeldung.nth.root.calculator;
+import static org.junit.Assert.assertEquals;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static org.junit.Assert.assertEquals;
+import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class NthRootCalculatorUnitTest {
diff --git a/core-kotlin/README.md b/core-kotlin/README.md
index 7d8d5213d1..523f5b6e78 100644
--- a/core-kotlin/README.md
+++ b/core-kotlin/README.md
@@ -37,3 +37,5 @@
- [Kotlin with Ktor](https://www.baeldung.com/kotlin-ktor)
- [Fuel HTTP Library with Kotlin](https://www.baeldung.com/kotlin-fuel)
- [Introduction to Kovenant Library for Kotlin](https://www.baeldung.com/kotlin-kovenant)
+- [Converting Kotlin Data Class from JSON using GSON](https://www.baeldung.com/kotlin-json-convert-data-class)
+- [Concatenate Strings in Kotlin](https://www.baeldung.com/kotlin-concatenate-strings)
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Main.kt b/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Main.kt
new file mode 100644
index 0000000000..4fd8aa27c7
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Main.kt
@@ -0,0 +1,19 @@
+package com.baeldung.datastructures
+
+/**
+ * Example of how to use the {@link Node} class.
+ *
+ */
+fun main(args: Array) {
+ val tree = Node(4)
+ val keys = arrayOf(8, 15, 21, 3, 7, 2, 5, 10, 2, 3, 4, 6, 11)
+ for (key in keys) {
+ tree.insert(key)
+ }
+ val node = tree.find(4)!!
+ println("Node with value ${node.key} [left = ${node.left?.key}, right = ${node.right?.key}]")
+ println("Delete node with key = 3")
+ node.delete(3)
+ print("Tree content after the node elimination: ")
+ println(tree.visit().joinToString { it.toString() })
+}
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Node.kt b/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Node.kt
new file mode 100644
index 0000000000..b81afe1e4c
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/datastructures/Node.kt
@@ -0,0 +1,167 @@
+package com.baeldung.datastructures
+
+/**
+ * An ADT for a binary search tree.
+ * Note that this data type is neither immutable nor thread safe.
+ */
+class Node(
+ var key: Int,
+ var left: Node? = null,
+ var right: Node? = null) {
+
+ /**
+ * Return a node with given value. If no such node exists, return null.
+ * @param value
+ */
+ fun find(value: Int): Node? = when {
+ this.key > value -> left?.find(value)
+ this.key < value -> right?.find(value)
+ else -> this
+
+ }
+
+ /**
+ * Insert a given value into the tree.
+ * After insertion, the tree should contain a node with the given value.
+ * If the tree already contains the given value, nothing is performed.
+ * @param value
+ */
+ fun insert(value: Int) {
+ if (value > this.key) {
+ if (this.right == null) {
+ this.right = Node(value)
+ } else {
+ this.right?.insert(value)
+ }
+ } else if (value < this.key) {
+ if (this.left == null) {
+ this.left = Node(value)
+ } else {
+ this.left?.insert(value)
+ }
+ }
+ }
+
+ /**
+ * Delete the value from the given tree. If the tree does not contain the value, the tree remains unchanged.
+ * @param value
+ */
+ fun delete(value: Int) {
+ when {
+ value > key -> scan(value, this.right, this)
+ value < key -> scan(value, this.left, this)
+ else -> removeNode(this, null)
+ }
+ }
+
+ /**
+ * Scan the tree in the search of the given value.
+ * @param value
+ * @param node sub-tree that potentially might contain the sought value
+ * @param parent node's parent
+ */
+ private fun scan(value: Int, node: Node?, parent: Node?) {
+ if (node == null) {
+ System.out.println("value " + value
+ + " seems not present in the tree.")
+ return
+ }
+ when {
+ value > node.key -> scan(value, node.right, node)
+ value < node.key -> scan(value, node.left, node)
+ value == node.key -> removeNode(node, parent)
+ }
+
+ }
+
+ /**
+ * Remove the node.
+ *
+ * Removal process depends on how many children the node has.
+ *
+ * @param node node that is to be removed
+ * @param parent parent of the node to be removed
+ */
+ private fun removeNode(node: Node, parent: Node?) {
+ node.left?.let { leftChild ->
+ run {
+ node.right?.let {
+ removeTwoChildNode(node)
+ } ?: removeSingleChildNode(node, leftChild)
+ }
+ } ?: run {
+ node.right?.let { rightChild -> removeSingleChildNode(node, rightChild) } ?: removeNoChildNode(node, parent)
+ }
+
+
+ }
+
+ /**
+ * Remove the node without children.
+ * @param node
+ * @param parent
+ */
+ private fun removeNoChildNode(node: Node, parent: Node?) {
+ parent?.let { p ->
+ if (node == p.left) {
+ p.left = null
+ } else if (node == p.right) {
+ p.right = null
+ }
+ } ?: throw IllegalStateException(
+ "Can not remove the root node without child nodes")
+
+ }
+
+ /**
+ * Remove a node that has two children.
+ *
+ * The process of elimination is to find the biggest key in the left sub-tree and replace the key of the
+ * node that is to be deleted with that key.
+ */
+ private fun removeTwoChildNode(node: Node) {
+ val leftChild = node.left!!
+ leftChild.right?.let {
+ val maxParent = findParentOfMaxChild(leftChild)
+ maxParent.right?.let {
+ node.key = it.key
+ maxParent.right = null
+ } ?: throw IllegalStateException("Node with max child must have the right child!")
+
+ } ?: run {
+ node.key = leftChild.key
+ node.left = leftChild.left
+ }
+
+ }
+
+ /**
+ * Return a node whose right child contains the biggest value in the given sub-tree.
+ * Assume that the node n has a non-null right child.
+ *
+ * @param n
+ */
+ private fun findParentOfMaxChild(n: Node): Node {
+ return n.right?.let { r -> r.right?.let { findParentOfMaxChild(r) } ?: n }
+ ?: throw IllegalArgumentException("Right child must be non-null")
+
+ }
+
+ /**
+ * Remove a parent that has only one child.
+ * Removal is effectively is just coping the data from the child parent to the parent parent.
+ * @param parent Node to be deleted. Assume that it has just one child
+ * @param child Assume it is a child of the parent
+ */
+ private fun removeSingleChildNode(parent: Node, child: Node) {
+ parent.key = child.key
+ parent.left = child.left
+ parent.right = child.right
+ }
+
+ fun visit(): Array {
+ val a = left?.visit() ?: emptyArray()
+ val b = right?.visit() ?: emptyArray()
+ return a + arrayOf(key) + b
+ }
+}
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/interfaces/ConflictingInterfaces.kt b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/ConflictingInterfaces.kt
new file mode 100644
index 0000000000..630afbdae7
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/ConflictingInterfaces.kt
@@ -0,0 +1,23 @@
+package com.baeldung.interfaces
+
+interface BaseInterface {
+ fun someMethod(): String
+}
+
+interface FirstChildInterface : BaseInterface {
+ override fun someMethod(): String {
+ return("Hello, from someMethod in FirstChildInterface")
+ }
+}
+
+interface SecondChildInterface : BaseInterface {
+ override fun someMethod(): String {
+ return("Hello, from someMethod in SecondChildInterface")
+ }
+}
+
+class ChildClass : FirstChildInterface, SecondChildInterface {
+ override fun someMethod(): String {
+ return super.someMethod()
+ }
+}
\ No newline at end of file
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/interfaces/InterfaceDelegation.kt b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/InterfaceDelegation.kt
new file mode 100644
index 0000000000..591fde0689
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/InterfaceDelegation.kt
@@ -0,0 +1,13 @@
+package com.baeldung.interfaces
+
+interface MyInterface {
+ fun someMethod(): String
+}
+
+class MyClass() : MyInterface {
+ override fun someMethod(): String {
+ return("Hello, World!")
+ }
+}
+
+class MyDerivedClass(myInterface: MyInterface) : MyInterface by myInterface
\ No newline at end of file
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/interfaces/MultipleInterfaces.kt b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/MultipleInterfaces.kt
new file mode 100644
index 0000000000..105a85cbb3
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/MultipleInterfaces.kt
@@ -0,0 +1,29 @@
+package com.baeldung.interfaces
+
+interface FirstInterface {
+ fun someMethod(): String
+
+ fun anotherMethod(): String {
+ return("Hello, from anotherMethod in FirstInterface")
+ }
+}
+
+interface SecondInterface {
+ fun someMethod(): String {
+ return("Hello, from someMethod in SecondInterface")
+ }
+
+ fun anotherMethod(): String {
+ return("Hello, from anotherMethod in SecondInterface")
+ }
+}
+
+class SomeClass: FirstInterface, SecondInterface {
+ override fun someMethod(): String {
+ return("Hello, from someMethod in SomeClass")
+ }
+
+ override fun anotherMethod(): String {
+ return("Hello, from anotherMethod in SomeClass")
+ }
+}
\ No newline at end of file
diff --git a/core-kotlin/src/main/kotlin/com/baeldung/interfaces/SimpleInterface.kt b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/SimpleInterface.kt
new file mode 100644
index 0000000000..0758549dde
--- /dev/null
+++ b/core-kotlin/src/main/kotlin/com/baeldung/interfaces/SimpleInterface.kt
@@ -0,0 +1,24 @@
+package com.baeldung.interfaces
+
+interface SimpleInterface {
+ val firstProp: String
+ val secondProp: String
+ get() = "Second Property"
+ fun firstMethod(): String
+ fun secondMethod(): String {
+ println("Hello, from: " + secondProp)
+ return ""
+ }
+}
+
+class SimpleClass: SimpleInterface {
+ override val firstProp: String = "First Property"
+ override val secondProp: String
+ get() = "Second Property, Overridden!"
+ override fun firstMethod(): String {
+ return("Hello, from: " + firstProp)
+ }
+ override fun secondMethod(): String {
+ return("Hello, from: " + secondProp + firstProp)
+ }
+}
\ No newline at end of file
diff --git a/core-kotlin/src/test/kotlin/com/baeldung/datastructures/NodeTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/datastructures/NodeTest.kt
new file mode 100644
index 0000000000..8a46c5f6ec
--- /dev/null
+++ b/core-kotlin/src/test/kotlin/com/baeldung/datastructures/NodeTest.kt
@@ -0,0 +1,319 @@
+package com.baeldung.datastructures
+
+import org.junit.After
+import org.junit.Assert.*
+import org.junit.Before
+import org.junit.Test
+
+class NodeTest {
+
+ @Before
+ fun setUp() {
+ }
+
+ @After
+ fun tearDown() {
+ }
+
+ /**
+ * Test suit for finding the node by value
+ * Partition the tests as follows:
+ * 1. tree depth: 0, 1, > 1
+ * 2. pivot depth location: not present, 0, 1, 2, > 2
+ */
+
+ /**
+ * Find the node by value
+ * 1. tree depth: 0
+ * 2. pivot depth location: not present
+ */
+ @Test
+ fun givenDepthZero_whenPivotNotPresent_thenNull() {
+ val n = Node(1)
+ assertNull(n.find(2))
+ }
+
+ /**
+ * Find the node by value
+ * 1. tree depth: 0
+ * 2. pivot depth location: 0
+ */
+ @Test
+ fun givenDepthZero_whenPivotDepthZero_thenReturnNodeItself() {
+ val n = Node(1)
+ assertEquals(n, n.find(1))
+ }
+
+ /**
+ * Find the node by value
+ * 1. tree depth: 1
+ * 2. pivot depth location: not present
+ */
+ @Test
+ fun givenDepthOne_whenPivotNotPresent_thenNull() {
+ val n = Node(1, Node(0))
+ assertNull(n.find(2))
+ }
+
+ /**
+ * Find the node by value
+ * 1. tree depth: 1
+ * 2. pivot depth location: not present
+ */
+ @Test
+ fun givenDepthOne_whenPivotAtDepthOne_thenSuccess() {
+ val n = Node(1, Node(0))
+ assertEquals(n.left, n.find(0)
+ )
+ }
+
+ @Test
+ fun givenDepthTwo_whenPivotAtDepth2_then_Success() {
+ val left = Node(1, Node(0), Node(2))
+ val right = Node(5, Node(4), Node(6))
+ val n = Node(3, left, right)
+ assertEquals(left.left, n.find(0))
+ }
+
+
+ /**
+ * Test suit for inserting a value
+ * Partition the test as follows:
+ * 1. tree depth: 0, 1, 2, > 2
+ * 2. depth to insert: 0, 1, > 1
+ * 3. is duplicate: no, yes
+ * 4. sub-tree: left, right
+ */
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 0
+ * 2. depth to insert: 1
+ * 3. is duplicate: no
+ * 4. sub-tree: right
+ */
+ @Test
+ fun givenTreeDepthZero_whenInsertNoDuplicateToRight_thenAddNode() {
+ val n = Node(1)
+ n.insert(2)
+ assertEquals(1, n.key)
+ with(n.right!!) {
+ assertEquals(2, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ assertNull(n.left)
+ }
+
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 0
+ * 2. depth to insert: 1
+ * 3. is duplicate: no
+ * 4. sub-tree: right
+ */
+ @Test
+ fun givenTreeDepthZero_whenInsertNoDuplicateToLeft_thenSuccess() {
+ val n = Node(1)
+ n.insert(0)
+ assertEquals(1, n.key)
+ with(n.left!!) {
+ assertEquals(0, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ assertNull(n.right)
+ }
+
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 0
+ * 2. depth to insert: 1
+ * 3. is duplicate: yes
+ */
+ @Test
+ fun givenTreeDepthZero_whenInsertDuplicate_thenSuccess() {
+ val n = Node(1)
+ n.insert(1)
+ assertEquals(1, n.key)
+ assertNull(n.right)
+ assertNull(n.left)
+ }
+
+
+ /**
+ * Test suit for inserting a value
+ * Partition the test as follows:
+ * 1. tree depth: 0, 1, 2, > 2
+ * 2. depth to insert: 0, 1, > 1
+ * 3. is duplicate: no, yes
+ * 4. sub-tree: left, right
+ */
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 1
+ * 2. depth to insert: 1
+ * 3. is duplicate: no
+ * 4. sub-tree: right
+ */
+ @Test
+ fun givenTreeDepthOne_whenInsertNoDuplicateToRight_thenSuccess() {
+ val n = Node(10, Node(3))
+ n.insert(15)
+ assertEquals(10, n.key)
+ with(n.right!!) {
+ assertEquals(15, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ with(n.left!!) {
+ assertEquals(3, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ }
+
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 1
+ * 2. depth to insert: 1
+ * 3. is duplicate: no
+ * 4. sub-tree: left
+ */
+ @Test
+ fun givenTreeDepthOne_whenInsertNoDuplicateToLeft_thenAddNode() {
+ val n = Node(10, null, Node(15))
+ n.insert(3)
+ assertEquals(10, n.key)
+ with(n.right!!) {
+ assertEquals(15, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ with(n.left!!) {
+ assertEquals(3, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ }
+
+ /**
+ * Test for inserting a value
+ * 1. tree depth: 1
+ * 2. depth to insert: 1
+ * 3. is duplicate: yes
+ */
+ @Test
+ fun givenTreeDepthOne_whenInsertDuplicate_thenNoChange() {
+ val n = Node(10, null, Node(15))
+ n.insert(15)
+ assertEquals(10, n.key)
+ with(n.right!!) {
+ assertEquals(15, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ assertNull(n.left)
+ }
+
+ /**
+ * Test suit for removal
+ * Partition the input as follows:
+ * 1. tree depth: 0, 1, 2, > 2
+ * 2. value to delete: absent, present
+ * 3. # child nodes: 0, 1, 2
+ */
+ /**
+ * Test for removal value
+ * 1. tree depth: 0
+ * 2. value to delete: absent
+ */
+ @Test
+ fun givenTreeDepthZero_whenValueAbsent_thenNoChange() {
+ val n = Node(1)
+ n.delete(0)
+ assertEquals(1, n.key)
+ assertNull(n.left)
+ assertNull(n.right)
+ }
+
+ /**
+ * Test for removal
+ * 1. tree depth: 1
+ * 2. value to delete: absent
+ */
+ @Test
+ fun givenTreeDepthOne_whenValueAbsent_thenNoChange() {
+ val n = Node(1, Node(0), Node(2))
+ n.delete(3)
+ assertEquals(1, n.key)
+ assertEquals(2, n.right!!.key)
+ with(n.left!!) {
+ assertEquals(0, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ with(n.right!!) {
+ assertNull(left)
+ assertNull(right)
+ }
+ }
+
+ /**
+ * Test suit for removal
+ * 1. tree depth: 1
+ * 2. value to delete: present
+ * 3. # child nodes: 0
+ */
+ @Test
+ fun givenTreeDepthOne_whenNodeToDeleteHasNoChildren_thenChangeTree() {
+ val n = Node(1, Node(0))
+ n.delete(0)
+ assertEquals(1, n.key)
+ assertNull(n.left)
+ assertNull(n.right)
+ }
+
+ /**
+ * Test suit for removal
+ * 1. tree depth: 2
+ * 2. value to delete: present
+ * 3. # child nodes: 1
+ */
+ @Test
+ fun givenTreeDepthTwo_whenNodeToDeleteHasOneChild_thenChangeTree() {
+ val n = Node(2, Node(0, null, Node(1)), Node(3))
+ n.delete(0)
+ assertEquals(2, n.key)
+ with(n.right!!) {
+ assertEquals(3, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ with(n.left!!) {
+ assertEquals(1, key)
+ assertNull(left)
+ assertNull(right)
+ }
+ }
+
+ @Test
+ fun givenTreeDepthThree_whenNodeToDeleteHasTwoChildren_thenChangeTree() {
+ val l = Node(2, Node(1), Node(5, Node(4), Node(6)))
+ val r = Node(10, Node(9), Node(11))
+ val n = Node(8, l, r)
+ n.delete(8)
+ assertEquals(6, n.key)
+ with(n.left!!) {
+ assertEquals(2, key)
+ assertEquals(1, left!!.key)
+ assertEquals(5, right!!.key)
+ assertEquals(4, right!!.left!!.key)
+ }
+ with(n.right!!) {
+ assertEquals(10, key)
+ assertEquals(9, left!!.key)
+ assertEquals(11, right!!.key)
+ }
+ }
+
+}
diff --git a/core-kotlin/src/test/kotlin/com/baeldung/interfaces/InterfaceExamplesUnitTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/interfaces/InterfaceExamplesUnitTest.kt
new file mode 100644
index 0000000000..96b99948b7
--- /dev/null
+++ b/core-kotlin/src/test/kotlin/com/baeldung/interfaces/InterfaceExamplesUnitTest.kt
@@ -0,0 +1,32 @@
+package com.baeldung.interfaces
+
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class InterfaceExamplesUnitTest {
+ @Test
+ fun givenAnInterface_whenImplemented_thenBehavesAsOverridden() {
+ val simpleClass = SimpleClass()
+ assertEquals("Hello, from: First Property", simpleClass.firstMethod())
+ assertEquals("Hello, from: Second Property, Overridden!First Property", simpleClass.secondMethod())
+ }
+
+ @Test
+ fun givenMultipleInterfaces_whenImplemented_thenBehavesAsOverridden() {
+ val someClass = SomeClass()
+ assertEquals("Hello, from someMethod in SomeClass", someClass.someMethod())
+ assertEquals("Hello, from anotherMethod in SomeClass", someClass.anotherMethod())
+ }
+
+ @Test
+ fun givenConflictingInterfaces_whenImplemented_thenBehavesAsOverridden() {
+ val childClass = ChildClass()
+ assertEquals("Hello, from someMethod in SecondChildInterface", childClass.someMethod())
+ }
+
+ @Test
+ fun givenAnInterface_whenImplemented_thenBehavesAsDelegated() {
+ val myClass = MyClass()
+ assertEquals("Hello, World!", MyDerivedClass(myClass).someMethod())
+ }
+}
\ No newline at end of file
diff --git a/gradle/junit5/build.gradle b/gradle/junit5/build.gradle
new file mode 100644
index 0000000000..5f056d8c23
--- /dev/null
+++ b/gradle/junit5/build.gradle
@@ -0,0 +1,25 @@
+plugins {
+ // Apply the java-library plugin to add support for Java Library
+ id 'java-library'
+}
+
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
+
+ // Only necessary for JUnit 3 and 4 tests
+ testCompileOnly 'junit:junit:4.12'
+ testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
+
+}
+
+repositories {
+ jcenter()
+}
+
+test {
+ useJUnitPlatform {
+ includeTags 'fast'
+ excludeTags 'slow'
+ }
+}
\ No newline at end of file
diff --git a/gradle/junit5/src/test/java/com/example/CalculatorJUnit4Test.java b/gradle/junit5/src/test/java/com/example/CalculatorJUnit4Test.java
new file mode 100644
index 0000000000..4cf63642ee
--- /dev/null
+++ b/gradle/junit5/src/test/java/com/example/CalculatorJUnit4Test.java
@@ -0,0 +1,12 @@
+package com.example;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class CalculatorJUnit4Test {
+ @Test
+ public void testAdd() {
+ assertEquals(42, Integer.sum(19, 23));
+ }
+}
diff --git a/gradle/junit5/src/test/java/com/example/CalculatorJUnit5Test.java b/gradle/junit5/src/test/java/com/example/CalculatorJUnit5Test.java
new file mode 100644
index 0000000000..59fdb0f8ae
--- /dev/null
+++ b/gradle/junit5/src/test/java/com/example/CalculatorJUnit5Test.java
@@ -0,0 +1,36 @@
+package com.example;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;;
+
+public class CalculatorJUnit5Test {
+
+ @Tag("fast")
+ @Test
+ public void testAdd() {
+ assertEquals(42, Integer.sum(19, 23));
+ }
+
+ @Tag("slow")
+ @Test
+ public void testAddMaxInteger() {
+ assertEquals(2147483646, Integer.sum(2147183646, 300000));
+ }
+
+ @Tag("fast")
+ @Test
+ public void testAddZero() {
+ assertEquals(21, Integer.sum(21, 0));
+ }
+
+ @Tag("fast")
+ @Test
+ public void testDivide() {
+ assertThrows(ArithmeticException.class, () -> {
+ Integer.divideUnsigned(42, 0);
+ });
+ }
+}
diff --git a/gradle/settings.gradle b/gradle/settings.gradle
index 38704681bd..f1d64de58a 100644
--- a/gradle/settings.gradle
+++ b/gradle/settings.gradle
@@ -5,6 +5,6 @@ include 'greeting-library'
include 'greeting-library-java'
include 'greeter'
include 'gradletaskdemo'
-
+include 'junit5'
println 'This will be executed during the initialization phase.'
diff --git a/guava-collections/.gitignore b/guava-collections/.gitignore
new file mode 100644
index 0000000000..83c05e60c8
--- /dev/null
+++ b/guava-collections/.gitignore
@@ -0,0 +1,13 @@
+*.class
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/guava-collections/README.md b/guava-collections/README.md
new file mode 100644
index 0000000000..eb1eb1d35c
--- /dev/null
+++ b/guava-collections/README.md
@@ -0,0 +1,20 @@
+=========
+
+## Guava and Hamcrest Cookbooks and Examples
+
+
+### Relevant Articles:
+- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections)
+- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order)
+- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays)
+- [Partition a List in Java](http://www.baeldung.com/java-list-split)
+- [Filtering and Transforming Collections in Guava](http://www.baeldung.com/guava-filter-and-transform-a-collection)
+- [Guava – Join and Split Collections](http://www.baeldung.com/guava-joiner-and-splitter-tutorial)
+- [Guava – Lists](http://www.baeldung.com/guava-lists)
+- [Guava – Sets](http://www.baeldung.com/guava-sets)
+- [Guava – Maps](http://www.baeldung.com/guava-maps)
+- [Guide to Guava Multimap](http://www.baeldung.com/guava-multimap)
+- [Guide to Guava RangeSet](http://www.baeldung.com/guava-rangeset)
+- [Guide to Guava RangeMap](http://www.baeldung.com/guava-rangemap)
+- [Guide to Guava MinMaxPriorityQueue and EvictingQueue](http://www.baeldung.com/guava-minmax-priority-queue-and-evicting-queue)
+- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
\ No newline at end of file
diff --git a/guava-collections/pom.xml b/guava-collections/pom.xml
new file mode 100644
index 0000000000..a717023156
--- /dev/null
+++ b/guava-collections/pom.xml
@@ -0,0 +1,66 @@
+
+ 4.0.0
+ com.baeldung
+ guava-collections
+ 0.1.0-SNAPSHOT
+ guava-collections
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
+
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+
+
+ org.hamcrest
+ java-hamcrest
+ ${java-hamcrest.version}
+ test
+
+
+
+
+ guava
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ 24.0-jre
+ 3.5
+ 4.1
+
+
+ 3.6.1
+ 2.0.0.0
+
+
+
\ No newline at end of file
diff --git a/guava-collections/src/main/resources/logback.xml b/guava-collections/src/main/resources/logback.xml
new file mode 100644
index 0000000000..56af2d397e
--- /dev/null
+++ b/guava-collections/src/main/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guava/src/test/java/org/baeldung/guava/EvictingQueueUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/EvictingQueueUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/EvictingQueueUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/EvictingQueueUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaCollectionTypesUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaCollectionTypesUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaCollectionTypesUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaCollectionTypesUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaCollectionsExamplesUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaCollectionsExamplesUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaCollectionsExamplesUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaCollectionsExamplesUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaFilterTransformCollectionsUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaFilterTransformCollectionsUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaFilterTransformCollectionsUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaFilterTransformCollectionsUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaMapFromSet.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaMapFromSet.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaMapFromSet.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMapFromSetUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaMapFromSetUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaMapFromSetUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaMapFromSetUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMapInitializeUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaMapInitializeUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaMapInitializeUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaMapInitializeUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMultiMapUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaMultiMapUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaMultiMapUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaMultiMapUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaOrderingExamplesUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaOrderingExamplesUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaOrderingExamplesUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaOrderingExamplesUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaOrderingUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaOrderingUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaOrderingUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaOrderingUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaRangeMapUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaRangeMapUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaRangeMapUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaRangeMapUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaRangeSetUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaRangeSetUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaRangeSetUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaRangeSetUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/GuavaStringUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/GuavaStringUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/GuavaStringUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/GuavaStringUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/guava/MinMaxPriorityQueueUnitTest.java b/guava-collections/src/test/java/org/baeldung/guava/MinMaxPriorityQueueUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/guava/MinMaxPriorityQueueUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/guava/MinMaxPriorityQueueUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/hamcrest/HamcrestExamplesUnitTest.java b/guava-collections/src/test/java/org/baeldung/hamcrest/HamcrestExamplesUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/hamcrest/HamcrestExamplesUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/hamcrest/HamcrestExamplesUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/java/CollectionApachePartitionUnitTest.java b/guava-collections/src/test/java/org/baeldung/java/CollectionApachePartitionUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/java/CollectionApachePartitionUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/java/CollectionApachePartitionUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/java/CollectionGuavaPartitionUnitTest.java b/guava-collections/src/test/java/org/baeldung/java/CollectionGuavaPartitionUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/java/CollectionGuavaPartitionUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/java/CollectionGuavaPartitionUnitTest.java
diff --git a/guava/src/test/java/org/baeldung/java/CollectionJavaPartitionUnitTest.java b/guava-collections/src/test/java/org/baeldung/java/CollectionJavaPartitionUnitTest.java
similarity index 100%
rename from guava/src/test/java/org/baeldung/java/CollectionJavaPartitionUnitTest.java
rename to guava-collections/src/test/java/org/baeldung/java/CollectionJavaPartitionUnitTest.java
diff --git a/guava-collections/src/test/resources/.gitignore b/guava-collections/src/test/resources/.gitignore
new file mode 100644
index 0000000000..83c05e60c8
--- /dev/null
+++ b/guava-collections/src/test/resources/.gitignore
@@ -0,0 +1,13 @@
+*.class
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test.out b/guava-collections/src/test/resources/test.out
new file mode 100644
index 0000000000..7a79da3803
--- /dev/null
+++ b/guava-collections/src/test/resources/test.out
@@ -0,0 +1 @@
+John Jane Adam Tom
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test1.in b/guava-collections/src/test/resources/test1.in
new file mode 100644
index 0000000000..70c379b63f
--- /dev/null
+++ b/guava-collections/src/test/resources/test1.in
@@ -0,0 +1 @@
+Hello world
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test1_1.in b/guava-collections/src/test/resources/test1_1.in
new file mode 100644
index 0000000000..8318c86b35
--- /dev/null
+++ b/guava-collections/src/test/resources/test1_1.in
@@ -0,0 +1 @@
+Test
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test2.in b/guava-collections/src/test/resources/test2.in
new file mode 100644
index 0000000000..622efea9e6
--- /dev/null
+++ b/guava-collections/src/test/resources/test2.in
@@ -0,0 +1,4 @@
+John
+Jane
+Adam
+Tom
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test_copy.in b/guava-collections/src/test/resources/test_copy.in
new file mode 100644
index 0000000000..70c379b63f
--- /dev/null
+++ b/guava-collections/src/test/resources/test_copy.in
@@ -0,0 +1 @@
+Hello world
\ No newline at end of file
diff --git a/guava-collections/src/test/resources/test_le.txt b/guava-collections/src/test/resources/test_le.txt
new file mode 100644
index 0000000000..f7cc484bf4
Binary files /dev/null and b/guava-collections/src/test/resources/test_le.txt differ
diff --git a/guava/README.md b/guava/README.md
index fe1a347d72..7501bf08de 100644
--- a/guava/README.md
+++ b/guava/README.md
@@ -4,33 +4,19 @@
### Relevant Articles:
-- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections)
-- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order)
- [Guava Functional Cookbook](http://www.baeldung.com/guava-functions-predicates)
-- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays)
-- [Partition a List in Java](http://www.baeldung.com/java-list-split)
-- [Filtering and Transforming Collections in Guava](http://www.baeldung.com/guava-filter-and-transform-a-collection)
-- [Guava – Join and Split Collections](http://www.baeldung.com/guava-joiner-and-splitter-tutorial)
- [Guava – Write to File, Read from File](http://www.baeldung.com/guava-write-to-file-read-from-file)
-- [Guava – Lists](http://www.baeldung.com/guava-lists)
-- [Guava – Sets](http://www.baeldung.com/guava-sets)
-- [Guava – Maps](http://www.baeldung.com/guava-maps)
- [Guava Set + Function = Map](http://www.baeldung.com/guava-set-function-map-tutorial)
- [Guide to Guava’s Ordering](http://www.baeldung.com/guava-ordering)
- [Guide to Guava’s PreConditions](http://www.baeldung.com/guava-preconditions)
- [Introduction to Guava CacheLoader](http://www.baeldung.com/guava-cacheloader)
- [Introduction to Guava Memoizer](http://www.baeldung.com/guava-memoizer)
- [Guide to Guava’s EventBus](http://www.baeldung.com/guava-eventbus)
-- [Guide to Guava Multimap](http://www.baeldung.com/guava-multimap)
-- [Guide to Guava RangeSet](http://www.baeldung.com/guava-rangeset)
-- [Guide to Guava RangeMap](http://www.baeldung.com/guava-rangemap)
- [Guide to Guava Table](http://www.baeldung.com/guava-table)
- [Guide to Guava’s Reflection Utilities](http://www.baeldung.com/guava-reflection)
- [Guide to Guava ClassToInstanceMap](http://www.baeldung.com/guava-class-to-instance-map)
-- [Guide to Guava MinMaxPriorityQueue and EvictingQueue](http://www.baeldung.com/guava-minmax-priority-queue-and-evicting-queue)
- [Guide to Mathematical Utilities in Guava](http://www.baeldung.com/guava-math)
- [Bloom Filter in Java using Guava](http://www.baeldung.com/guava-bloom-filter)
- [Using Guava CountingOutputStream](http://www.baeldung.com/guava-counting-outputstream)
- [Hamcrest Text Matchers](http://www.baeldung.com/hamcrest-text-matchers)
- [Quick Guide to the Guava RateLimiter](http://www.baeldung.com/guava-rate-limiter)
-- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
diff --git a/guava/pom.xml b/guava/pom.xml
index 60678608dd..1d37a79ab6 100644
--- a/guava/pom.xml
+++ b/guava/pom.xml
@@ -14,12 +14,6 @@
-
-
- org.apache.commons
- commons-collections4
- ${commons-collections4.version}
-
org.apache.commons
commons-lang3
@@ -56,7 +50,6 @@
24.0-jre
3.5
- 4.1
3.6.1
diff --git a/hibernate5/README.md b/hibernate5/README.md
index b90f885c78..fbf46eed50 100644
--- a/hibernate5/README.md
+++ b/hibernate5/README.md
@@ -16,3 +16,4 @@
- [Hibernate Entity Lifecycle](https://www.baeldung.com/hibernate-entity-lifecycle)
- [Mapping A Hibernate Query to a Custom Class](https://www.baeldung.com/hibernate-query-to-custom-class)
- [@JoinColumn Annotation Explained](https://www.baeldung.com/jpa-join-column)
+- [Hibernate 5 Naming Strategy Configuration](https://www.baeldung.com/hibernate-naming-strategy)
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/User.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/User.java
index 90203d29ec..ccbdf80bf1 100644
--- a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/User.java
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/User.java
@@ -4,13 +4,23 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
-import javax.persistence.SequenceGenerator;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
@Entity
public class User {
@Id
- @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence-generator")
- @SequenceGenerator(name = "sequence-generator", sequenceName = "user_sequence", initialValue = 4)
+ @GeneratedValue(generator = "sequence-generator")
+ @GenericGenerator(
+ name = "sequence-generator",
+ strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
+ parameters = {
+ @Parameter(name = "sequence_name", value = "user_sequence"),
+ @Parameter(name = "initial_value", value = "4"),
+ @Parameter(name = "increment_size", value = "1")
+ }
+ )
private long userId;
public long getUserId() {
diff --git a/jackson/src/test/java/com/baeldung/jackson/xmlToJson/XmlToJsonUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/xmlToJson/XmlToJsonUnitTest.java
index 295bb9d6e8..6329a8ed2f 100644
--- a/jackson/src/test/java/com/baeldung/jackson/xmlToJson/XmlToJsonUnitTest.java
+++ b/jackson/src/test/java/com/baeldung/jackson/xmlToJson/XmlToJsonUnitTest.java
@@ -1,7 +1,5 @@
package com.baeldung.jackson.xmlToJson;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@@ -14,43 +12,32 @@ import java.io.IOException;
public class XmlToJsonUnitTest {
@Test
- public void givenAnXML_whenUseDataBidingToConvertToJSON_thenReturnDataOK() {
+ public void givenAnXML_whenUseDataBidingToConvertToJSON_thenReturnDataOK() throws IOException{
String flowerXML = "PoppyRED9";
- try {
- XmlMapper xmlMapper = new XmlMapper();
- Flower poppy = xmlMapper.readValue(flowerXML, Flower.class);
+ XmlMapper xmlMapper = new XmlMapper();
+ Flower poppy = xmlMapper.readValue(flowerXML, Flower.class);
- assertEquals(poppy.getName(), "Poppy");
- assertEquals(poppy.getColor(), Color.RED);
- assertEquals(poppy.getPetals(), new Integer(9));
+ assertEquals(poppy.getName(), "Poppy");
+ assertEquals(poppy.getColor(), Color.RED);
+ assertEquals(poppy.getPetals(), new Integer(9));
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(poppy);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(poppy);
- assertEquals(json, "{\"name\":\"Poppy\",\"color\":\"RED\",\"petals\":9}");
- System.out.println(json);
- } catch(IOException e) {
- e.printStackTrace();
- }
+ assertEquals(json, "{\"name\":\"Poppy\",\"color\":\"RED\",\"petals\":9}");
}
@Test
- public void givenAnXML_whenUseATreeConvertToJSON_thenReturnDataOK() {
+ public void givenAnXML_whenUseATreeConvertToJSON_thenReturnDataOK() throws IOException {
String flowerXML = "PoppyRED9";
- try {
- XmlMapper xmlMapper = new XmlMapper();
- JsonNode node = xmlMapper.readTree(flowerXML.getBytes());
+ XmlMapper xmlMapper = new XmlMapper();
+ JsonNode node = xmlMapper.readTree(flowerXML.getBytes());
- ObjectMapper jsonMapper = new ObjectMapper();
- String json = jsonMapper.writeValueAsString(node);
+ ObjectMapper jsonMapper = new ObjectMapper();
+ String json = jsonMapper.writeValueAsString(node);
- System.out.println(json);
-
- assertEquals(json, "{\"name\":\"Poppy\",\"color\":\"RED\",\"petals\":\"9\"}");
- } catch(IOException e) {
- e.printStackTrace();
- }
+ assertEquals(json, "{\"name\":\"Poppy\",\"color\":\"RED\",\"petals\":\"9\"}");
}
}
diff --git a/java-dates/pom.xml b/java-dates/pom.xml
index 13e2a077e1..2618fad1d4 100644
--- a/java-dates/pom.xml
+++ b/java-dates/pom.xml
@@ -80,7 +80,7 @@
2.10
3.6.1
- 9
- 9
+ 1.9
+ 1.9
diff --git a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java
index 545009a2a9..92da22cc95 100644
--- a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java
+++ b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java
@@ -5,7 +5,9 @@ import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
+import java.time.LocalDate;
import java.time.LocalDateTime;
+import java.time.Period;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@@ -26,6 +28,17 @@ public class DateDiffUnitTest {
assertEquals(diff, 6);
}
+
+ @Test
+ public void givenTwoDatesInJava8_whenDifferentiating_thenWeGetSix() {
+ LocalDate now = LocalDate.now();
+ LocalDate sixDaysBehind = now.minusDays(6);
+
+ Period period = Period.between(now, sixDaysBehind);
+ int diff = period.getDays();
+
+ assertEquals(diff, 6);
+ }
@Test
public void givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix() {
@@ -38,6 +51,15 @@ public class DateDiffUnitTest {
assertEquals(diff, 6);
}
+ @Test
+ public void givenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix() {
+ LocalDateTime ldt = LocalDateTime.now();
+ ZonedDateTime now = ldt.atZone(ZoneId.of("America/Montreal"));
+ ZonedDateTime sixDaysBehind = now.withZoneSameInstant(ZoneId.of("Asia/Singapore")).minusDays(6);
+ long diff = ChronoUnit.DAYS.between(sixDaysBehind, now);
+ assertEquals(diff, 6);
+ }
+
@Test
public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() {
org.joda.time.LocalDate now = org.joda.time.LocalDate.now();
diff --git a/java-dates/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java b/java-dates/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java
new file mode 100644
index 0000000000..f3b2b11893
--- /dev/null
+++ b/java-dates/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java
@@ -0,0 +1,158 @@
+package com.baeldung.datetime;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.FormatStyle;
+import java.time.temporal.ChronoUnit;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class DateTimeFormatterUnitTest {
+
+ @Test
+ public void givenDefaultUsLocaleAndDateTimeAndPattern_whenFormatWithDifferentLocales_thenGettingLocalizedDateTimes() {
+ Locale.setDefault(Locale.US);
+ LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
+ String pattern = "dd-MMMM-yyyy HH:mm:ss.SSS";
+
+ DateTimeFormatter defaultTimeFormatter = DateTimeFormatter.ofPattern(pattern);
+ DateTimeFormatter plTimeFormatter = DateTimeFormatter.ofPattern(pattern, new Locale("pl", "PL"));
+ DateTimeFormatter deTimeFormatter = DateTimeFormatter.ofPattern(pattern).withLocale(Locale.GERMANY);
+
+ Assert.assertEquals("01-January-2018 10:15:50.000", defaultTimeFormatter.format(localDateTime));
+ Assert.assertEquals("01-stycznia-2018 10:15:50.000", plTimeFormatter.format(localDateTime));
+ Assert.assertEquals("01-Januar-2018 10:15:50.000", deTimeFormatter.format(localDateTime));
+ }
+
+ @Test
+ public void givenDateTimeAndTimeZone_whenFormatWithDifferentLocales_thenGettingLocalizedZonedDateTimes() {
+ Locale.setDefault(Locale.US);
+ LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
+ ZoneId losAngelesTimeZone = TimeZone.getTimeZone("America/Los_Angeles").toZoneId();
+
+ DateTimeFormatter localizedFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
+ DateTimeFormatter frLocalizedFormatter =
+ DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(Locale.FRANCE);
+ String formattedDateTime = localizedFormatter.format(ZonedDateTime.of(localDateTime, losAngelesTimeZone));
+ String frFormattedDateTime = frLocalizedFormatter.format(ZonedDateTime.of(localDateTime, losAngelesTimeZone));
+
+ Assert.assertEquals("Monday, January 1, 2018 10:15:50 AM PST", formattedDateTime);
+ Assert.assertEquals("lundi 1 janvier 2018 10 h 15 PST", frFormattedDateTime);
+ }
+
+ @Test
+ public void shouldPrintFormattedDate() {
+ String europeanDatePattern = "dd.MM.yyyy";
+ DateTimeFormatter europeanDateFormatter = DateTimeFormatter.ofPattern(europeanDatePattern);
+ LocalDate summerDay = LocalDate.of(2016, 7, 31);
+ Assert.assertEquals("31.07.2016", europeanDateFormatter.format(summerDay));
+ }
+
+ @Test
+ public void shouldPrintFormattedTime24() {
+ String timeColonPattern = "HH:mm:ss";
+ DateTimeFormatter timeColonFormatter = DateTimeFormatter.ofPattern(timeColonPattern);
+ LocalTime colonTime = LocalTime.of(17, 35, 50);
+ Assert.assertEquals("17:35:50", timeColonFormatter.format(colonTime));
+ }
+
+ @Test
+ public void shouldPrintFormattedTimeWithMillis() {
+ String timeColonPattern = "HH:mm:ss SSS";
+ DateTimeFormatter timeColonFormatter = DateTimeFormatter.ofPattern(timeColonPattern);
+ LocalTime colonTime = LocalTime.of(17, 35, 50).plus(329, ChronoUnit.MILLIS);
+ Assert.assertEquals("17:35:50 329", timeColonFormatter.format(colonTime));
+ }
+
+ @Test
+ public void shouldPrintFormattedTimePM() {
+ String timeColonPattern = "hh:mm:ss a";
+ DateTimeFormatter timeColonFormatter = DateTimeFormatter.ofPattern(timeColonPattern);
+ LocalTime colonTime = LocalTime.of(17, 35, 50);
+ Assert.assertEquals("05:35:50 PM", timeColonFormatter.format(colonTime));
+ }
+
+ @Test
+ public void shouldPrintFormattedUTCRelatedZonedDateTime() {
+ String newYorkDateTimePattern = "dd.MM.yyyy HH:mm z";
+ DateTimeFormatter newYorkDateFormatter = DateTimeFormatter.ofPattern(newYorkDateTimePattern);
+ LocalDateTime summerDay = LocalDateTime.of(2016, 7, 31, 14, 15);
+ Assert.assertEquals("31.07.2016 14:15 UTC-04:00", newYorkDateFormatter.format(ZonedDateTime.of(summerDay, ZoneId.of("UTC-4"))));
+ }
+
+ @Test
+ public void shouldPrintFormattedNewYorkZonedDateTime() {
+ String newYorkDateTimePattern = "dd.MM.yyyy HH:mm z";
+ DateTimeFormatter newYorkDateFormatter = DateTimeFormatter.ofPattern(newYorkDateTimePattern);
+ LocalDateTime summerDay = LocalDateTime.of(2016, 7, 31, 14, 15);
+ Assert.assertEquals("31.07.2016 14:15 EDT", newYorkDateFormatter.format(ZonedDateTime.of(summerDay, ZoneId.of("America/New_York"))));
+ }
+
+ @Test
+ public void shouldPrintStyledDate() {
+ LocalDate anotherSummerDay = LocalDate.of(2016, 8, 23);
+ Assert.assertEquals("Tuesday, August 23, 2016", DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(anotherSummerDay));
+ Assert.assertEquals("August 23, 2016", DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(anotherSummerDay));
+ Assert.assertEquals("Aug 23, 2016", DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(anotherSummerDay));
+ Assert.assertEquals("8/23/16", DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(anotherSummerDay));
+ }
+
+ @Test
+ public void shouldPrintStyledDateTime() {
+ LocalDateTime anotherSummerDay = LocalDateTime.of(2016, 8, 23, 13, 12, 45);
+ Assert.assertEquals("Tuesday, August 23, 2016 1:12:45 PM EET", DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withZone(ZoneId.of("Europe/Helsinki")).format(anotherSummerDay));
+ Assert.assertEquals("August 23, 2016 1:12:45 PM EET", DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withZone(ZoneId.of("Europe/Helsinki")).format(anotherSummerDay));
+ Assert.assertEquals("Aug 23, 2016 1:12:45 PM", DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withZone(ZoneId.of("Europe/Helsinki")).format(anotherSummerDay));
+ Assert.assertEquals("8/23/16 1:12 PM", DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withZone(ZoneId.of("Europe/Helsinki")).format(anotherSummerDay));
+ }
+
+ @Test
+ public void shouldPrintFormattedDateTimeWithPredefined() {
+ Assert.assertEquals("2018-03-09", DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.of(2018, 3, 9)));
+ Assert.assertEquals("2018-03-09-03:00", DateTimeFormatter.ISO_OFFSET_DATE.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3"))));
+ Assert.assertEquals("Fri, 9 Mar 2018 00:00:00 -0300", DateTimeFormatter.RFC_1123_DATE_TIME.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3"))));
+ }
+
+ @Test
+ public void shouldParseDateTime() {
+ Assert.assertEquals(LocalDate.of(2018, 3, 12), LocalDate.from(DateTimeFormatter.ISO_LOCAL_DATE.parse("2018-03-09")).plusDays(3));
+ }
+
+ @Test
+ public void shouldParseFormatStyleFull() {
+ ZonedDateTime dateTime = ZonedDateTime.from(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).parse("Tuesday, August 23, 2016 1:12:45 PM EET"));
+ Assert.assertEquals(ZonedDateTime.of(LocalDateTime.of(2016, 8, 23, 22, 12, 45), ZoneId.of("Europe/Bucharest")), dateTime.plusHours(9));
+ }
+
+ @Test
+ public void shouldParseDateWithCustomFormatter() {
+ DateTimeFormatter europeanDateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
+ Assert.assertFalse(LocalDate.from(europeanDateFormatter.parse("15.08.2014")).isLeapYear());
+ }
+
+ @Test
+ public void shouldParseTimeWithCustomFormatter() {
+ DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm:ss a");
+ Assert.assertTrue(LocalTime.from(timeFormatter.parse("12:25:30 AM")).isBefore(LocalTime.NOON));
+ }
+
+ @Test
+ public void shouldParseZonedDateTimeWithCustomFormatter() {
+ DateTimeFormatter zonedFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm z");
+ Assert.assertEquals(7200, ZonedDateTime.from(zonedFormatter.parse("31.07.2016 14:15 GMT+02:00")).getOffset().getTotalSeconds());
+ }
+
+ @Test(expected = DateTimeParseException.class)
+ public void shouldExpectAnExceptionIfDateTimeStringNotMatchPattern() {
+ DateTimeFormatter zonedFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm z");
+ ZonedDateTime.from(zonedFormatter.parse("31.07.2016 14:15"));
+ }
+}
diff --git a/java-dates/src/test/java/com/baeldung/zoneddatetime/ZonedDateTimeUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/ZonedDateTimeUnitTest.java
new file mode 100644
index 0000000000..355fef35c6
--- /dev/null
+++ b/java-dates/src/test/java/com/baeldung/zoneddatetime/ZonedDateTimeUnitTest.java
@@ -0,0 +1,43 @@
+package com.baeldung.zoneddatetime;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.logging.Logger;
+
+import org.junit.Test;
+
+public class ZonedDateTimeUnitTest {
+
+ private static final Logger log = Logger.getLogger(ZonedDateTimeUnitTest.class.getName());
+
+ @Test
+ public void testZonedDateTimeToString() {
+
+ ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(ZoneId.of("UTC"));
+ ZonedDateTime zonedDateTimeOf = ZonedDateTime.of(2018, 01, 01, 0, 0, 0, 0, ZoneId.of("UTC"));
+
+ LocalDateTime localDateTime = LocalDateTime.now();
+ ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("UTC"));
+
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy - hh:mm:ss Z");
+ String formattedString = zonedDateTime.format(formatter);
+
+ DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy - hh:mm:ss z");
+ String formattedString2 = zonedDateTime.format(formatter2);
+
+ log.info(formattedString);
+ log.info(formattedString2);
+
+ }
+
+ @Test
+ public void testZonedDateTimeFromString() {
+
+ ZonedDateTime zonedDateTime = ZonedDateTime.parse("2011-12-03T10:15:30+01:00", DateTimeFormatter.ISO_ZONED_DATE_TIME);
+
+ log.info(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
+ }
+
+}
diff --git a/java-difference-date/README.md b/java-difference-date/README.md
deleted file mode 100644
index 2a024c27a2..0000000000
--- a/java-difference-date/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## Relevant articles:
-
-- [Period and Duration in Java](http://www.baeldung.com/java-period-duration)
-- [Introduction to the Java 8 Date/Time API](http://www.baeldung.com/java-8-date-time-intro)
-- [Migrating to the New Java 8 Date Time API](http://www.baeldung.com/migrating-to-java-8-date-time-api)
\ No newline at end of file
diff --git a/java-difference-date/pom.xml b/java-difference-date/pom.xml
deleted file mode 100644
index 8c87afc0a2..0000000000
--- a/java-difference-date/pom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
- 4.0.0
- com.baeldung
- java-difference-date
- 0.0.1-SNAPSHOT
- jar
- java-difference-date
- Difference between two dates in java
-
-
- com.baeldung
- parent-modules
- 1.0.0-SNAPSHOT
-
-
-
-
- joda-time
- joda-time
- ${joda-time.version}
-
-
- com.darwinsys
- hirondelle-date4j
- ${hirondelle-date4j.version}
-
-
-
-
- 2.9.9
- 1.5.1
-
-
-
diff --git a/java-difference-date/src/test/java/com/baeldung/DateDiffUnitTest.java b/java-difference-date/src/test/java/com/baeldung/DateDiffUnitTest.java
deleted file mode 100644
index 2c5323be6f..0000000000
--- a/java-difference-date/src/test/java/com/baeldung/DateDiffUnitTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.baeldung;
-
-import org.joda.time.DateTime;
-import org.junit.Test;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.Duration;
-import java.time.ZonedDateTime;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertEquals;
-
-public class DateDiffUnitTest {
- @Test
- public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
- Date firstDate = sdf.parse("06/24/2017");
- Date secondDate = sdf.parse("06/30/2017");
-
- long diffInMillies = Math.abs(secondDate.getTime() - firstDate.getTime());
- long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
-
- assertEquals(diff, 6);
- }
-
- @Test
- public void givenTwoDatesInJava8_whenDifferentiating_thenWeGetSix() {
- ZonedDateTime now = ZonedDateTime.now();
- ZonedDateTime sixDaysBehind = now.minusDays(6);
-
- Duration duration = Duration.between(now, sixDaysBehind);
- long diff = Math.abs(duration.toDays());
-
- assertEquals(diff, 6);
- }
-
- @Test
- public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() {
- DateTime now = DateTime.now();
- DateTime sixDaysBehind = now.minusDays(6);
-
- org.joda.time.Duration duration = new org.joda.time.Duration(now, sixDaysBehind);
- long diff = Math.abs(duration.getStandardDays());
-
- assertEquals(diff, 6);
- }
-
- @Test
- public void givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix() {
- hirondelle.date4j.DateTime now = hirondelle.date4j.DateTime.now(TimeZone.getDefault());
- hirondelle.date4j.DateTime sixDaysBehind = now.minusDays(6);
-
- long diff = Math.abs(now.numDaysFrom(sixDaysBehind));
-
- assertEquals(diff, 6);
- }
-}
\ No newline at end of file
diff --git a/java-streams/README.md b/java-streams/README.md
index 548d4b6a33..2550f08650 100644
--- a/java-streams/README.md
+++ b/java-streams/README.md
@@ -13,3 +13,4 @@
- [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices)
- [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams)
- [Stream Ordering in Java](https://www.baeldung.com/java-stream-ordering)
+- [Introduction to Protonpack](https://www.baeldung.com/java-protonpack)
diff --git a/java-strings/README.md b/java-strings/README.md
index b12fc75f30..603f70d2f1 100644
--- a/java-strings/README.md
+++ b/java-strings/README.md
@@ -27,7 +27,10 @@
- [Compact Strings in Java 9](http://www.baeldung.com/java-9-compact-string)
- [Java Check a String for Lowercase/Uppercase Letter, Special Character and Digit](https://www.baeldung.com/java-lowercase-uppercase-special-character-digit-regex)
- [Convert java.util.Date to String](https://www.baeldung.com/java-util-date-to-string)
+- [String Not Empty Test Assertions in Java](https://www.baeldung.com/java-assert-string-not-empty)
- [Get Substring from String in Java](https://www.baeldung.com/java-substring)
- [Converting a Stack Trace to a String in Java](https://www.baeldung.com/java-stacktrace-to-string)
- [Sorting a String Alphabetically in Java](https://www.baeldung.com/java-sort-string-alphabetically)
- [Remove Emojis from a Java String](https://www.baeldung.com/java-string-remove-emojis)
+- [String Not Empty Test Assertions in Java](https://www.baeldung.com/java-assert-string-not-empty)
+- [String Performance Hints](https://www.baeldung.com/java-string-performance)
diff --git a/java-strings/pom.xml b/java-strings/pom.xml
index b1ba49b33a..a43490ce5c 100644
--- a/java-strings/pom.xml
+++ b/java-strings/pom.xml
@@ -68,7 +68,17 @@
emoji-java
4.0.0
-
+
+
+ org.passay
+ passay
+ 1.3.1
+
+
+ org.apache.commons
+ commons-text
+ 1.4
+
diff --git a/java-strings/src/main/java/com/baeldung/string/password/RandomPasswordGenerator.java b/java-strings/src/main/java/com/baeldung/string/password/RandomPasswordGenerator.java
new file mode 100644
index 0000000000..46af4d7c51
--- /dev/null
+++ b/java-strings/src/main/java/com/baeldung/string/password/RandomPasswordGenerator.java
@@ -0,0 +1,152 @@
+package com.baeldung.string.password;
+
+import java.security.SecureRandom;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.text.RandomStringGenerator;
+import org.passay.CharacterData;
+import org.passay.CharacterRule;
+import org.passay.EnglishCharacterData;
+import org.passay.PasswordGenerator;
+
+public class RandomPasswordGenerator {
+
+ /**
+ * Special characters allowed in password.
+ */
+ public static final String ALLOWED_SPL_CHARACTERS = "!@#$%^&*()_+";
+
+ public static final String ERROR_CODE = "ERRONEOUS_SPECIAL_CHARS";
+
+ Random random = new SecureRandom();
+
+ public String generatePassayPassword() {
+ PasswordGenerator gen = new PasswordGenerator();
+ CharacterData lowerCaseChars = EnglishCharacterData.LowerCase;
+ CharacterRule lowerCaseRule = new CharacterRule(lowerCaseChars);
+ lowerCaseRule.setNumberOfCharacters(2);
+ CharacterData upperCaseChars = EnglishCharacterData.UpperCase;
+ CharacterRule upperCaseRule = new CharacterRule(upperCaseChars);
+ upperCaseRule.setNumberOfCharacters(2);
+ CharacterData digitChars = EnglishCharacterData.Digit;
+ CharacterRule digitRule = new CharacterRule(digitChars);
+ digitRule.setNumberOfCharacters(2);
+ CharacterData specialChars = new CharacterData() {
+ public String getErrorCode() {
+ return ERROR_CODE;
+ }
+
+ public String getCharacters() {
+ return ALLOWED_SPL_CHARACTERS;
+ }
+ };
+ CharacterRule splCharRule = new CharacterRule(specialChars);
+ splCharRule.setNumberOfCharacters(2);
+ String password = gen.generatePassword(10, splCharRule, lowerCaseRule, upperCaseRule, digitRule);
+ return password;
+ }
+
+ public String generateCommonTextPassword() {
+ String pwString = generateRandomSpecialCharacters(2).concat(generateRandomNumbers(2))
+ .concat(generateRandomAlphabet(2, true))
+ .concat(generateRandomAlphabet(2, false))
+ .concat(generateRandomCharacters(2));
+ List pwChars = pwString.chars()
+ .mapToObj(data -> (char) data)
+ .collect(Collectors.toList());
+ Collections.shuffle(pwChars);
+ String password = pwChars.stream()
+ .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
+ .toString();
+ return password;
+ }
+
+ public String generateCommonsLang3Password() {
+ String upperCaseLetters = RandomStringUtils.random(2, 65, 90, true, true);
+ String lowerCaseLetters = RandomStringUtils.random(2, 97, 122, true, true);
+ String numbers = RandomStringUtils.randomNumeric(2);
+ String specialChar = RandomStringUtils.random(2, 33, 47, false, false);
+ String totalChars = RandomStringUtils.randomAlphanumeric(2);
+ String combinedChars = upperCaseLetters.concat(lowerCaseLetters)
+ .concat(numbers)
+ .concat(specialChar)
+ .concat(totalChars);
+ List pwdChars = combinedChars.chars()
+ .mapToObj(c -> (char) c)
+ .collect(Collectors.toList());
+ Collections.shuffle(pwdChars);
+ String password = pwdChars.stream()
+ .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
+ .toString();
+ return password;
+ }
+
+ public String generateSecureRandomPassword() {
+ Stream pwdStream = Stream.concat(getRandomNumbers(2), Stream.concat(getRandomSpecialChars(2), Stream.concat(getRandomAlphabets(2, true), getRandomAlphabets(4, false))));
+ List charList = pwdStream.collect(Collectors.toList());
+ Collections.shuffle(charList);
+ String password = charList.stream()
+ .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
+ .toString();
+ return password;
+ }
+
+ public String generateRandomSpecialCharacters(int length) {
+ RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder().withinRange(33, 45)
+ .build();
+ return pwdGenerator.generate(length);
+ }
+
+ public String generateRandomNumbers(int length) {
+ RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder().withinRange(48, 57)
+ .build();
+ return pwdGenerator.generate(length);
+ }
+
+ public String generateRandomCharacters(int length) {
+ RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder().withinRange(48, 57)
+ .build();
+ return pwdGenerator.generate(length);
+ }
+
+ public String generateRandomAlphabet(int length, boolean lowerCase) {
+ int low;
+ int hi;
+ if (lowerCase) {
+ low = 97;
+ hi = 122;
+ } else {
+ low = 65;
+ hi = 90;
+ }
+ RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder().withinRange(low, hi)
+ .build();
+ return pwdGenerator.generate(length);
+ }
+
+ public Stream getRandomAlphabets(int count, boolean upperCase) {
+ IntStream characters = null;
+ if (upperCase) {
+ characters = random.ints(count, 65, 90);
+ } else {
+ characters = random.ints(count, 97, 122);
+ }
+ return characters.mapToObj(data -> (char) data);
+ }
+
+ public Stream getRandomNumbers(int count) {
+ IntStream numbers = random.ints(count, 48, 57);
+ return numbers.mapToObj(data -> (char) data);
+ }
+
+ public Stream getRandomSpecialChars(int count) {
+ IntStream specialChars = random.ints(count, 33, 45);
+ return specialChars.mapToObj(data -> (char) data);
+ }
+}
diff --git a/java-strings/src/test/java/com/baeldung/string/password/StringPasswordUnitTest.java b/java-strings/src/test/java/com/baeldung/string/password/StringPasswordUnitTest.java
new file mode 100644
index 0000000000..bfd4b0fe8e
--- /dev/null
+++ b/java-strings/src/test/java/com/baeldung/string/password/StringPasswordUnitTest.java
@@ -0,0 +1,64 @@
+package com.baeldung.string.password;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Examples of passwords conforming to various specifications, using different libraries.
+ *
+ */
+public class StringPasswordUnitTest {
+
+ RandomPasswordGenerator passGen = new RandomPasswordGenerator();
+
+ @Test
+ public void whenPasswordGeneratedUsingPassay_thenSuccessful() {
+ String password = passGen.generatePassayPassword();
+ int specialCharCount = 0;
+ for (char c : password.toCharArray()) {
+ if (c >= 33 || c <= 47) {
+ specialCharCount++;
+ }
+ }
+ assertTrue("Password validation failed in Passay", specialCharCount >= 2);
+ }
+
+ @Test
+ public void whenPasswordGeneratedUsingCommonsText_thenSuccessful() {
+ RandomPasswordGenerator passGen = new RandomPasswordGenerator();
+ String password = passGen.generateCommonTextPassword();
+ int lowerCaseCount = 0;
+ for (char c : password.toCharArray()) {
+ if (c >= 97 || c <= 122) {
+ lowerCaseCount++;
+ }
+ }
+ assertTrue("Password validation failed in commons-text ", lowerCaseCount >= 2);
+ }
+
+ @Test
+ public void whenPasswordGeneratedUsingCommonsLang3_thenSuccessful() {
+ String password = passGen.generateCommonsLang3Password();
+ int numCount = 0;
+ for (char c : password.toCharArray()) {
+ if (c >= 48 || c <= 57) {
+ numCount++;
+ }
+ }
+ assertTrue("Password validation failed in commons-lang3", numCount >= 2);
+ }
+
+ @Test
+ public void whenPasswordGeneratedUsingSecureRandom_thenSuccessful() {
+ String password = passGen.generateSecureRandomPassword();
+ int specialCharCount = 0;
+ for (char c : password.toCharArray()) {
+ if (c >= 33 || c <= 47) {
+ specialCharCount++;
+ }
+ }
+ assertTrue("Password validation failed in Secure Random", specialCharCount >= 2);
+ }
+
+}
diff --git a/javaxval/README.md b/javaxval/README.md
index 3153546c7d..3a975022ad 100644
--- a/javaxval/README.md
+++ b/javaxval/README.md
@@ -9,3 +9,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Java Bean Validation Basics](http://www.baeldung.com/javax-validation)
- [Validating Container Elements with Bean Validation 2.0](http://www.baeldung.com/bean-validation-container-elements)
- [Method Constraints with Bean Validation 2.0](http://www.baeldung.com/javax-validation-method-constraints)
+- [Difference Between @NotNull, @NotEmpty, and @NotBlank Constraints in Bean Validation](https://www.baeldung.com/java-bean-validation-not-null-empty-blank)
diff --git a/javaxval/pom.xml b/javaxval/pom.xml
index 63cb4c1d1d..0263fb68af 100644
--- a/javaxval/pom.xml
+++ b/javaxval/pom.xml
@@ -33,7 +33,7 @@
${javax.el-api.version}
- org.glassfish.web
+ org.glassfish
javax.el
${javax.el.version}
@@ -63,11 +63,11 @@
2.0.1.Final
- 6.0.7.Final
+ 6.0.13.Final
3.0.0
- 2.2.6
+ 3.0.0
5.0.2.RELEASE
4.12
3.11.1
-
\ No newline at end of file
+
diff --git a/jee-7-security/README.md b/jee-7-security/README.md
new file mode 100644
index 0000000000..314de6d957
--- /dev/null
+++ b/jee-7-security/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Securing Java EE with Spring Security](http://www.baeldung.com/java-ee-spring-security)
diff --git a/jee-7-security/pom.xml b/jee-7-security/pom.xml
new file mode 100644
index 0000000000..622ca19903
--- /dev/null
+++ b/jee-7-security/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+ jee-7-security
+ 1.0-SNAPSHOT
+ war
+ jee-7-security
+ JavaEE 7 Spring Security Application
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ javax
+ javaee-api
+ ${javaee_api.version}
+ provided
+
+
+ com.sun.faces
+ jsf-api
+ ${com.sun.faces.jsf.version}
+
+
+ com.sun.faces
+ jsf-impl
+ ${com.sun.faces.jsf.version}
+
+
+ javax.servlet
+ jstl
+ ${jstl.version}
+
+
+ javax.servlet
+ javax.servlet-api
+ ${javax.servlet-api.version}
+
+
+ javax.servlet.jsp
+ jsp-api
+ ${jsp-api.version}
+ provided
+
+
+ taglibs
+ standard
+ ${taglibs.standard.version}
+
+
+
+ javax.mvc
+ javax.mvc-api
+ 1.0-pr
+
+
+
+ org.springframework.security
+ spring-security-web
+ ${org.springframework.security.version}
+
+
+
+ org.springframework.security
+ spring-security-config
+ ${org.springframework.security.version}
+
+
+ org.springframework.security
+ spring-security-taglibs
+ ${org.springframework.security.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ ${maven-war-plugin.version}
+
+ src/main/webapp
+ false
+
+
+
+
+
+
+ 7.0
+ 2.2.14
+ 2.2
+ 1.1.2
+ 4.2.3.RELEASE
+
+
+
diff --git a/jee-7/src/main/java/com/baeldung/springSecurity/SecurityWebApplicationInitializer.java b/jee-7-security/src/main/java/com/baeldung/springsecurity/SecurityWebApplicationInitializer.java
similarity index 88%
rename from jee-7/src/main/java/com/baeldung/springSecurity/SecurityWebApplicationInitializer.java
rename to jee-7-security/src/main/java/com/baeldung/springsecurity/SecurityWebApplicationInitializer.java
index e6a05f7b71..e3e2ed80e6 100644
--- a/jee-7/src/main/java/com/baeldung/springSecurity/SecurityWebApplicationInitializer.java
+++ b/jee-7-security/src/main/java/com/baeldung/springsecurity/SecurityWebApplicationInitializer.java
@@ -1,4 +1,4 @@
-package com.baeldung.springSecurity;
+package com.baeldung.springsecurity;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
diff --git a/jee-7/src/main/java/com/baeldung/springSecurity/SpringSecurityConfig.java b/jee-7-security/src/main/java/com/baeldung/springsecurity/SpringSecurityConfig.java
similarity index 97%
rename from jee-7/src/main/java/com/baeldung/springSecurity/SpringSecurityConfig.java
rename to jee-7-security/src/main/java/com/baeldung/springsecurity/SpringSecurityConfig.java
index bda8930f36..70be1f91ce 100644
--- a/jee-7/src/main/java/com/baeldung/springSecurity/SpringSecurityConfig.java
+++ b/jee-7-security/src/main/java/com/baeldung/springsecurity/SpringSecurityConfig.java
@@ -1,4 +1,4 @@
-package com.baeldung.springSecurity;
+package com.baeldung.springsecurity;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
diff --git a/jee-7/src/main/java/com/baeldung/springSecurity/controller/HomeController.java b/jee-7-security/src/main/java/com/baeldung/springsecurity/controller/HomeController.java
similarity index 89%
rename from jee-7/src/main/java/com/baeldung/springSecurity/controller/HomeController.java
rename to jee-7-security/src/main/java/com/baeldung/springsecurity/controller/HomeController.java
index 53fd9f4b81..1662f38609 100644
--- a/jee-7/src/main/java/com/baeldung/springSecurity/controller/HomeController.java
+++ b/jee-7-security/src/main/java/com/baeldung/springsecurity/controller/HomeController.java
@@ -1,4 +1,4 @@
-package com.baeldung.springSecurity.controller;
+package com.baeldung.springsecurity.controller;
import javax.mvc.annotation.Controller;
import javax.ws.rs.GET;
diff --git a/jee-7/src/main/java/com/baeldung/springSecurity/controller/LoginController.java b/jee-7-security/src/main/java/com/baeldung/springsecurity/controller/LoginController.java
similarity index 82%
rename from jee-7/src/main/java/com/baeldung/springSecurity/controller/LoginController.java
rename to jee-7-security/src/main/java/com/baeldung/springsecurity/controller/LoginController.java
index a7e7bb471d..45d7ff3d2c 100644
--- a/jee-7/src/main/java/com/baeldung/springSecurity/controller/LoginController.java
+++ b/jee-7-security/src/main/java/com/baeldung/springsecurity/controller/LoginController.java
@@ -1,4 +1,4 @@
-package com.baeldung.springSecurity.controller;
+package com.baeldung.springsecurity.controller;
import javax.mvc.annotation.Controller;
import javax.ws.rs.GET;
diff --git a/jee-7-security/src/main/resources/logback.xml b/jee-7-security/src/main/resources/logback.xml
new file mode 100644
index 0000000000..c8c077ba1d
--- /dev/null
+++ b/jee-7-security/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jee-7-security/src/main/webapp/WEB-INF/beans.xml b/jee-7-security/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/jee-7-security/src/main/webapp/WEB-INF/faces-config.xml b/jee-7-security/src/main/webapp/WEB-INF/faces-config.xml
new file mode 100644
index 0000000000..1f4085458f
--- /dev/null
+++ b/jee-7-security/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/jee-7/src/main/webapp/WEB-INF/spring/security.xml b/jee-7-security/src/main/webapp/WEB-INF/spring/security.xml
similarity index 100%
rename from jee-7/src/main/webapp/WEB-INF/spring/security.xml
rename to jee-7-security/src/main/webapp/WEB-INF/spring/security.xml
diff --git a/jee-7/src/main/webapp/WEB-INF/views/admin.jsp b/jee-7-security/src/main/webapp/WEB-INF/views/admin.jsp
similarity index 100%
rename from jee-7/src/main/webapp/WEB-INF/views/admin.jsp
rename to jee-7-security/src/main/webapp/WEB-INF/views/admin.jsp
diff --git a/jee-7/src/main/webapp/WEB-INF/views/home.jsp b/jee-7-security/src/main/webapp/WEB-INF/views/home.jsp
similarity index 100%
rename from jee-7/src/main/webapp/WEB-INF/views/home.jsp
rename to jee-7-security/src/main/webapp/WEB-INF/views/home.jsp
diff --git a/jee-7/src/main/webapp/WEB-INF/views/login.jsp b/jee-7-security/src/main/webapp/WEB-INF/views/login.jsp
similarity index 100%
rename from jee-7/src/main/webapp/WEB-INF/views/login.jsp
rename to jee-7-security/src/main/webapp/WEB-INF/views/login.jsp
diff --git a/jee-7/src/main/webapp/WEB-INF/views/user.jsp b/jee-7-security/src/main/webapp/WEB-INF/views/user.jsp
similarity index 100%
rename from jee-7/src/main/webapp/WEB-INF/views/user.jsp
rename to jee-7-security/src/main/webapp/WEB-INF/views/user.jsp
diff --git a/jee-7-security/src/main/webapp/WEB-INF/web.xml b/jee-7-security/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..e656ffc5be
--- /dev/null
+++ b/jee-7-security/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ Faces Servlet
+ javax.faces.webapp.FacesServlet
+
+
+ Faces Servlet
+ *.jsf
+
+
+ javax.faces.PROJECT_STAGE
+ Development
+
+
+ State saving method: 'client' or 'server' (default). See JSF Specification section 2.5.2
+ javax.faces.STATE_SAVING_METHOD
+ client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ index.jsf
+ welcome.jsf
+ index.html
+ index.jsp
+
+
\ No newline at end of file
diff --git a/jee-7/src/main/webapp/index.jsp b/jee-7-security/src/main/webapp/index.jsp
similarity index 100%
rename from jee-7/src/main/webapp/index.jsp
rename to jee-7-security/src/main/webapp/index.jsp
diff --git a/jee-7/src/main/webapp/secure.jsp b/jee-7-security/src/main/webapp/secure.jsp
similarity index 100%
rename from jee-7/src/main/webapp/secure.jsp
rename to jee-7-security/src/main/webapp/secure.jsp
diff --git a/jee-7/README.md b/jee-7/README.md
index f0bd65fdf2..a2493e561b 100644
--- a/jee-7/README.md
+++ b/jee-7/README.md
@@ -5,5 +5,3 @@
- [Introduction to JAX-WS](http://www.baeldung.com/jax-ws)
- [A Guide to Java EE Web-Related Annotations](http://www.baeldung.com/javaee-web-annotations)
- [Introduction to Testing with Arquillian](http://www.baeldung.com/arquillian)
-- [Securing Java EE with Spring Security](http://www.baeldung.com/java-ee-spring-security)
-- [A Guide to Java EE Web-Related Annotations](https://www.baeldung.com/javaee-web-annotations)
\ No newline at end of file
diff --git a/jee-7/src/main/java/com/baeldung/springSecurity/ApplicationConfig.java b/jee-7/src/main/java/com/baeldung/springSecurity/ApplicationConfig.java
deleted file mode 100755
index f8e7982253..0000000000
--- a/jee-7/src/main/java/com/baeldung/springSecurity/ApplicationConfig.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.baeldung.springSecurity;
-
-import javax.ws.rs.ApplicationPath;
-import javax.ws.rs.core.Application;
-
-/**
- * Application class required by JAX-RS. If you don't want to have any
- * prefix in the URL, you can set the application path to "/".
- */
-@ApplicationPath("/")
-public class ApplicationConfig extends Application {
-
-}
diff --git a/jee-7/src/main/webapp/WEB-INF/web.xml b/jee-7/src/main/webapp/WEB-INF/web.xml
index 1bcbb96e24..e656ffc5be 100644
--- a/jee-7/src/main/webapp/WEB-INF/web.xml
+++ b/jee-7/src/main/webapp/WEB-INF/web.xml
@@ -1,5 +1,8 @@
-
+
-
- org.apache.crunch
- crunch-core
- ${org.apache.crunch.crunch-core.version}
-
-
- org.apache.hadoop
- hadoop-client
- ${org.apache.hadoop.hadoop-client}
- provided
-
+
+ org.apache.crunch
+ crunch-core
+ ${org.apache.crunch.crunch-core.version}
+
+
+ org.apache.hadoop
+ hadoop-client
+ ${org.apache.hadoop.hadoop-client}
+ provided
+
-
- commons-cli
- commons-cli
- 1.2
- provided
-
-
- commons-io
- commons-io
- 2.1
- provided
-
-
- commons-httpclient
- commons-httpclient
- 3.0.1
- provided
-
-
- commons-codec
- commons-codec
-
-
-
+
+ commons-cli
+ commons-cli
+ 1.2
+ provided
+
+
+ commons-io
+ commons-io
+ 2.1
+ provided
+
+
+ commons-httpclient
+ commons-httpclient
+ 3.0.1
+ provided
+
+
+ commons-codec
+ commons-codec
+
+
+
org.apache.flink
flink-connector-kafka-0.11_2.11
@@ -249,7 +249,32 @@
${awaitility.version}
test
+
+ io.ebean
+ ebean
+ ${ebean.version}
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+ ch.qos.logback
+ logback-core
+ ${logback.version}
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j.version}
+
@@ -354,31 +379,48 @@
-
- org.apache.maven.plugins
- maven-assembly-plugin
- 2.3
-
-
- src/main/assembly/hadoop-job.xml
-
-
-
- com.baeldung.crunch.WordCount
-
-
-
-
-
- make-assembly
- package
-
- single
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.3
+
+
+ src/main/assembly/hadoop-job.xml
+
+
+
+ com.baeldung.crunch.WordCount
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+ io.ebean
+ ebean-maven-plugin
+ 11.11.2
+
+
+
+ main
+ process-classes
+
+ debug=1
+
+
+ enhance
+
+
+
+
@@ -415,7 +457,10 @@
5.0.4
1.6.0.1
0.15.0
- 2.2.0
+ 2.2.0
+ 11.22.4
+ 1.7.25
+ 1.0.1
diff --git a/libraries-data/src/main/java/com/baeldung/ebean/app/App.java b/libraries-data/src/main/java/com/baeldung/ebean/app/App.java
new file mode 100644
index 0000000000..44a4fa8562
--- /dev/null
+++ b/libraries-data/src/main/java/com/baeldung/ebean/app/App.java
@@ -0,0 +1,75 @@
+package com.baeldung.ebean.app;
+
+import java.util.Arrays;
+
+import com.baeldung.ebean.model.Address;
+import com.baeldung.ebean.model.Customer;
+
+import io.ebean.Ebean;
+import io.ebean.EbeanServer;
+import io.ebean.annotation.Transactional;
+
+public class App {
+
+ public static void main(String[] args) {
+ insertAndDeleteInsideTransaction();
+ crudOperations();
+ queryCustomers();
+ }
+
+ @Transactional
+ public static void insertAndDeleteInsideTransaction() {
+
+ Customer c1 = getCustomer();
+ EbeanServer server = Ebean.getDefaultServer();
+ server.save(c1);
+ Customer foundC1 = server.find(Customer.class, c1.getId());
+ server.delete(foundC1);
+ }
+
+ public static void crudOperations() {
+
+ Address a1 = new Address("5, Wide Street", null, "New York");
+ Customer c1 = new Customer("John Wide", a1);
+
+ EbeanServer server = Ebean.getDefaultServer();
+ server.save(c1);
+
+ c1.setName("Jane Wide");
+ c1.setAddress(null);
+ server.save(c1);
+
+ Customer foundC1 = Ebean.find(Customer.class, c1.getId());
+
+ Ebean.delete(foundC1);
+ }
+
+ public static void queryCustomers() {
+ Address a1 = new Address("1, Big Street", null, "New York");
+ Customer c1 = new Customer("Big John", a1);
+
+ Address a2 = new Address("2, Big Street", null, "New York");
+ Customer c2 = new Customer("Big John", a2);
+
+ Address a3 = new Address("3, Big Street", null, "San Jose");
+ Customer c3 = new Customer("Big Bob", a3);
+
+ Ebean.saveAll(Arrays.asList(c1, c2, c3));
+
+ Customer customer = Ebean.find(Customer.class)
+ .select("name")
+ .fetch("address", "city")
+ .where()
+ .eq("city", "San Jose")
+ .findOne();
+
+ Ebean.deleteAll(Arrays.asList(c1, c2, c3));
+ }
+
+ private static Customer getCustomer() {
+ Address a1 = new Address("1, Big Street", null, "New York");
+ Customer c1 = new Customer("Big John", a1);
+ return c1;
+ }
+
+}
diff --git a/libraries-data/src/main/java/com/baeldung/ebean/app/App2.java b/libraries-data/src/main/java/com/baeldung/ebean/app/App2.java
new file mode 100644
index 0000000000..fba77007c6
--- /dev/null
+++ b/libraries-data/src/main/java/com/baeldung/ebean/app/App2.java
@@ -0,0 +1,26 @@
+package com.baeldung.ebean.app;
+
+import java.util.Properties;
+
+import io.ebean.EbeanServer;
+import io.ebean.EbeanServerFactory;
+import io.ebean.config.ServerConfig;
+
+public class App2 {
+
+ public static void main(String[] args) {
+ ServerConfig cfg = new ServerConfig();
+ cfg.setDefaultServer(true);
+ Properties properties = new Properties();
+ properties.put("ebean.db.ddl.generate", "true");
+ properties.put("ebean.db.ddl.run", "true");
+ properties.put("datasource.db.username", "sa");
+ properties.put("datasource.db.password", "");
+ properties.put("datasource.db.databaseUrl", "jdbc:h2:mem:app2");
+ properties.put("datasource.db.databaseDriver", "org.h2.Driver");
+ cfg.loadFromProperties(properties);
+ EbeanServer server = EbeanServerFactory.create(cfg);
+
+ }
+
+}
diff --git a/libraries-data/src/main/java/com/baeldung/ebean/model/Address.java b/libraries-data/src/main/java/com/baeldung/ebean/model/Address.java
new file mode 100644
index 0000000000..dfcd90ffa7
--- /dev/null
+++ b/libraries-data/src/main/java/com/baeldung/ebean/model/Address.java
@@ -0,0 +1,48 @@
+package com.baeldung.ebean.model;
+
+import javax.persistence.Entity;
+
+@Entity
+public class Address extends BaseModel {
+
+ public Address(String addressLine1, String addressLine2, String city) {
+ super();
+ this.addressLine1 = addressLine1;
+ this.addressLine2 = addressLine2;
+ this.city = city;
+ }
+
+ private String addressLine1;
+ private String addressLine2;
+ private String city;
+
+ public String getAddressLine1() {
+ return addressLine1;
+ }
+
+ public void setAddressLine1(String addressLine1) {
+ this.addressLine1 = addressLine1;
+ }
+
+ public String getAddressLine2() {
+ return addressLine2;
+ }
+
+ public void setAddressLine2(String addressLine2) {
+ this.addressLine2 = addressLine2;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ @Override
+ public String toString() {
+ return "Address [id=" + id + ", addressLine1=" + addressLine1 + ", addressLine2=" + addressLine2 + ", city=" + city + "]";
+ }
+
+}
diff --git a/libraries-data/src/main/java/com/baeldung/ebean/model/BaseModel.java b/libraries-data/src/main/java/com/baeldung/ebean/model/BaseModel.java
new file mode 100644
index 0000000000..547d5bf075
--- /dev/null
+++ b/libraries-data/src/main/java/com/baeldung/ebean/model/BaseModel.java
@@ -0,0 +1,59 @@
+package com.baeldung.ebean.model;
+
+import java.time.Instant;
+
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Version;
+
+import io.ebean.annotation.WhenCreated;
+import io.ebean.annotation.WhenModified;
+
+@MappedSuperclass
+public abstract class BaseModel {
+
+ @Id
+ protected long id;
+
+ @Version
+ protected long version;
+
+ @WhenCreated
+ protected Instant createdOn;
+
+ @WhenModified
+ protected Instant modifiedOn;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public Instant getCreatedOn() {
+ return createdOn;
+ }
+
+ public void setCreatedOn(Instant createdOn) {
+ this.createdOn = createdOn;
+ }
+
+ public Instant getModifiedOn() {
+ return modifiedOn;
+ }
+
+ public void setModifiedOn(Instant modifiedOn) {
+ this.modifiedOn = modifiedOn;
+ }
+
+ public long getVersion() {
+ return version;
+ }
+
+ public void setVersion(long version) {
+ this.version = version;
+ }
+
+}
diff --git a/libraries-data/src/main/java/com/baeldung/ebean/model/Customer.java b/libraries-data/src/main/java/com/baeldung/ebean/model/Customer.java
new file mode 100644
index 0000000000..4dd629245a
--- /dev/null
+++ b/libraries-data/src/main/java/com/baeldung/ebean/model/Customer.java
@@ -0,0 +1,42 @@
+package com.baeldung.ebean.model;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToOne;
+
+@Entity
+public class Customer extends BaseModel {
+
+ public Customer(String name, Address address) {
+ super();
+ this.name = name;
+ this.address = address;
+ }
+
+ private String name;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ Address address;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ @Override
+ public String toString() {
+ return "Customer [id=" + id + ", name=" + name + ", address=" + address + "]";
+ }
+
+}
diff --git a/libraries-data/src/main/resources/ebean.mf b/libraries-data/src/main/resources/ebean.mf
new file mode 100644
index 0000000000..f49fecc717
--- /dev/null
+++ b/libraries-data/src/main/resources/ebean.mf
@@ -0,0 +1,3 @@
+entity-packages: com.baeldung.ebean.model
+transactional-packages: com.baeldung.ebean.app
+querybean-packages: com.baeldung.ebean.app
diff --git a/libraries-data/src/main/resources/ebean.properties b/libraries-data/src/main/resources/ebean.properties
new file mode 100644
index 0000000000..9cc5cc170a
--- /dev/null
+++ b/libraries-data/src/main/resources/ebean.properties
@@ -0,0 +1,7 @@
+ebean.db.ddl.generate=true
+ebean.db.ddl.run=true
+
+datasource.db.username=sa
+datasource.db.password=
+datasource.db.databaseUrl=jdbc:h2:mem:customer
+datasource.db.databaseDriver=org.h2.Driver
diff --git a/libraries-data/src/main/resources/logback.xml b/libraries-data/src/main/resources/logback.xml
index 7d900d8ea8..a57d22fcb2 100644
--- a/libraries-data/src/main/resources/logback.xml
+++ b/libraries-data/src/main/resources/logback.xml
@@ -6,7 +6,9 @@
-
+
+
+
diff --git a/libraries-security/README.md b/libraries-security/README.md
new file mode 100644
index 0000000000..c42e91a888
--- /dev/null
+++ b/libraries-security/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Guide to ScribeJava](https://www.baeldung.com/scribejava)
diff --git a/libraries/README.md b/libraries/README.md
index c2c4b2718a..fcf687d806 100644
--- a/libraries/README.md
+++ b/libraries/README.md
@@ -81,6 +81,8 @@
- [Guide to Resilience4j](http://www.baeldung.com/resilience4j)
- [Parsing YAML with SnakeYAML](http://www.baeldung.com/java-snake-yaml)
- [Guide to JMapper](http://www.baeldung.com/jmapper)
+- [An Introduction to Apache Commons Lang 3](https://www.baeldung.com/java-commons-lang-3)
+- [Exactly Once Processing in Kafka](https://www.baeldung.com/kafka-exactly-once)
The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own.
diff --git a/libraries/pom.xml b/libraries/pom.xml
index 91c54b6113..8ffd33272d 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -358,6 +358,7 @@
org.codehaus.groovy
groovy-all
+ pom
${groovy.version}
@@ -710,6 +711,12 @@
${snakeyaml.version}
+
+ com.numericalmethod
+ suanshu
+ ${suanshu.version}
+
+
@@ -730,6 +737,12 @@
Apache Staging
https://repository.apache.org/content/groups/staging
+
+ nm-repo
+ Numerical Method's Maven Repository
+ http://repo.numericalmethod.com/maven/
+ default
+
@@ -834,6 +847,7 @@
+ 4.0.0
1.21
1.23.0
0.1.0
@@ -922,7 +936,7 @@
2.3.0
0.9.12
1.19
- 2.4.10
+ 2.5.2
1.1.0
3.9.0
2.0.4
diff --git a/libraries/src/main/java/com/baeldung/suanshu/SuanShuMath.java b/libraries/src/main/java/com/baeldung/suanshu/SuanShuMath.java
new file mode 100644
index 0000000000..46af24692d
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/suanshu/SuanShuMath.java
@@ -0,0 +1,142 @@
+package com.baeldung.suanshu;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.Matrix;
+import com.numericalmethod.suanshu.algebra.linear.vector.doubles.Vector;
+import com.numericalmethod.suanshu.algebra.linear.vector.doubles.dense.DenseVector;
+import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix;
+import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.operation.Inverse;
+import com.numericalmethod.suanshu.analysis.function.polynomial.Polynomial;
+import com.numericalmethod.suanshu.analysis.function.polynomial.root.PolyRoot;
+import com.numericalmethod.suanshu.analysis.function.polynomial.root.PolyRootSolver;
+import com.numericalmethod.suanshu.number.complex.Complex;
+
+class SuanShuMath {
+
+ private static final Logger log = LoggerFactory.getLogger(SuanShuMath.class);
+
+ public static void main(String[] args) throws Exception {
+ SuanShuMath math = new SuanShuMath();
+
+ math.addingVectors();
+ math.scaleVector();
+ math.innerProductVectors();
+ math.addingIncorrectVectors();
+
+ math.addingMatrices();
+ math.multiplyMatrices();
+ math.multiplyIncorrectMatrices();
+ math.inverseMatrix();
+
+ Polynomial p = math.createPolynomial();
+ math.evaluatePolynomial(p);
+ math.solvePolynomial();
+ }
+
+ public void addingVectors() throws Exception {
+ Vector v1 = new DenseVector(new double[]{1, 2, 3, 4, 5});
+ Vector v2 = new DenseVector(new double[]{5, 4, 3, 2, 1});
+ Vector v3 = v1.add(v2);
+ log.info("Adding vectors: {}", v3);
+ }
+
+ public void scaleVector() throws Exception {
+ Vector v1 = new DenseVector(new double[]{1, 2, 3, 4, 5});
+ Vector v2 = v1.scaled(2.0);
+ log.info("Scaling a vector: {}", v2);
+ }
+
+ public void innerProductVectors() throws Exception {
+ Vector v1 = new DenseVector(new double[]{1, 2, 3, 4, 5});
+ Vector v2 = new DenseVector(new double[]{5, 4, 3, 2, 1});
+ double inner = v1.innerProduct(v2);
+ log.info("Vector inner product: {}", inner);
+ }
+
+ public void addingIncorrectVectors() throws Exception {
+ Vector v1 = new DenseVector(new double[]{1, 2, 3});
+ Vector v2 = new DenseVector(new double[]{5, 4});
+ Vector v3 = v1.add(v2);
+ log.info("Adding vectors: {}", v3);
+ }
+
+ public void addingMatrices() throws Exception {
+ Matrix m1 = new DenseMatrix(new double[][]{
+ {1, 2, 3},
+ {4, 5, 6}
+ });
+
+ Matrix m2 = new DenseMatrix(new double[][]{
+ {3, 2, 1},
+ {6, 5, 4}
+ });
+
+ Matrix m3 = m1.add(m2);
+ log.info("Adding matrices: {}", m3);
+ }
+
+ public void multiplyMatrices() throws Exception {
+ Matrix m1 = new DenseMatrix(new double[][]{
+ {1, 2, 3},
+ {4, 5, 6}
+ });
+
+ Matrix m2 = new DenseMatrix(new double[][]{
+ {1, 4},
+ {2, 5},
+ {3, 6}
+ });
+
+ Matrix m3 = m1.multiply(m2);
+ log.info("Multiplying matrices: {}", m3);
+ }
+
+ public void multiplyIncorrectMatrices() throws Exception {
+ Matrix m1 = new DenseMatrix(new double[][]{
+ {1, 2, 3},
+ {4, 5, 6}
+ });
+
+ Matrix m2 = new DenseMatrix(new double[][]{
+ {3, 2, 1},
+ {6, 5, 4}
+ });
+
+ Matrix m3 = m1.multiply(m2);
+ log.info("Multiplying matrices: {}", m3);
+ }
+
+ public void inverseMatrix() {
+ Matrix m1 = new DenseMatrix(new double[][]{
+ {1, 2},
+ {3, 4}
+ });
+
+ Inverse m2 = new Inverse(m1);
+ log.info("Inverting a matrix: {}", m2);
+ log.info("Verifying a matrix inverse: {}", m1.multiply(m2));
+ }
+
+ public Polynomial createPolynomial() {
+ return new Polynomial(new double[]{3, -5, 1});
+ }
+
+ public void evaluatePolynomial(Polynomial p) {
+ // Evaluate using a real number
+ log.info("Evaluating a polynomial using a real number: {}", p.evaluate(5));
+ // Evaluate using a complex number
+ log.info("Evaluating a polynomial using a complex number: {}", p.evaluate(new Complex(1, 2)));
+ }
+
+ public void solvePolynomial() {
+ Polynomial p = new Polynomial(new double[]{2, 2, -4});
+ PolyRootSolver solver = new PolyRoot();
+ List extends Number> roots = solver.solve(p);
+ log.info("Finding polynomial roots: {}", roots);
+ }
+
+}
diff --git a/libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsUnitTest.java b/libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsManualTest.java
similarity index 86%
rename from libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsUnitTest.java
rename to libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsManualTest.java
index 0efe97f912..cb45ebc24d 100644
--- a/libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsUnitTest.java
+++ b/libraries/src/test/java/com/baeldung/commons/lang3/test/SystemsUtilsManualTest.java
@@ -6,8 +6,10 @@ import org.apache.commons.lang3.SystemUtils;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
-public class SystemsUtilsUnitTest {
+public class SystemsUtilsManualTest {
+ // the paths depend on the OS and installed version of Java
+
@Test
public void givenSystemUtilsClass_whenCalledgetJavaHome_thenCorrect() {
assertThat(SystemUtils.getJavaHome()).isEqualTo(new File("/usr/lib/jvm/java-8-oracle/jre"));
diff --git a/logging-modules/log4j2/${sys b/logging-modules/log4j2/${sys
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lombok/pom.xml b/lombok/pom.xml
index eba140122a..7ad2e3dc83 100644
--- a/lombok/pom.xml
+++ b/lombok/pom.xml
@@ -59,6 +59,7 @@
${project.basedir}/src/main/java
+ ${project.build.directory}/delombok
false
skip
diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/defaultvalue/Pojo.java b/lombok/src/main/java/com/baeldung/lombok/builder/defaultvalue/Pojo.java
new file mode 100644
index 0000000000..feaade9cd5
--- /dev/null
+++ b/lombok/src/main/java/com/baeldung/lombok/builder/defaultvalue/Pojo.java
@@ -0,0 +1,17 @@
+package com.baeldung.lombok.builder.defaultvalue;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Builder(toBuilder = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class Pojo {
+ private String name = "foo";
+ private boolean original = true;
+}
diff --git a/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java b/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java
new file mode 100644
index 0000000000..d9184f605c
--- /dev/null
+++ b/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java
@@ -0,0 +1,25 @@
+package com.baeldung.lombok.builder.defaultvalue;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BuilderWithDefaultValueUnitTest {
+
+ @Test
+ public void givenBuilderWithDefaultValue_ThanDefaultValueIsPresent() {
+ Pojo build = new Pojo().toBuilder()
+ .build();
+ Assert.assertEquals("foo", build.getName());
+ Assert.assertTrue(build.isOriginal());
+ }
+
+ @Test
+ public void givenBuilderWithDefaultValue_NoArgsWorksAlso() {
+ Pojo build = new Pojo().toBuilder()
+ .build();
+ Pojo pojo = new Pojo();
+ Assert.assertEquals(build.getName(), pojo.getName());
+ Assert.assertTrue(build.isOriginal() == pojo.isOriginal());
+ }
+
+}
diff --git a/maven/versions-maven-plugin/original/pom.xml b/maven/versions-maven-plugin/original/pom.xml
new file mode 100644
index 0000000000..295c77b860
--- /dev/null
+++ b/maven/versions-maven-plugin/original/pom.xml
@@ -0,0 +1,76 @@
+
+ 4.0.0
+ com.baeldung
+ versions-maven-plugin-example
+ 0.0.1-SNAPSHOT
+
+
+ 1.15
+
+
+
+
+
+ commons-io
+ commons-io
+ 2.3
+
+
+
+ org.apache.commons
+ commons-collections4
+ 4.0
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.0
+
+
+
+ org.apache.commons
+ commons-compress
+ ${commons-compress-version}
+
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.1-SNAPSHOT
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.7
+
+
+ org.apache.commons:commons-collections4
+
+
+
+
+
+
+
+
+ apache.snapshots
+ Apache Development Snapshot Repository
+ https://repository.apache.org/content/repositories/snapshots/
+
+ false
+
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/maven/versions-maven-plugin/pom.xml b/maven/versions-maven-plugin/pom.xml
new file mode 100644
index 0000000000..295c77b860
--- /dev/null
+++ b/maven/versions-maven-plugin/pom.xml
@@ -0,0 +1,76 @@
+
+ 4.0.0
+ com.baeldung
+ versions-maven-plugin-example
+ 0.0.1-SNAPSHOT
+
+
+ 1.15
+
+
+
+
+
+ commons-io
+ commons-io
+ 2.3
+
+
+
+ org.apache.commons
+ commons-collections4
+ 4.0
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.0
+
+
+
+ org.apache.commons
+ commons-compress
+ ${commons-compress-version}
+
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.1-SNAPSHOT
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.7
+
+
+ org.apache.commons:commons-collections4
+
+
+
+
+
+
+
+
+ apache.snapshots
+ Apache Development Snapshot Repository
+ https://repository.apache.org/content/repositories/snapshots/
+
+ false
+
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/maven/versions-maven-plugin/run-the-demo.sh b/maven/versions-maven-plugin/run-the-demo.sh
new file mode 100755
index 0000000000..89ca871e01
--- /dev/null
+++ b/maven/versions-maven-plugin/run-the-demo.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+#function to display commands
+exe() { echo -e "\$ $@\n" ; "$@" ; }
+
+TEXT_COLOR='\033[1;33m' #Yellow
+NO_COLOR='\033[0m' # No Color
+
+clear
+
+echo -e "======================================================================================"
+echo -e " Showcase for the BAELDUNG tutorial \"Use the latest version of a dependency in Maven\""
+echo -e " Author: Andrea Ligios"
+echo -e "======================================================================================"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Resetting the demo environment (which will be altered during the run): "
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+rm -f pom.xml.versionsBackup
+cp original/pom.xml pom.xml
+ls -lt pom.*
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Checking for newer versions of the Maven dependencies:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:display-dependency-updates
+echo
+read -p "Press enter to continue"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Updating SNAPSHOT dependencies to their RELEASE version, if any:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:use-releases
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " A backup has been created automatically:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+ls -lt pom.*
+echo
+read -p "Press enter to continue"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Updating RELEASE dependencies to their *next* RELEASE version:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:use-next-releases
+echo
+read -p "Press enter to continue"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Reverting every modification made since the beginning:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:revert
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " The backup is gone, and the pom.xml contains the initial dependencies:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+ls -lt pom.*
+echo
+read -p "Press enter to continue"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Updating RELEASE dependencies to their *latest* RELEASE version:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:use-latest-releases
+echo
+read -p "Press enter to continue"
+
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " Committing the modifications to pom.xml:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+exe mvn versions:commit
+echo -e "${TEXT_COLOR}\n--------------------------------------------------------------------------------------"
+echo -e " The backup is gone, and the pom.xml contains the latest dependencies:"
+echo -e "--------------------------------------------------------------------------------------${NO_COLOR}"
+ls -lt pom.*
+echo
+
+echo -e "${TEXT_COLOR}\nThat's all folks!${NO_COLOR}\n"
diff --git a/parent-boot-1/pom.xml b/parent-boot-1/pom.xml
index 7742841d07..d220b4a6b7 100644
--- a/parent-boot-1/pom.xml
+++ b/parent-boot-1/pom.xml
@@ -17,7 +17,7 @@
org.springframework.boot
spring-boot-dependencies
- 1.5.15.RELEASE
+ 1.5.16.RELEASE
pom
import
diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml
index 5981bf41e0..bee3d683b8 100644
--- a/persistence-modules/spring-data-redis/pom.xml
+++ b/persistence-modules/spring-data-redis/pom.xml
@@ -7,17 +7,61 @@
jar
+ parent-boot-2
com.baeldung
- parent-spring-5
0.0.1-SNAPSHOT
- ../../parent-spring-5
+ ../../parent-boot-2
- org.springframework.data
- spring-data-redis
- ${spring-data-redis}
+ org.springframework.boot
+ spring-boot-starter-data-redis-reactive
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+
+
+ io.projectreactor
+ reactor-test
+ test
+
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.platform
+ junit-platform-surefire-provider
+ ${junit.platform.version}
+ test
+
+
+ org.junit.platform
+ junit-platform-runner
+ ${junit.platform.version}
+ test
@@ -33,42 +77,12 @@
jar
-
- org.springframework
- spring-core
- ${spring.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
-
- org.springframework
- spring-context
- ${spring.version}
-
-
-
- org.springframework
- spring-test
- ${spring.version}
- test
-
-
com.lordofthejars
nosqlunit-redis
${nosqlunit.version}
-
- org.springframework.data
- spring-data-commons
- ${spring-data-commons.version}
-
com.github.kstyrc
embedded-redis
@@ -77,12 +91,13 @@
- 2.0.3.RELEASE
3.2.4
2.9.0
0.10.0
2.0.3.RELEASE
0.6
+ 1.0.0
+ 5.0.2
diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/SpringRedisReactiveApplication.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/SpringRedisReactiveApplication.java
new file mode 100644
index 0000000000..8b1f892f67
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/SpringRedisReactiveApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.data.reactive.redis;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringRedisReactiveApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringRedisReactiveApplication.class, args);
+ }
+
+}
diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/config/RedisConfig.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/config/RedisConfig.java
new file mode 100644
index 0000000000..d23d0092eb
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/config/RedisConfig.java
@@ -0,0 +1,56 @@
+package com.baeldung.spring.data.reactive.redis.config;
+
+
+import com.baeldung.spring.data.reactive.redis.model.Employee;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.ReactiveKeyCommands;
+import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
+import org.springframework.data.redis.connection.ReactiveStringCommands;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import javax.annotation.PreDestroy;
+
+@Configuration
+public class RedisConfig {
+
+ @Autowired
+ RedisConnectionFactory factory;
+
+ @Bean
+ public ReactiveRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
+ Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Employee.class);
+ RedisSerializationContext.RedisSerializationContextBuilder builder = RedisSerializationContext.newSerializationContext(new StringRedisSerializer());
+ RedisSerializationContext context = builder.value(serializer)
+ .build();
+ return new ReactiveRedisTemplate<>(factory, context);
+ }
+
+ @Bean
+ public ReactiveRedisTemplate reactiveRedisTemplateString(ReactiveRedisConnectionFactory connectionFactory) {
+ return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
+ }
+
+ @Bean
+ public ReactiveKeyCommands keyCommands(final ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
+ return reactiveRedisConnectionFactory.getReactiveConnection()
+ .keyCommands();
+ }
+
+ @Bean
+ public ReactiveStringCommands stringCommands(final ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
+ return reactiveRedisConnectionFactory.getReactiveConnection()
+ .stringCommands();
+ }
+
+ @PreDestroy
+ public void cleanRedis() {
+ factory.getConnection()
+ .flushDb();
+ }
+}
diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/model/Employee.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/model/Employee.java
new file mode 100644
index 0000000000..9178f6e112
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/model/Employee.java
@@ -0,0 +1,21 @@
+package com.baeldung.spring.data.reactive.redis.model;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Data
+@ToString
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode
+public class Employee implements Serializable {
+ private static final long serialVersionUID = 1603714798906422731L;
+ private String id;
+ private String name;
+ private String department;
+}
diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java
index 62a7886f46..6fdb3c5bef 100644
--- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java
+++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java
@@ -1,6 +1,8 @@
package com.baeldung.spring.data.redis.config;
-import org.springframework.beans.factory.annotation.Value;
+import com.baeldung.spring.data.redis.queue.MessagePublisher;
+import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
+import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@@ -13,10 +15,6 @@ import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
-import com.baeldung.spring.data.redis.queue.MessagePublisher;
-import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
-import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
-
@Configuration
@ComponentScan("com.baeldung.spring.data.redis")
@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo")
diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisKeyCommandsIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisKeyCommandsIntegrationTest.java
new file mode 100644
index 0000000000..e48aa1e06a
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisKeyCommandsIntegrationTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.spring.data.reactive.redis.template;
+
+
+import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
+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.data.redis.connection.ReactiveKeyCommands;
+import org.springframework.data.redis.connection.ReactiveStringCommands;
+import org.springframework.data.redis.connection.ReactiveStringCommands.SetCommand;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.nio.ByteBuffer;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
+public class RedisKeyCommandsIntegrationTest {
+
+ @Autowired
+ private ReactiveKeyCommands keyCommands;
+
+ @Autowired
+ private ReactiveStringCommands stringCommands;
+
+ @Test
+ public void givenFluxOfKeys_whenPerformOperations_thenPerformOperations() {
+ Flux keys = Flux.just("key1", "key2", "key3", "key4");
+
+ Flux generator = keys.map(String::getBytes)
+ .map(ByteBuffer::wrap)
+ .map(key -> SetCommand.set(key)
+ .value(key));
+
+ StepVerifier.create(stringCommands.set(generator))
+ .expectNextCount(4L)
+ .verifyComplete();
+
+ Mono keyCount = keyCommands.keys(ByteBuffer.wrap("key*".getBytes()))
+ .flatMapMany(Flux::fromIterable)
+ .count();
+
+ StepVerifier.create(keyCount)
+ .expectNext(4L)
+ .verifyComplete();
+
+ }
+}
diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateListOpsIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateListOpsIntegrationTest.java
new file mode 100644
index 0000000000..3ebeff87b1
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateListOpsIntegrationTest.java
@@ -0,0 +1,49 @@
+package com.baeldung.spring.data.reactive.redis.template;
+
+
+import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.ReactiveListOperations;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
+public class RedisTemplateListOpsIntegrationTest {
+
+ private static final String LIST_NAME = "demo_list";
+
+ @Autowired
+ private ReactiveRedisTemplate redisTemplate;
+
+ private ReactiveListOperations reactiveListOps;
+
+ @Before
+ public void setup() {
+ reactiveListOps = redisTemplate.opsForList();
+ }
+
+ @Test
+ public void givenListAndValues_whenLeftPushAndLeftPop_thenLeftPushAndLeftPop() {
+ Mono lPush = reactiveListOps.leftPushAll(LIST_NAME, "first", "second")
+ .log("Pushed");
+
+ StepVerifier.create(lPush)
+ .expectNext(2L)
+ .verifyComplete();
+
+ Mono lPop = reactiveListOps.leftPop(LIST_NAME)
+ .log("Popped");
+
+ StepVerifier.create(lPop)
+ .expectNext("second")
+ .verifyComplete();
+ }
+
+}
diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateValueOpsIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateValueOpsIntegrationTest.java
new file mode 100644
index 0000000000..9490568089
--- /dev/null
+++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateValueOpsIntegrationTest.java
@@ -0,0 +1,71 @@
+package com.baeldung.spring.data.reactive.redis.template;
+
+
+import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
+import com.baeldung.spring.data.reactive.redis.model.Employee;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.redis.core.ReactiveValueOperations;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.time.Duration;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
+public class RedisTemplateValueOpsIntegrationTest {
+
+ @Autowired
+ private ReactiveRedisTemplate redisTemplate;
+
+ private ReactiveValueOperations reactiveValueOps;
+
+ @Before
+ public void setup() {
+ reactiveValueOps = redisTemplate.opsForValue();
+ }
+
+ @Test
+ public void givenEmployee_whenSet_thenSet() {
+
+ Mono result = reactiveValueOps.set("123", new Employee("123", "Bill", "Accounts"));
+
+ StepVerifier.create(result)
+ .expectNext(true)
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenEmployeeId_whenGet_thenReturnsEmployee() {
+
+ Mono fetchedEmployee = reactiveValueOps.get("123");
+
+ StepVerifier.create(fetchedEmployee)
+ .expectNext(new Employee("123", "Bill", "Accounts"))
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenEmployee_whenSetWithExpiry_thenSetsWithExpiryTime() throws InterruptedException {
+
+ Mono result = reactiveValueOps.set("129", new Employee("129", "John", "Programming"), Duration.ofSeconds(1));
+
+ Mono fetchedEmployee = reactiveValueOps.get("129");
+
+ StepVerifier.create(result)
+ .expectNext(true)
+ .verifyComplete();
+
+ Thread.sleep(2000L);
+
+ StepVerifier.create(fetchedEmployee)
+ .expectNextCount(0L)
+ .verifyComplete();
+ }
+
+}
diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/RedisMessageListenerIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/RedisMessageListenerIntegrationTest.java
index 5bc70069c5..99febb6430 100644
--- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/RedisMessageListenerIntegrationTest.java
+++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/RedisMessageListenerIntegrationTest.java
@@ -31,7 +31,7 @@ public class RedisMessageListenerIntegrationTest {
@BeforeClass
public static void startRedisServer() throws IOException {
- redisServer = new redis.embedded.RedisServer(6379);
+ redisServer = new redis.embedded.RedisServer(6380);
redisServer.start();
}
diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java
index 48832a8de9..43aadefc01 100644
--- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java
+++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java
@@ -32,7 +32,7 @@ public class StudentRepositoryIntegrationTest {
@BeforeClass
public static void startRedisServer() throws IOException {
- redisServer = new redis.embedded.RedisServer(6379);
+ redisServer = new redis.embedded.RedisServer(6380);
redisServer.start();
}
diff --git a/pom.xml b/pom.xml
index a499aac7ee..a0c54f4b8a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,6 +46,12 @@
${junit-jupiter.version}
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit-jupiter.version}
+ test
+
org.junit.jupiter
junit-jupiter-api
@@ -372,6 +378,7 @@
google-web-toolkit
gson
guava
+ guava-collections
guava-modules/guava-18
guava-modules/guava-19
guava-modules/guava-21
@@ -399,6 +406,7 @@
javafx
jgroups
jee-7
+ jee-7-security
jhipster
jjwt
jsf
@@ -526,31 +534,6 @@
spring-resttemplate
- spring-security-acl
- spring-security-cache-control
- spring-security-client/spring-security-jsp-authentication
- spring-security-client/spring-security-jsp-authorize
- spring-security-client/spring-security-jsp-config
- spring-security-client/spring-security-mvc
- spring-security-client/spring-security-thymeleaf-authentication
- spring-security-client/spring-security-thymeleaf-authorize
- spring-security-client/spring-security-thymeleaf-config
- spring-security-core
- spring-security-mvc-boot
- spring-security-mvc-custom
- spring-security-mvc-digest-auth
- spring-security-mvc-ldap
- spring-security-mvc-login
- spring-security-mvc-persisted-remember-me
- spring-security-mvc-session
- spring-security-mvc-socket
- spring-security-openid
-
- spring-security-rest-basic-auth
- spring-security-rest-custom
- spring-security-rest
- spring-security-sso
- spring-security-x509
@@ -665,7 +648,6 @@
dubbo
flyway
- java-difference-date
jni
jooby
@@ -720,7 +702,33 @@
- flyway-cdi-extension
+ flyway-cdi-extension
+
+ spring-security-acl
+ spring-security-cache-control
+ spring-security-client/spring-security-jsp-authentication
+ spring-security-client/spring-security-jsp-authorize
+ spring-security-client/spring-security-jsp-config
+ spring-security-client/spring-security-mvc
+ spring-security-client/spring-security-thymeleaf-authentication
+ spring-security-client/spring-security-thymeleaf-authorize
+ spring-security-client/spring-security-thymeleaf-config
+ spring-security-core
+ spring-security-mvc-boot
+ spring-security-mvc-custom
+ spring-security-mvc-digest-auth
+ spring-security-mvc-ldap
+ spring-security-mvc-login
+ spring-security-mvc-persisted-remember-me
+ spring-security-mvc-session
+ spring-security-mvc-socket
+ spring-security-openid
+
+ spring-security-rest-basic-auth
+ spring-security-rest-custom
+ spring-security-rest
+ spring-security-sso
+ spring-security-x509
@@ -1138,7 +1146,6 @@
dubbo
flyway
- java-difference-date
jni
jooby
@@ -1278,6 +1285,7 @@
google-cloud
gson
guava
+ guava-collections
guava-modules/guava-18
guava-modules/guava-19
guava-modules/guava-21
@@ -1303,6 +1311,7 @@
javafx
jgroups
jee-7
+ jee-7-security
jjwt
jsf
json-path
diff --git a/reactor-core/src/main/java/com/baeldung/reactor/ItemProducerCreate.java b/reactor-core/src/main/java/com/baeldung/reactor/ItemProducerCreate.java
new file mode 100644
index 0000000000..6078f8ef0b
--- /dev/null
+++ b/reactor-core/src/main/java/com/baeldung/reactor/ItemProducerCreate.java
@@ -0,0 +1,44 @@
+package com.baeldung.reactor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.publisher.Flux;
+
+public class ItemProducerCreate {
+
+ Logger logger = LoggerFactory.getLogger(NetworTrafficProducerPush.class);
+
+ Consumer> listener;
+
+ public void create() {
+ Flux articlesFlux = Flux.create((sink) -> {
+ ItemProducerCreate.this.listener = (items) -> {
+ items.stream()
+ .forEach(article -> sink.next(article));
+ };
+ });
+ articlesFlux.subscribe(ItemProducerCreate.this.logger::info);
+ }
+
+ public static void main(String[] args) {
+ ItemProducerCreate producer = new ItemProducerCreate();
+ producer.create();
+
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ List items = new ArrayList<>();
+ items.add("Item 1");
+ items.add("Item 2");
+ items.add("Item 3");
+ producer.listener.accept(items);
+ }
+ }).start();
+ }
+}
diff --git a/reactor-core/src/main/java/com/baeldung/reactor/NetworTrafficProducerPush.java b/reactor-core/src/main/java/com/baeldung/reactor/NetworTrafficProducerPush.java
new file mode 100644
index 0000000000..807ceae84d
--- /dev/null
+++ b/reactor-core/src/main/java/com/baeldung/reactor/NetworTrafficProducerPush.java
@@ -0,0 +1,34 @@
+package com.baeldung.reactor;
+
+import java.util.function.Consumer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.FluxSink.OverflowStrategy;
+
+public class NetworTrafficProducerPush {
+
+ Logger logger = LoggerFactory.getLogger(NetworTrafficProducerPush.class);
+
+ Consumer listener;
+
+ public void subscribe(Consumer consumer) {
+ Flux flux = Flux.push(sink -> {
+ NetworTrafficProducerPush.this.listener = (t) -> sink.next(t);
+ }, OverflowStrategy.DROP);
+ flux.subscribe(consumer);
+ }
+
+ public void onPacket(String packet) {
+ listener.accept(packet);
+ }
+
+ public static void main(String[] args) {
+ NetworTrafficProducerPush trafficProducer = new NetworTrafficProducerPush();
+ trafficProducer.subscribe(trafficProducer.logger::info);
+ trafficProducer.onPacket("Packet[A18]");
+ }
+
+}
diff --git a/reactor-core/src/main/java/com/baeldung/reactor/ProgramaticSequences.java b/reactor-core/src/main/java/com/baeldung/reactor/ProgramaticSequences.java
new file mode 100644
index 0000000000..b52def377d
--- /dev/null
+++ b/reactor-core/src/main/java/com/baeldung/reactor/ProgramaticSequences.java
@@ -0,0 +1,58 @@
+package com.baeldung.reactor;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.publisher.Flux;
+
+public class ProgramaticSequences {
+
+ Logger logger = LoggerFactory.getLogger(ProgramaticSequences.class);
+
+ public void statefullImutableGenerate() {
+ Flux flux = Flux.generate(() -> 1, (state, sink) -> {
+ sink.next("2 + " + state + " = " + 2 + state);
+ if (state == 101)
+ sink.complete();
+ return state + 1;
+ });
+
+ flux.subscribe(logger::info);
+ }
+
+ public void statefullMutableGenerate() {
+ Flux flux = Flux.generate(AtomicInteger::new, (state, sink) -> {
+ int i = state.getAndIncrement();
+ sink.next("2 + " + state + " = " + 2 + state);
+ if (i == 101)
+ sink.complete();
+ return state;
+ });
+
+ flux.subscribe(logger::info);
+ }
+
+ public void handle() {
+ Flux elephants = Flux.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ .handle((i, sink) -> {
+ String animal = "Elephant nr " + i;
+ if (i % 2 == 0) {
+ sink.next(animal);
+ }
+ });
+
+ elephants.subscribe(logger::info);
+ }
+
+ public static void main(String[] args) {
+ ProgramaticSequences ps = new ProgramaticSequences();
+
+ ps.statefullImutableGenerate();
+ ps.statefullMutableGenerate();
+ ps.handle();
+
+ }
+
+}
diff --git a/reactor-core/src/main/java/com/baeldung/reactor/StatelessGenerate.java b/reactor-core/src/main/java/com/baeldung/reactor/StatelessGenerate.java
new file mode 100644
index 0000000000..c82f8e160b
--- /dev/null
+++ b/reactor-core/src/main/java/com/baeldung/reactor/StatelessGenerate.java
@@ -0,0 +1,24 @@
+package com.baeldung.reactor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.publisher.Flux;
+
+public class StatelessGenerate {
+
+ Logger logger = LoggerFactory.getLogger(StatelessGenerate.class);
+
+ public void statelessGenerate() {
+ Flux flux = Flux.generate((sink) -> {
+ sink.next("hallo");
+ });
+ flux.subscribe(logger::info);
+ }
+
+ public static void main(String[] args) {
+ StatelessGenerate ps = new StatelessGenerate();
+ ps.statelessGenerate();
+ }
+
+}
diff --git a/spring-5-mvc/README.md b/spring-5-mvc/README.md
index 7e83077f54..fa9d48ab72 100644
--- a/spring-5-mvc/README.md
+++ b/spring-5-mvc/README.md
@@ -2,3 +2,4 @@
- [Spring Boot and Kotlin](http://www.baeldung.com/spring-boot-kotlin)
- [Spring MVC Streaming and SSE Request Processing](https://www.baeldung.com/spring-mvc-sse-streams)
- [Overview and Need for DelegatingFilterProxy in Spring](https://www.baeldung.com/spring-delegating-filter-proxy)
+- [A Controller, Service and DAO Example with Spring Boot and JSF](https://www.baeldung.com/jsf-spring-boot-controller-service-dao)
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java
new file mode 100644
index 0000000000..e548e33c85
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.validations.functional;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class FunctionalValidationsApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(FunctionalValidationsApplication.class, args);
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java
new file mode 100644
index 0000000000..f34c1ee8d8
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java
@@ -0,0 +1,45 @@
+package com.baeldung.validations.functional.handlers;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.BeanPropertyBindingResult;
+import org.springframework.validation.Errors;
+import org.springframework.validation.Validator;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.server.ResponseStatusException;
+
+import reactor.core.publisher.Mono;
+
+public abstract class AbstractValidationHandler {
+
+ private final Class validationClass;
+
+ private final U validator;
+
+ protected AbstractValidationHandler(Class clazz, U validator) {
+ this.validationClass = clazz;
+ this.validator = validator;
+ }
+
+ abstract protected Mono processBody(T validBody, final ServerRequest originalRequest);
+
+ public final Mono handleRequest(final ServerRequest request) {
+ return request.bodyToMono(this.validationClass)
+ .flatMap(body -> {
+ Errors errors = new BeanPropertyBindingResult(body, this.validationClass.getName());
+ this.validator.validate(body, errors);
+
+ if (errors == null || errors.getAllErrors()
+ .isEmpty()) {
+ return processBody(body, request);
+ } else {
+ return onValidationErrors(errors, body, request);
+ }
+ });
+ }
+
+ protected Mono onValidationErrors(Errors errors, T invalidBody, final ServerRequest request) {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errors.getAllErrors()
+ .toString());
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java
new file mode 100644
index 0000000000..d7e3bd0bc0
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java
@@ -0,0 +1,43 @@
+package com.baeldung.validations.functional.handlers;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BeanPropertyBindingResult;
+import org.springframework.validation.Errors;
+import org.springframework.validation.Validator;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.server.ResponseStatusException;
+
+import com.baeldung.validations.functional.model.CustomRequestEntity;
+import com.baeldung.validations.functional.validators.CustomRequestEntityValidator;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class FunctionalHandler {
+
+ public Mono handleRequest(final ServerRequest request) {
+ Validator validator = new CustomRequestEntityValidator();
+ Mono responseBody = request.bodyToMono(CustomRequestEntity.class)
+ .map(body -> {
+ Errors errors = new BeanPropertyBindingResult(body, CustomRequestEntity.class.getName());
+ validator.validate(body, errors);
+
+ if (errors == null || errors.getAllErrors()
+ .isEmpty()) {
+ return String.format("Hi, %s [%s]!", body.getName(), body.getCode());
+
+ } else {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errors.getAllErrors()
+ .toString());
+ }
+
+ });
+ return ServerResponse.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(responseBody, String.class);
+
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java
new file mode 100644
index 0000000000..2011679741
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java
@@ -0,0 +1,30 @@
+package com.baeldung.validations.functional.handlers.impl;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.Validator;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+import com.baeldung.validations.functional.handlers.AbstractValidationHandler;
+import com.baeldung.validations.functional.model.AnnotatedRequestEntity;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class AnnotatedRequestEntityValidationHandler extends AbstractValidationHandler {
+
+ private AnnotatedRequestEntityValidationHandler(@Autowired Validator validator) {
+ super(AnnotatedRequestEntity.class, validator);
+ }
+
+ @Override
+ protected Mono processBody(AnnotatedRequestEntity validBody, ServerRequest originalRequest) {
+ String responseBody = String.format("Hi, %s. Password: %s!", validBody.getUser(), validBody.getPassword());
+ return ServerResponse.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(Mono.just(responseBody), String.class);
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java
new file mode 100644
index 0000000000..34630c60b2
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java
@@ -0,0 +1,37 @@
+package com.baeldung.validations.functional.handlers.impl;
+
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.Errors;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+import com.baeldung.validations.functional.handlers.AbstractValidationHandler;
+import com.baeldung.validations.functional.model.CustomRequestEntity;
+import com.baeldung.validations.functional.validators.CustomRequestEntityValidator;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class CustomRequestEntityValidationHandler extends AbstractValidationHandler {
+
+ private CustomRequestEntityValidationHandler() {
+ super(CustomRequestEntity.class, new CustomRequestEntityValidator());
+ }
+
+ @Override
+ protected Mono processBody(CustomRequestEntity validBody, ServerRequest originalRequest) {
+ String responseBody = String.format("Hi, %s [%s]!", validBody.getName(), validBody.getCode());
+ return ServerResponse.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(Mono.just(responseBody), String.class);
+ }
+
+ @Override
+ protected Mono onValidationErrors(Errors errors, CustomRequestEntity invalidBody, final ServerRequest request) {
+ return ServerResponse.badRequest()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(Mono.just(String.format("Custom message showing the errors: %s", errors.getAllErrors()
+ .toString())), String.class);
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java
new file mode 100644
index 0000000000..0196287d13
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java
@@ -0,0 +1,28 @@
+package com.baeldung.validations.functional.handlers.impl;
+
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+import com.baeldung.validations.functional.handlers.AbstractValidationHandler;
+import com.baeldung.validations.functional.model.OtherEntity;
+import com.baeldung.validations.functional.validators.OtherEntityValidator;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class OtherEntityValidationHandler extends AbstractValidationHandler {
+
+ private OtherEntityValidationHandler() {
+ super(OtherEntity.class, new OtherEntityValidator());
+ }
+
+ @Override
+ protected Mono processBody(OtherEntity validBody, ServerRequest originalRequest) {
+ String responseBody = String.format("Other object with item %s and quantity %s!", validBody.getItem(), validBody.getQuantity());
+ return ServerResponse.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(Mono.just(responseBody), String.class);
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java
new file mode 100644
index 0000000000..992f07481c
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java
@@ -0,0 +1,23 @@
+package com.baeldung.validations.functional.model;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class AnnotatedRequestEntity {
+ @NotNull
+ private String user;
+
+ @NotNull
+ @Size(min = 4, max = 7)
+ private String password;
+
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java
new file mode 100644
index 0000000000..ed459f121b
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java
@@ -0,0 +1,17 @@
+package com.baeldung.validations.functional.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class CustomRequestEntity {
+
+ private String name;
+ private String code;
+
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java
new file mode 100644
index 0000000000..78667cb13d
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java
@@ -0,0 +1,17 @@
+package com.baeldung.validations.functional.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class OtherEntity {
+
+ private String item;
+ private Integer quantity;
+
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java
new file mode 100644
index 0000000000..efbdbe3f99
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java
@@ -0,0 +1,29 @@
+package com.baeldung.validations.functional.routers;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.server.RequestPredicates;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+import com.baeldung.validations.functional.handlers.FunctionalHandler;
+import com.baeldung.validations.functional.handlers.impl.AnnotatedRequestEntityValidationHandler;
+import com.baeldung.validations.functional.handlers.impl.CustomRequestEntityValidationHandler;
+import com.baeldung.validations.functional.handlers.impl.OtherEntityValidationHandler;
+
+@Configuration
+public class ValidationsRouters {
+
+ @Bean
+ public RouterFunction responseHeaderRoute(@Autowired CustomRequestEntityValidationHandler dryHandler,
+ @Autowired FunctionalHandler complexHandler,
+ @Autowired OtherEntityValidationHandler otherHandler,
+ @Autowired AnnotatedRequestEntityValidationHandler annotatedEntityHandler) {
+ return RouterFunctions.route(RequestPredicates.POST("/complex-handler-functional-validation"), complexHandler::handleRequest)
+ .andRoute(RequestPredicates.POST("/dry-functional-validation"), dryHandler::handleRequest)
+ .andRoute(RequestPredicates.POST("/other-dry-functional-validation"), otherHandler::handleRequest)
+ .andRoute(RequestPredicates.POST("/annotated-functional-validation"), annotatedEntityHandler::handleRequest);
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java
new file mode 100644
index 0000000000..085d477318
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java
@@ -0,0 +1,29 @@
+package com.baeldung.validations.functional.validators;
+
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import com.baeldung.validations.functional.model.CustomRequestEntity;
+
+public class CustomRequestEntityValidator implements Validator {
+
+ private static final int MINIMUM_CODE_LENGTH = 6;
+
+ @Override
+ public boolean supports(Class> clazz) {
+ return CustomRequestEntity.class.isAssignableFrom(clazz);
+ }
+
+ @Override
+ public void validate(Object target, Errors errors) {
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "field.required");
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "code", "field.required");
+ CustomRequestEntity request = (CustomRequestEntity) target;
+ if (request.getCode() != null && request.getCode()
+ .trim()
+ .length() < MINIMUM_CODE_LENGTH) {
+ errors.rejectValue("code", "field.min.length", new Object[] { Integer.valueOf(MINIMUM_CODE_LENGTH) }, "The code must be at least [" + MINIMUM_CODE_LENGTH + "] characters in length.");
+ }
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java
new file mode 100644
index 0000000000..18c2c28cfe
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java
@@ -0,0 +1,27 @@
+package com.baeldung.validations.functional.validators;
+
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import com.baeldung.validations.functional.model.OtherEntity;
+
+public class OtherEntityValidator implements Validator {
+
+ private static final int MIN_ITEM_QUANTITY = 1;
+
+ @Override
+ public boolean supports(Class> clazz) {
+ return OtherEntity.class.isAssignableFrom(clazz);
+ }
+
+ @Override
+ public void validate(Object target, Errors errors) {
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "item", "field.required");
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "quantity", "field.required");
+ OtherEntity request = (OtherEntity) target;
+ if (request.getQuantity() != null && request.getQuantity() < MIN_ITEM_QUANTITY) {
+ errors.rejectValue("quantity", "field.min.length", new Object[] { Integer.valueOf(MIN_ITEM_QUANTITY) }, "There must be at least one item");
+ }
+ }
+}
diff --git a/spring-5-reactive/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java b/spring-5-reactive/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java
new file mode 100644
index 0000000000..5fe764bf8f
--- /dev/null
+++ b/spring-5-reactive/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java
@@ -0,0 +1,111 @@
+package com.baeldung.validations.functional;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
+
+import com.baeldung.validations.functional.model.AnnotatedRequestEntity;
+import com.baeldung.validations.functional.model.CustomRequestEntity;
+
+import reactor.core.publisher.Mono;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class FunctionalEndpointValidationsLiveTest {
+
+ private static final String BASE_URL = "http://localhost:8080";
+ private static final String COMPLEX_EP_URL = BASE_URL + "/complex-handler-functional-validation";
+ private static final String DRY_EP_URL = BASE_URL + "/dry-functional-validation";
+ private static final String ANNOTATIONS_EP_URL = BASE_URL + "/annotated-functional-validation";
+
+ private static WebTestClient client;
+
+ @BeforeAll
+ public static void setup() {
+ client = WebTestClient.bindToServer()
+ .baseUrl(BASE_URL)
+ .build();
+ }
+
+ @Test
+ public void whenRequestingDryEPWithInvalidBody_thenObtainBadRequest() {
+ CustomRequestEntity body = new CustomRequestEntity("name", "123");
+
+ ResponseSpec response = client.post()
+ .uri(DRY_EP_URL)
+ .body(Mono.just(body), CustomRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isBadRequest();
+ }
+
+ @Test
+ public void whenRequestingComplexEPWithInvalidBody_thenObtainBadRequest() {
+ CustomRequestEntity body = new CustomRequestEntity("name", "123");
+
+ ResponseSpec response = client.post()
+ .uri(COMPLEX_EP_URL)
+ .body(Mono.just(body), CustomRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isBadRequest();
+ }
+
+ @Test
+ public void whenRequestingAnnotatedEPWithInvalidBody_thenObtainBadRequest() {
+ AnnotatedRequestEntity body = new AnnotatedRequestEntity("user", "passwordlongerthan7digits");
+
+ ResponseSpec response = client.post()
+ .uri(ANNOTATIONS_EP_URL)
+ .body(Mono.just(body), AnnotatedRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isBadRequest();
+ }
+
+ @Test
+ public void whenRequestingDryEPWithValidBody_thenObtainBadRequest() {
+ CustomRequestEntity body = new CustomRequestEntity("name", "1234567");
+
+ ResponseSpec response = client.post()
+ .uri(DRY_EP_URL)
+ .body(Mono.just(body), CustomRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isOk();
+ }
+
+ @Test
+ public void whenRequestingComplexEPWithValidBody_thenObtainBadRequest() {
+ CustomRequestEntity body = new CustomRequestEntity("name", "1234567");
+
+ ResponseSpec response = client.post()
+ .uri(COMPLEX_EP_URL)
+ .body(Mono.just(body), CustomRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isOk();
+ }
+
+ @Test
+ public void whenRequestingAnnotatedEPWithValidBody_thenObtainBadRequest() {
+ AnnotatedRequestEntity body = new AnnotatedRequestEntity("user", "12345");
+
+ ResponseSpec response = client.post()
+ .uri(ANNOTATIONS_EP_URL)
+ .body(Mono.just(body), AnnotatedRequestEntity.class)
+ .exchange();
+
+ response.expectStatus()
+ .isOk();
+ }
+}
diff --git a/spring-boot-bootstrap/README.md b/spring-boot-bootstrap/README.md
index 4b09f11714..08fdb1bdc9 100644
--- a/spring-boot-bootstrap/README.md
+++ b/spring-boot-bootstrap/README.md
@@ -3,3 +3,4 @@
- [Spring Boot Dependency Management with a Custom Parent](http://www.baeldung.com/spring-boot-dependency-management-custom-parent)
- [Thin JARs with Spring Boot](http://www.baeldung.com/spring-boot-thin-jar)
- [Deploying a Spring Boot Application to Cloud Foundry](https://www.baeldung.com/spring-boot-app-deploy-to-cloud-foundry)
+- [Deploy a Spring Boot Application to Google App Engine](https://www.baeldung.com/spring-boot-google-app-engine)
diff --git a/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java b/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java
new file mode 100644
index 0000000000..8d92e18754
--- /dev/null
+++ b/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java
@@ -0,0 +1,14 @@
+package com.baeldung.h2db.auto.configuration;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+public class AutoConfigurationDemo {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AutoConfigurationDemo.class, args);
+ }
+
+}
diff --git a/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties b/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
index 0591cc9e0f..5e425a3550 100644
--- a/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
+++ b/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
@@ -4,4 +4,5 @@ spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create
spring.h2.console.enabled=true
-spring.h2.console.path=/h2-console
\ No newline at end of file
+spring.h2.console.path=/h2-console
+debug=true
\ No newline at end of file
diff --git a/spring-cloud-data-flow/etl/README.MD b/spring-cloud-data-flow/etl/README.MD
index 0cbb460b01..ee9c3a19c3 100644
--- a/spring-cloud-data-flow/etl/README.MD
+++ b/spring-cloud-data-flow/etl/README.MD
@@ -7,3 +7,7 @@ JDBC Source - Application Starter distributed by default
customer-transform - Custom application to transform the data
customer-mongodb-sink - Custom application to sink the data
+
+# Relevant Articles
+
+* [ETL with Spring Cloud Data Flow](https://www.baeldung.com/spring-cloud-data-flow-etl)
diff --git a/spring-cloud/README.md b/spring-cloud/README.md
index 805052e4db..16bc2d110a 100644
--- a/spring-cloud/README.md
+++ b/spring-cloud/README.md
@@ -28,3 +28,5 @@
- [An Intro to Spring Cloud Task](http://www.baeldung.com/spring-cloud-task)
- [Running Spring Boot Applications With Minikube](http://www.baeldung.com/spring-boot-minikube)
- [Introduction to Netflix Archaius with Spring Cloud](https://www.baeldung.com/netflix-archaius-spring-cloud-integration)
+- [An Intro to Spring Cloud Vault](https://www.baeldung.com/spring-cloud-vault)
+- [Netflix Archaius with Various Database Configurations](https://www.baeldung.com/netflix-archaius-database-configurations)
diff --git a/spring-core/README.md b/spring-core/README.md
index c0577b4ebc..e5c359c11b 100644
--- a/spring-core/README.md
+++ b/spring-core/README.md
@@ -20,3 +20,5 @@
- [Controlling Bean Creation Order with @DependsOn Annotation](http://www.baeldung.com/spring-depends-on)
- [Spring Autowiring of Generic Types](https://www.baeldung.com/spring-autowire-generics)
- [Spring Application Context Events](https://www.baeldung.com/spring-context-events)
+- [Unsatisfied Dependency in Spring](https://www.baeldung.com/spring-unsatisfied-dependency)
+- [What is a Spring Bean?](https://www.baeldung.com/spring-bean)
diff --git a/spring-data-jpa/README.md b/spring-data-jpa/README.md
index 8817020eec..44ce240da3 100644
--- a/spring-data-jpa/README.md
+++ b/spring-data-jpa/README.md
@@ -14,6 +14,7 @@
- [Auditing with JPA, Hibernate, and Spring Data JPA](https://www.baeldung.com/database-auditing-jpa)
- [Query Entities by Dates and Times with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-query-by-date)
- [DDD Aggregates and @DomainEvents](https://www.baeldung.com/spring-data-ddd)
+- [Spring Data – CrudRepository save() Method](https://www.baeldung.com/spring-data-crud-repository-save)
### Eclipse Config
After importing the project into Eclipse, you may see the following error:
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index ad70d987bb..072ed7a2ac 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -34,6 +34,12 @@
${mongodb-reactivestreams.version}
+
+ io.projectreactor
+ reactor-core
+ ${projectreactor.version}
+
+
io.projectreactor
reactor-test
@@ -109,6 +115,7 @@
5.1.0.RELEASE
1.9.2
3.2.0.RELEASE
+
diff --git a/spring-mockito/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java b/spring-mockito/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java
index f30af140af..aeec57d136 100644
--- a/spring-mockito/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java
+++ b/spring-mockito/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java
@@ -1,17 +1,18 @@
package com.baeldung.app.rest;
-import com.baeldung.app.api.Flower;
-import com.baeldung.domain.service.FlowerService;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
+import com.baeldung.app.api.Flower;
+import com.baeldung.domain.service.FlowerService;
@RunWith(MockitoJUnitRunner.class)
public class FlowerControllerUnitTest {
diff --git a/spring-mockito/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java b/spring-mockito/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java
index e303c85caf..15e91d86b5 100644
--- a/spring-mockito/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java
+++ b/spring-mockito/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java
@@ -1,18 +1,19 @@
package com.baeldung.app.rest;
+import static org.mockito.Mockito.times;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
import com.baeldung.app.api.MessageApi;
import com.baeldung.domain.model.Message;
import com.baeldung.domain.service.MessageService;
import com.baeldung.domain.util.MessageMatcher;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Matchers;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static org.mockito.Mockito.times;
@RunWith(MockitoJUnitRunner.class)
public class MessageControllerUnitTest {
@@ -37,6 +38,6 @@ public class MessageControllerUnitTest {
message.setTo("you");
message.setText("Hello, you!");
- Mockito.verify(messageService, times(1)).deliverMessage(Matchers.argThat(new MessageMatcher(message)));
+ Mockito.verify(messageService, times(1)).deliverMessage(ArgumentMatchers.argThat(new MessageMatcher(message)));
}
}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMethodController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMethodController.java
new file mode 100644
index 0000000000..03cf729ddf
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMethodController.java
@@ -0,0 +1,25 @@
+package com.baeldung.spring.controller;
+
+import com.baeldung.spring.domain.Employee;
+import com.baeldung.spring.exception.InvalidRequestException;
+import com.baeldung.spring.service.EmployeeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(value="/api")
+public class RequestMethodController {
+
+ @Autowired
+ EmployeeService service;
+
+ @RequestMapping(value = "/employees", produces = "application/json", method={RequestMethod.GET,RequestMethod.POST})
+ public List findEmployees()
+ throws InvalidRequestException {
+ return service.getEmployeeList();
+ }
+}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/exception/InvalidRequestException.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/exception/InvalidRequestException.java
new file mode 100644
index 0000000000..4dcbe86735
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/exception/InvalidRequestException.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.exception;
+
+public class InvalidRequestException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4088649120307193208L;
+
+ public InvalidRequestException() {
+ super();
+ }
+
+ public InvalidRequestException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidRequestException(final String message) {
+ super(message);
+ }
+
+ public InvalidRequestException(final Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeService.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeService.java
new file mode 100644
index 0000000000..4d87352c42
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeService.java
@@ -0,0 +1,12 @@
+package com.baeldung.spring.service;
+
+import com.baeldung.spring.domain.Employee;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public interface EmployeeService {
+
+ List getEmployeeList();
+}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeServiceImpl.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeServiceImpl.java
new file mode 100644
index 0000000000..18f2d70795
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/service/EmployeeServiceImpl.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.service;
+
+import com.baeldung.spring.domain.Employee;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class EmployeeServiceImpl implements EmployeeService{
+
+ @Override
+ public List getEmployeeList() {
+ List employeeList = new ArrayList<>();
+ employeeList.add(createEmployee(100L, "Steve Martin", "333-777-999"));
+ employeeList.add(createEmployee(200L, "Adam Schawn", "444-111-777"));
+ return employeeList;
+ }
+
+ private Employee createEmployee(long id, String name, String contactNumber) {
+ Employee employee = new Employee();
+ employee.setId(id);
+ employee.setName(name);
+ employee.setContactNumber(contactNumber);
+ return employee;
+ }
+}
diff --git a/spring-rest/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java b/spring-rest/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
index a84f866dfe..814efc112a 100644
--- a/spring-rest/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
+++ b/spring-rest/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
@@ -4,10 +4,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import com.baeldung.propertyeditor.creditcard.CreditCard;
-import com.baeldung.propertyeditor.creditcard.CreditCardEditor;
+import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class CreditCardEditorUnitTest {
diff --git a/spring-security-mvc-boot/README.MD b/spring-security-mvc-boot/README.MD
index 6bd9b9295c..6f01bfdc65 100644
--- a/spring-security-mvc-boot/README.MD
+++ b/spring-security-mvc-boot/README.MD
@@ -11,3 +11,4 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com
- [Granted Authority Versus Role in Spring Security](http://www.baeldung.com/spring-security-granted-authority-vs-role)
- [Spring Data with Spring Security](https://www.baeldung.com/spring-data-security)
- [Spring Security – Whitelist IP Range](https://www.baeldung.com/spring-security-whitelist-ip-range)
+- [Find the Registered Spring Security Filters](https://www.baeldung.com/spring-security-registered-filters)
diff --git a/core-java/src/main/java/com/baeldung/throwsexception/Calculator.java b/testing-modules/junit-5/src/main/java/com/baeldung/throwsexception/Calculator.java
similarity index 100%
rename from core-java/src/main/java/com/baeldung/throwsexception/Calculator.java
rename to testing-modules/junit-5/src/main/java/com/baeldung/throwsexception/Calculator.java
diff --git a/core-java/src/main/java/com/baeldung/throwsexception/DivideByZeroException.java b/testing-modules/junit-5/src/main/java/com/baeldung/throwsexception/DivideByZeroException.java
similarity index 100%
rename from core-java/src/main/java/com/baeldung/throwsexception/DivideByZeroException.java
rename to testing-modules/junit-5/src/main/java/com/baeldung/throwsexception/DivideByZeroException.java
diff --git a/core-java/src/test/java/com/baeldung/junit4vstestng/SortedUnitTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/junit4vstestng/SortedUnitTest.java
similarity index 100%
rename from core-java/src/test/java/com/baeldung/junit4vstestng/SortedUnitTest.java
rename to testing-modules/junit-5/src/test/java/com/baeldung/junit4vstestng/SortedUnitTest.java
diff --git a/core-java/src/test/java/com/baeldung/junit4vstestng/SummationServiceIntegrationTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/junit4vstestng/SummationServiceIntegrationTest.java
similarity index 100%
rename from core-java/src/test/java/com/baeldung/junit4vstestng/SummationServiceIntegrationTest.java
rename to testing-modules/junit-5/src/test/java/com/baeldung/junit4vstestng/SummationServiceIntegrationTest.java
diff --git a/testing-modules/junit-5/src/test/java/com/baeldung/junit5vstestng/SummationServiceIntegrationTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/junit5vstestng/SummationServiceIntegrationTest.java
new file mode 100644
index 0000000000..92e7a6f5db
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/com/baeldung/junit5vstestng/SummationServiceIntegrationTest.java
@@ -0,0 +1,53 @@
+package com.baeldung.junit5vstestng;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class SummationServiceIntegrationTest {
+ private static List numbers;
+
+ @BeforeAll
+ public static void initialize() {
+ numbers = new ArrayList<>();
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ numbers = null;
+ }
+
+ @BeforeEach
+ public void runBeforeEachTest() {
+ numbers.add(1);
+ numbers.add(2);
+ numbers.add(3);
+ }
+
+ @AfterEach
+ public void runAfterEachTest() {
+ numbers.clear();
+ }
+
+ @Test
+ public void givenNumbers_sumEquals_thenCorrect() {
+ int sum = numbers.stream()
+ .reduce(0, Integer::sum);
+ Assert.assertEquals(6, sum);
+ }
+
+ @Ignore
+ @Test
+ public void givenEmptyList_sumEqualsZero_thenCorrect() {
+ int sum = numbers.stream()
+ .reduce(0, Integer::sum);
+ Assert.assertEquals(6, sum);
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/throwsexception/CalculatorUnitTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/throwsexception/CalculatorUnitTest.java
similarity index 100%
rename from core-java/src/test/java/com/baeldung/throwsexception/CalculatorUnitTest.java
rename to testing-modules/junit-5/src/test/java/com/baeldung/throwsexception/CalculatorUnitTest.java
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/customtestname/CustomNameUnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/customtestname/CustomNameUnitTest.java
new file mode 100644
index 0000000000..f04b825c89
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/customtestname/CustomNameUnitTest.java
@@ -0,0 +1,17 @@
+package org.baeldung.java.customtestname;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class CustomNameUnitTest {
+
+ @ParameterizedTest
+ @ValueSource(strings = { "Hello", "World" })
+ @DisplayName("Test Method to check that the inputs are not nullable")
+ void givenString_TestNullOrNot(String word) {
+ assertNotNull(word);
+ }
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/ParameterizedUnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/ParameterizedUnitTest.java
new file mode 100644
index 0000000000..8d09161176
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/ParameterizedUnitTest.java
@@ -0,0 +1,45 @@
+package org.baeldung.java.parameterisedsource;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class ParameterizedUnitTest {
+
+ @ParameterizedTest
+ @ValueSource(strings = { "Hello", "World" })
+ void givenString_TestNullOrNot(String word) {
+ assertNotNull(word);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = PizzaDeliveryStrategy.class, names = {"EXPRESS", "NORMAL"})
+ void givenEnum_TestContainsOrNot(PizzaDeliveryStrategy timeUnit) {
+ assertTrue(EnumSet.of(PizzaDeliveryStrategy.EXPRESS, PizzaDeliveryStrategy.NORMAL).contains(timeUnit));
+ }
+
+ @ParameterizedTest
+ @MethodSource("wordDataProvider")
+ void givenMethodSource_TestInputStream(String argument) {
+ assertNotNull(argument);
+ }
+
+ static Stream wordDataProvider() {
+ return Stream.of("foo", "bar");
+ }
+
+ @ParameterizedTest
+ @CsvSource({ "1, Car", "2, House", "3, Train" })
+ void givenCSVSource_TestContent(int id, String word) {
+ assertNotNull(id);
+ assertNotNull(word);
+ }
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/PizzaDeliveryStrategy.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/PizzaDeliveryStrategy.java
new file mode 100644
index 0000000000..ecfc7b4627
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/parameterisedsource/PizzaDeliveryStrategy.java
@@ -0,0 +1,6 @@
+package org.baeldung.java.parameterisedsource;
+
+public enum PizzaDeliveryStrategy {
+ EXPRESS,
+ NORMAL;
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectClassesSuiteUnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectClassesSuiteUnitTest.java
new file mode 100644
index 0000000000..220897eae7
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectClassesSuiteUnitTest.java
@@ -0,0 +1,13 @@
+package org.baeldung.java.suite;
+
+import org.baeldung.java.suite.childpackage1.Class1UnitTest;
+import org.baeldung.java.suite.childpackage2.Class2UnitTest;
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.runner.RunWith;
+
+@RunWith(JUnitPlatform.class)
+@SelectClasses({Class1UnitTest.class, Class2UnitTest.class})
+public class SelectClassesSuiteUnitTest {
+
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectPackagesSuiteUnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectPackagesSuiteUnitTest.java
new file mode 100644
index 0000000000..ae887ae43b
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/SelectPackagesSuiteUnitTest.java
@@ -0,0 +1,11 @@
+package org.baeldung.java.suite;
+
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.platform.suite.api.SelectPackages;
+import org.junit.runner.RunWith;
+
+@RunWith(JUnitPlatform.class)
+@SelectPackages({ "org.baeldung.java.suite.childpackage1", "org.baeldung.java.suite.childpackage2" })
+public class SelectPackagesSuiteUnitTest {
+
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage1/Class1UnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage1/Class1UnitTest.java
new file mode 100644
index 0000000000..78469cb971
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage1/Class1UnitTest.java
@@ -0,0 +1,15 @@
+package org.baeldung.java.suite.childpackage1;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.Test;
+
+
+public class Class1UnitTest {
+
+ @Test
+ public void testCase_InClass1UnitTest() {
+ assertTrue(true);
+ }
+
+}
diff --git a/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage2/Class2UnitTest.java b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage2/Class2UnitTest.java
new file mode 100644
index 0000000000..4463ecfad9
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/org/baeldung/java/suite/childpackage2/Class2UnitTest.java
@@ -0,0 +1,14 @@
+package org.baeldung.java.suite.childpackage2;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.Test;
+
+public class Class2UnitTest {
+
+ @Test
+ public void testCase_InClass2UnitTest() {
+ assertTrue(true);
+ }
+
+}
diff --git a/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoSpyIntegrationTest.java b/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoSpyIntegrationTest.java
index 206e0f4daf..118d50ea40 100644
--- a/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoSpyIntegrationTest.java
+++ b/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoSpyIntegrationTest.java
@@ -1,15 +1,15 @@
package org.baeldung.mockito;
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
+import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MockitoSpyIntegrationTest {
diff --git a/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoVoidMethodsUnitTest.java b/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoVoidMethodsUnitTest.java
index 49360f8d6c..b020338fd9 100644
--- a/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoVoidMethodsUnitTest.java
+++ b/testing-modules/mockito/src/test/java/org/baeldung/mockito/MockitoVoidMethodsUnitTest.java
@@ -1,14 +1,22 @@
package org.baeldung.mockito;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertEquals;
-
-import static org.mockito.Mockito.*;
import org.mockito.ArgumentCaptor;
-import static org.mockito.Matchers.any;
+import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
-import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MockitoVoidMethodsUnitTest {
diff --git a/testing-modules/rest-testing/pom.xml b/testing-modules/rest-testing/pom.xml
index 0e54980683..9bfd715682 100644
--- a/testing-modules/rest-testing/pom.xml
+++ b/testing-modules/rest-testing/pom.xml
@@ -106,6 +106,46 @@
true
+
+
+
+ maven-failsafe-plugin
+ ${maven-failsafe-plugin.version}
+
+ classes
+ 4
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+ com.github.temyers
+ cucumber-jvm-parallel-plugin
+ 5.0.0
+
+
+ generateRunners
+ generate-test-sources
+
+ generateRunners
+
+
+
+ com.baeldung.rest.cucumber
+
+ src/test/resources/Feature/
+ SCENARIO
+
+
+
+
+
diff --git a/testing-modules/rest-testing/src/test/java/com/baeldung/rest/cucumber/StepDefinition.java b/testing-modules/rest-testing/src/test/java/com/baeldung/rest/cucumber/StepDefinition.java
index b461da8403..35a913ae25 100644
--- a/testing-modules/rest-testing/src/test/java/com/baeldung/rest/cucumber/StepDefinition.java
+++ b/testing-modules/rest-testing/src/test/java/com/baeldung/rest/cucumber/StepDefinition.java
@@ -1,19 +1,5 @@
package com.baeldung.rest.cucumber;
-import com.github.tomakehurst.wiremock.WireMockServer;
-import cucumber.api.java.en.Then;
-import cucumber.api.java.en.When;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Scanner;
-
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
import static com.github.tomakehurst.wiremock.client.WireMock.containing;
@@ -25,10 +11,27 @@ import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Scanner;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+
public class StepDefinition {
private static final String CREATE_PATH = "/create";
@@ -37,20 +40,20 @@ public class StepDefinition {
private final InputStream jsonInputStream = this.getClass().getClassLoader().getResourceAsStream("cucumber.json");
private final String jsonString = new Scanner(jsonInputStream, "UTF-8").useDelimiter("\\Z").next();
- private final WireMockServer wireMockServer = new WireMockServer();
+ private final WireMockServer wireMockServer = new WireMockServer(options().dynamicPort());
private final CloseableHttpClient httpClient = HttpClients.createDefault();
@When("^users upload data on a project$")
public void usersUploadDataOnAProject() throws IOException {
wireMockServer.start();
- configureFor("localhost", 8080);
+ configureFor("localhost", wireMockServer.port());
stubFor(post(urlEqualTo(CREATE_PATH))
.withHeader("content-type", equalTo(APPLICATION_JSON))
.withRequestBody(containing("testing-framework"))
.willReturn(aResponse().withStatus(200)));
- HttpPost request = new HttpPost("http://localhost:8080/create");
+ HttpPost request = new HttpPost("http://localhost:" + wireMockServer.port() + "/create");
StringEntity entity = new StringEntity(jsonString);
request.addHeader("content-type", APPLICATION_JSON);
request.setEntity(entity);
@@ -67,11 +70,11 @@ public class StepDefinition {
public void usersGetInformationOnAProject(String projectName) throws IOException {
wireMockServer.start();
- configureFor("localhost", 8080);
+ configureFor("localhost", wireMockServer.port());
stubFor(get(urlEqualTo("/projects/cucumber")).withHeader("accept", equalTo(APPLICATION_JSON))
.willReturn(aResponse().withBody(jsonString)));
- HttpGet request = new HttpGet("http://localhost:8080/projects/" + projectName.toLowerCase());
+ HttpGet request = new HttpGet("http://localhost:" + wireMockServer.port() + "/projects/" + projectName.toLowerCase());
request.addHeader("accept", APPLICATION_JSON);
HttpResponse httpResponse = httpClient.execute(request);
String responseString = convertResponseToString(httpResponse);
diff --git a/testing-modules/rest-testing/src/test/resources/Feature/cucumber.feature b/testing-modules/rest-testing/src/test/resources/Feature/cucumber.feature
new file mode 100644
index 0000000000..99dd8249fe
--- /dev/null
+++ b/testing-modules/rest-testing/src/test/resources/Feature/cucumber.feature
@@ -0,0 +1,10 @@
+Feature: Testing a REST API
+ Users should be able to submit GET and POST requests to a web service, represented by WireMock
+
+ Scenario: Data Upload to a web service
+ When users upload data on a project
+ Then the server should handle it and return a success status
+
+ Scenario: Data retrieval from a web service
+ When users want to get information on the Cucumber project
+ Then the requested data is returned
\ No newline at end of file
diff --git a/testing-modules/spring-testing/README.md b/testing-modules/spring-testing/README.md
index aed330d260..e22c3e84e7 100644
--- a/testing-modules/spring-testing/README.md
+++ b/testing-modules/spring-testing/README.md
@@ -1,3 +1,4 @@
### Relevant Articles:
-* [Mockito.mock() vs @Mock vs @MockBean](http://www.baeldung.com/java-spring-mockito-mock-mockbean)
+- [Mockito.mock() vs @Mock vs @MockBean](http://www.baeldung.com/java-spring-mockito-mock-mockbean)
+- [A Quick Guide to @TestPropertySource](https://www.baeldung.com/spring-test-property-source)
diff --git a/xml/src/main/java/com/baeldung/xml/XMLDocumentWriter.java b/xml/src/main/java/com/baeldung/xml/XMLDocumentWriter.java
new file mode 100644
index 0000000000..e33fc5fe1d
--- /dev/null
+++ b/xml/src/main/java/com/baeldung/xml/XMLDocumentWriter.java
@@ -0,0 +1,41 @@
+package com.baeldung.xml;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+
+public class XMLDocumentWriter {
+
+ public void write(Document document, String fileName, boolean excludeDeclaration, boolean prettyPrint) {
+ try(FileWriter writer = new FileWriter(new File(fileName))) {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ if(excludeDeclaration) {
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ }
+ if(prettyPrint) {
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ }
+ DOMSource source = new DOMSource(document);
+ StreamResult result = new StreamResult(writer);
+ transformer.transform(source, result);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ } catch (TransformerConfigurationException e) {
+ throw new IllegalStateException(e);
+ } catch (TransformerException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/xml/src/test/java/com/baeldung/xml/XMLDocumentWriterUnitTest.java b/xml/src/test/java/com/baeldung/xml/XMLDocumentWriterUnitTest.java
new file mode 100644
index 0000000000..68f787a054
--- /dev/null
+++ b/xml/src/test/java/com/baeldung/xml/XMLDocumentWriterUnitTest.java
@@ -0,0 +1,52 @@
+package com.baeldung.xml;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.io.File;
+
+public class XMLDocumentWriterUnitTest {
+
+ @Test
+ public void givenXMLDocumentWhenWriteIsCalledThenXMLIsWrittenToFile() throws Exception {
+ Document document = createSampleDocument();
+ new XMLDocumentWriter().write(document, "company_simple.xml", false, false);
+ }
+
+ @Test
+ public void givenXMLDocumentWhenWriteIsCalledWithPrettyPrintThenFormattedXMLIsWrittenToFile() throws Exception {
+ Document document = createSampleDocument();
+ new XMLDocumentWriter().write(document, "company_prettyprinted.xml", false, true);
+ }
+
+ private Document createSampleDocument() throws ParserConfigurationException {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.newDocument();
+ Element companyElement = document.createElement("Company");
+ document.appendChild(companyElement);
+ Element departmentElement = document.createElement("Department");
+ departmentElement.setAttribute("name", "Sales");
+ companyElement.appendChild(departmentElement);
+ Element employee1 = document.createElement("Employee");
+ employee1.setAttribute("name", "John Smith");
+ departmentElement.appendChild(employee1);
+ Element employee2 = document.createElement("Employee");
+ employee2.setAttribute("name", "Tim Dellor");
+ departmentElement.appendChild(employee2);
+ return document;
+ }
+
+ @After
+ public void cleanUp() throws Exception {
+ FileUtils.deleteQuietly(new File("company_simple.xml"));
+ FileUtils.deleteQuietly(new File("company_prettyprinted.xml"));
+ }
+}