diff --git a/algorithms-miscellaneous-3/pom.xml b/algorithms-miscellaneous-3/pom.xml
index c4017144c8..3cebdd09ac 100644
--- a/algorithms-miscellaneous-3/pom.xml
+++ b/algorithms-miscellaneous-3/pom.xml
@@ -18,6 +18,18 @@
${org.assertj.core.version}
test
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
@@ -34,6 +46,7 @@
3.9.0
+ 4.3
+ 28.0-jre
-
\ No newline at end of file
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/Employee.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/Employee.java
new file mode 100644
index 0000000000..796932728b
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/Employee.java
@@ -0,0 +1,34 @@
+package com.baeldung.algorithms.checksortedlist;
+
+public class Employee {
+
+ long id;
+
+ String name;
+
+ public Employee() {
+ }
+
+ public Employee(long id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/SortedListChecker.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/SortedListChecker.java
new file mode 100644
index 0000000000..d2aa159e6d
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checksortedlist/SortedListChecker.java
@@ -0,0 +1,85 @@
+package com.baeldung.algorithms.checksortedlist;
+
+import static org.apache.commons.collections4.CollectionUtils.isEmpty;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.collect.Comparators;
+import com.google.common.collect.Ordering;;
+
+public class SortedListChecker {
+
+ private SortedListChecker() {
+ throw new AssertionError();
+ }
+
+ public static boolean checkIfSortedUsingIterativeApproach(List listOfStrings) {
+ if (isEmpty(listOfStrings) || listOfStrings.size() == 1) {
+ return true;
+ }
+
+ Iterator iter = listOfStrings.iterator();
+ String current, previous = iter.next();
+ while (iter.hasNext()) {
+ current = iter.next();
+ if (previous.compareTo(current) > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean checkIfSortedUsingIterativeApproach(List employees, Comparator employeeComparator) {
+ if (isEmpty(employees) || employees.size() == 1) {
+ return true;
+ }
+
+ Iterator iter = employees.iterator();
+ Employee current, previous = iter.next();
+ while (iter.hasNext()) {
+ current = iter.next();
+ if (employeeComparator.compare(previous, current) > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean checkIfSortedUsingRecursion(List listOfStrings) {
+ return isSortedRecursive(listOfStrings, listOfStrings.size());
+ }
+
+ public static boolean isSortedRecursive(List listOfStrings, int index) {
+ if (index < 2) {
+ return true;
+ } else if (listOfStrings.get(index - 2)
+ .compareTo(listOfStrings.get(index - 1)) > 0) {
+ return false;
+ } else {
+ return isSortedRecursive(listOfStrings, index - 1);
+ }
+ }
+
+ public static boolean checkIfSortedUsingOrderingClass(List listOfStrings) {
+ return Ordering. natural()
+ .isOrdered(listOfStrings);
+ }
+
+ public static boolean checkIfSortedUsingOrderingClass(List employees, Comparator employeeComparator) {
+ return Ordering.from(employeeComparator)
+ .isOrdered(employees);
+ }
+
+ public static boolean checkIfSortedUsingOrderingClassHandlingNull(List listOfStrings) {
+ return Ordering. natural()
+ .nullsLast()
+ .isOrdered(listOfStrings);
+ }
+
+ public static boolean checkIfSortedUsingComparators(List listOfStrings) {
+ return Comparators.isInOrder(listOfStrings, Comparator. naturalOrder());
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/FoldingHash.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/FoldingHash.java
new file mode 100644
index 0000000000..0ea128c1d9
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/FoldingHash.java
@@ -0,0 +1,78 @@
+package com.baeldung.folding;
+
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * Calculate a hash value for the strings using the folding technique.
+ *
+ * The implementation serves only to the illustration purposes and is far
+ * from being the most efficient.
+ *
+ * @author A.Shcherbakov
+ *
+ */
+public class FoldingHash {
+
+ /**
+ * Calculate the hash value of a given string.
+ *
+ * @param str Assume it is not null
+ * @param groupSize the group size in the folding technique
+ * @param maxValue defines a max value that the hash may acquire (exclusive)
+ * @return integer value from 0 (inclusive) to maxValue (exclusive)
+ */
+ public int hash(String str, int groupSize, int maxValue) {
+ final int[] codes = this.toAsciiCodes(str);
+ return IntStream.range(0, str.length())
+ .filter(i -> i % groupSize == 0)
+ .mapToObj(i -> extract(codes, i, groupSize))
+ .map(block -> concatenate(block))
+ .reduce(0, (a, b) -> (a + b) % maxValue);
+ }
+
+ /**
+ * Returns a new array of given length whose elements are take from
+ * the original one starting from the offset.
+ *
+ * If the original array has not enough elements, the returning array will contain
+ * element from the offset till the end of the original array.
+ *
+ * @param numbers original array. Assume it is not null.
+ * @param offset index of the element to start from. Assume it is less than the size of the array
+ * @param length max size of the resulting array
+ * @return
+ */
+ public int[] extract(int[] numbers, int offset, int length) {
+ final int defect = numbers.length - (offset + length);
+ final int s = defect < 0 ? length + defect : length;
+ int[] result = new int[s];
+ for (int index = 0; index < s; index++) {
+ result[index] = numbers[index + offset];
+ }
+ return result;
+ }
+
+ /**
+ * Concatenate the numbers into a single number as if they were strings.
+ * Assume that the procedure does not suffer from the overflow.
+ * @param numbers integers to concatenate
+ * @return
+ */
+ public int concatenate(int[] numbers) {
+ final String merged = IntStream.of(numbers)
+ .mapToObj(number -> "" + number)
+ .collect(Collectors.joining());
+ return Integer.parseInt(merged, 10);
+ }
+
+ /**
+ * Convert the string into its characters' ASCII codes.
+ * @param str input string
+ * @return
+ */
+ private int[] toAsciiCodes(String str) {
+ return str.chars()
+ .toArray();
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/Main.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/Main.java
new file mode 100644
index 0000000000..3b055a0dbe
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/folding/Main.java
@@ -0,0 +1,17 @@
+package com.baeldung.folding;
+
+/**
+ * Code snippet for article "A Guide to the Folding Technique".
+ *
+ * @author A.Shcherbakov
+ *
+ */
+public class Main {
+
+ public static void main(String... arg) {
+ FoldingHash hasher = new FoldingHash();
+ final String str = "Java language";
+ System.out.println(hasher.hash(str, 2, 100_000));
+ System.out.println(hasher.hash(str, 3, 1_000));
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java
new file mode 100644
index 0000000000..44c4388e6c
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java
@@ -0,0 +1,106 @@
+package com.baeldung.algorithms.checksortedlist;
+
+import static com.baeldung.algorithms.checksortedlist.SortedListChecker.checkIfSortedUsingComparators;
+import static com.baeldung.algorithms.checksortedlist.SortedListChecker.checkIfSortedUsingIterativeApproach;
+import static com.baeldung.algorithms.checksortedlist.SortedListChecker.checkIfSortedUsingOrderingClass;
+import static com.baeldung.algorithms.checksortedlist.SortedListChecker.checkIfSortedUsingRecursion;
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SortedListCheckerUnitTest {
+
+ private List sortedListOfString;
+ private List unsortedListOfString;
+ private List singletonList;
+
+ private List employeesSortedByName;
+ private List employeesNotSortedByName;
+
+ @Before
+ public void setUp() {
+ sortedListOfString = asList("Canada", "HK", "LA", "NJ", "NY");
+ unsortedListOfString = asList("LA", "HK", "NJ", "NY", "Canada");
+ singletonList = Collections.singletonList("NY");
+
+ employeesSortedByName = asList(new Employee(1L, "John"), new Employee(2L, "Kevin"), new Employee(3L, "Mike"));
+ employeesNotSortedByName = asList(new Employee(1L, "Kevin"), new Employee(2L, "John"), new Employee(3L, "Mike"));
+ }
+
+ @Test
+ public void givenSortedList_whenUsingIterativeApproach_thenReturnTrue() {
+ assertThat(checkIfSortedUsingIterativeApproach(sortedListOfString)).isTrue();
+ }
+
+ @Test
+ public void givenSingleElementList_whenUsingIterativeApproach_thenReturnTrue() {
+ assertThat(checkIfSortedUsingIterativeApproach(singletonList)).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedList_whenUsingIterativeApproach_thenReturnFalse() {
+ assertThat(checkIfSortedUsingIterativeApproach(unsortedListOfString)).isFalse();
+ }
+
+ @Test
+ public void givenSortedListOfEmployees_whenUsingIterativeApproach_thenReturnTrue() {
+ assertThat(checkIfSortedUsingIterativeApproach(employeesSortedByName, Comparator.comparing(Employee::getName))).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedListOfEmployees_whenUsingIterativeApproach_thenReturnFalse() {
+ assertThat(checkIfSortedUsingIterativeApproach(employeesNotSortedByName, Comparator.comparing(Employee::getName))).isFalse();
+ }
+
+ @Test
+ public void givenSortedList_whenUsingRecursion_thenReturnTrue() {
+ assertThat(checkIfSortedUsingRecursion(sortedListOfString)).isTrue();
+ }
+
+ @Test
+ public void givenSingleElementList_whenUsingRecursion_thenReturnTrue() {
+ assertThat(checkIfSortedUsingRecursion(singletonList)).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedList_whenUsingRecursion_thenReturnFalse() {
+ assertThat(checkIfSortedUsingRecursion(unsortedListOfString)).isFalse();
+ }
+
+ @Test
+ public void givenSortedList_whenUsingGuavaOrdering_thenReturnTrue() {
+ assertThat(checkIfSortedUsingOrderingClass(sortedListOfString)).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedList_whenUsingGuavaOrdering_thenReturnFalse() {
+ assertThat(checkIfSortedUsingOrderingClass(unsortedListOfString)).isFalse();
+ }
+
+ @Test
+ public void givenSortedListOfEmployees_whenUsingGuavaOrdering_thenReturnTrue() {
+ assertThat(checkIfSortedUsingOrderingClass(employeesSortedByName, Comparator.comparing(Employee::getName))).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedListOfEmployees_whenUsingGuavaOrdering_thenReturnFalse() {
+ assertThat(checkIfSortedUsingOrderingClass(employeesNotSortedByName, Comparator.comparing(Employee::getName))).isFalse();
+ }
+
+ @Test
+ public void givenSortedList_whenUsingGuavaComparators_thenReturnTrue() {
+ assertThat(checkIfSortedUsingComparators(sortedListOfString)).isTrue();
+ }
+
+ @Test
+ public void givenUnsortedList_whenUsingGuavaComparators_thenReturnFalse() {
+ assertThat(checkIfSortedUsingComparators(unsortedListOfString)).isFalse();
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java
new file mode 100644
index 0000000000..43e33d8378
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java
@@ -0,0 +1,54 @@
+package com.baeldung.folding;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class FoldingHashUnitTest {
+
+ @Test
+ public void givenStringJavaLanguage_whenSize2Capacity100000_then48933() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int value = hasher.hash("Java language", 2, 100_000);
+ assertEquals(value, 48933);
+ }
+
+ @Test
+ public void givenStringVaJaLanguage_whenSize2Capacity100000_thenSameAsJavaLanguage() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int java = hasher.hash("Java language", 2, 100_000);
+ final int vaja = hasher.hash("vaJa language", 2, 100_000);
+ assertTrue(java == vaja);
+ }
+
+ @Test
+ public void givenSingleElementArray_whenOffset0Size2_thenSingleElement() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int[] value = hasher.extract(new int[] { 5 }, 0, 2);
+ assertArrayEquals(new int[] { 5 }, value);
+ }
+
+ @Test
+ public void givenFiveElementArray_whenOffset0Size3_thenFirstThreeElements() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 0, 3);
+ assertArrayEquals(new int[] { 1, 2, 3 }, value);
+ }
+
+ @Test
+ public void givenFiveElementArray_whenOffset1Size2_thenTwoElements() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 1, 2);
+ assertArrayEquals(new int[] { 2, 3 }, value);
+ }
+
+ @Test
+ public void givenFiveElementArray_whenOffset2SizeTooBig_thenElementsToTheEnd() throws Exception {
+ final FoldingHash hasher = new FoldingHash();
+ final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 2, 2000);
+ assertArrayEquals(new int[] { 3, 4, 5 }, value);
+ }
+
+}
diff --git a/autovalue/pom.xml b/autovalue/pom.xml
index 3ec2d26b35..a10e8ef055 100644
--- a/autovalue/pom.xml
+++ b/autovalue/pom.xml
@@ -29,6 +29,12 @@
+
+ com.google.auto.service
+ auto-service
+ ${auto-service.version}
+ true
+
com.google.inject
@@ -40,6 +46,7 @@
1.3
1.0-beta5
+ 1.0-rc5
4.2.0
diff --git a/autovalue/src/main/java/com/baeldung/autoservice/BingTranslationServiceProvider.java b/autovalue/src/main/java/com/baeldung/autoservice/BingTranslationServiceProvider.java
new file mode 100644
index 0000000000..86d42e80fa
--- /dev/null
+++ b/autovalue/src/main/java/com/baeldung/autoservice/BingTranslationServiceProvider.java
@@ -0,0 +1,14 @@
+package com.baeldung.autoservice;
+
+import com.google.auto.service.AutoService;
+
+import java.util.Locale;
+
+@AutoService(TranslationService.class)
+public class BingTranslationServiceProvider implements TranslationService {
+ @Override
+ public String translate(String message, Locale from, Locale to) {
+ // implementation details
+ return message + " (translated by Bing)";
+ }
+}
diff --git a/autovalue/src/main/java/com/baeldung/autoservice/GoogleTranslationServiceProvider.java b/autovalue/src/main/java/com/baeldung/autoservice/GoogleTranslationServiceProvider.java
new file mode 100644
index 0000000000..0bf91ee5ec
--- /dev/null
+++ b/autovalue/src/main/java/com/baeldung/autoservice/GoogleTranslationServiceProvider.java
@@ -0,0 +1,14 @@
+package com.baeldung.autoservice;
+
+import com.google.auto.service.AutoService;
+
+import java.util.Locale;
+
+@AutoService(TranslationService.class)
+public class GoogleTranslationServiceProvider implements TranslationService {
+ @Override
+ public String translate(String message, Locale from, Locale to) {
+ // implementation details
+ return message + " (translated by Google)";
+ }
+}
diff --git a/autovalue/src/main/java/com/baeldung/autoservice/TranslationService.java b/autovalue/src/main/java/com/baeldung/autoservice/TranslationService.java
new file mode 100644
index 0000000000..580db46cd1
--- /dev/null
+++ b/autovalue/src/main/java/com/baeldung/autoservice/TranslationService.java
@@ -0,0 +1,7 @@
+package com.baeldung.autoservice;
+
+import java.util.Locale;
+
+public interface TranslationService {
+ String translate(String message, Locale from, Locale to);
+}
\ No newline at end of file
diff --git a/autovalue/src/test/java/com/baeldung/autoservice/TranslationServiceUnitTest.java b/autovalue/src/test/java/com/baeldung/autoservice/TranslationServiceUnitTest.java
new file mode 100644
index 0000000000..9e1bd6d291
--- /dev/null
+++ b/autovalue/src/test/java/com/baeldung/autoservice/TranslationServiceUnitTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.autoservice;
+
+import com.baeldung.autoservice.TranslationService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import static org.junit.Assert.assertEquals;
+
+public class TranslationServiceUnitTest {
+
+ private ServiceLoader loader;
+
+ @Before
+ public void setUp() {
+ loader = ServiceLoader.load(TranslationService.class);
+ }
+
+ @Test
+ public void whenServiceLoaderLoads_thenLoadsAllProviders() {
+ long count = StreamSupport.stream(loader.spliterator(), false).count();
+ assertEquals(2, count);
+ }
+
+ @Test
+ public void whenServiceLoaderLoadsGoogleService_thenGoogleIsLoaded() {
+ TranslationService googleService = StreamSupport.stream(loader.spliterator(), false)
+ .filter(p -> p.getClass().getSimpleName().equals("GoogleTranslationServiceProvider"))
+ .findFirst()
+ .get();
+
+ String message = "message";
+ assertEquals(message + " (translated by Google)", googleService.translate(message, null, null));
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/stream/SkipLimitComparison.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/stream/SkipLimitComparison.java
new file mode 100644
index 0000000000..65f12ada45
--- /dev/null
+++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/stream/SkipLimitComparison.java
@@ -0,0 +1,46 @@
+package com.baeldung.stream;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class SkipLimitComparison {
+
+ public static void main(String[] args) {
+ skipExample();
+ limitExample();
+ limitInfiniteStreamExample();
+ getEvenNumbers(10, 10).stream()
+ .forEach(System.out::println);
+ }
+
+ public static void skipExample() {
+ Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ .filter(i -> i % 2 == 0)
+ .skip(2)
+ .forEach(i -> System.out.print(i + " "));
+ }
+
+ public static void limitExample() {
+ Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ .filter(i -> i % 2 == 0)
+ .limit(2)
+ .forEach(i -> System.out.print(i + " "));
+ }
+
+ public static void limitInfiniteStreamExample() {
+ Stream.iterate(0, i -> i + 1)
+ .filter(i -> i % 2 == 0)
+ .limit(10)
+ .forEach(System.out::println);
+ }
+
+ private static List getEvenNumbers(int offset, int limit) {
+ return Stream.iterate(0, i -> i + 1)
+ .filter(i -> i % 2 == 0)
+ .skip(offset)
+ .limit(limit)
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/forEach/ReverseList.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/forEach/ReverseList.java
new file mode 100644
index 0000000000..b2ce77a9f6
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/baeldung/forEach/ReverseList.java
@@ -0,0 +1,84 @@
+package com.baeldung.forEach;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+
+class ReverseList extends ArrayList {
+
+ List list = Arrays.asList("A", "B", "C", "D");
+
+ Consumer removeElement = s -> {
+ System.out.println(s + " " + list.size());
+ if (s != null && s.equals("A")) {
+ list.remove("D");
+ }
+ };
+
+ @Override
+ public Iterator iterator() {
+
+ final int startIndex = this.size() - 1;
+ final List list = this;
+ return new Iterator() {
+
+ int currentIndex = startIndex;
+
+ @Override
+ public boolean hasNext() {
+ return currentIndex >= 0;
+ }
+
+ @Override
+ public String next() {
+ String next = list.get(currentIndex);
+ currentIndex--;
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public void forEach(Consumer super String> action) {
+ for (String s : this) {
+ action.accept(s);
+ }
+ }
+
+ public void iterateParallel() {
+ list.forEach(System.out::print);
+ System.out.print(" ");
+ list.parallelStream().forEach(System.out::print);
+ }
+
+ public void iterateReverse() {
+ List myList = new ReverseList();
+ myList.addAll(list);
+ myList.forEach(System.out::print);
+ System.out.print(" ");
+ myList.stream().forEach(System.out::print);
+ }
+
+ public void removeInCollectionForEach() {
+ list.forEach(removeElement);
+ }
+
+ public void removeInStreamForEach() {
+ list.stream().forEach(removeElement);
+ }
+
+ public static void main(String[] argv) {
+
+ ReverseList collectionForEach = new ReverseList();
+ collectionForEach.iterateParallel();
+ collectionForEach.iterateReverse();
+ collectionForEach.removeInCollectionForEach();
+ collectionForEach.removeInStreamForEach();
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-exceptions/pom.xml b/core-java-modules/core-java-exceptions/pom.xml
index 51c4e51341..37f65882c3 100644
--- a/core-java-modules/core-java-exceptions/pom.xml
+++ b/core-java-modules/core-java-exceptions/pom.xml
@@ -1,26 +1,35 @@
- 4.0.0
- com.baeldung.exception.numberformat
- core-java-exceptions
- 0.0.1-SNAPSHOT
- core-java-exceptions
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ com.baeldung.exception.numberformat
+ core-java-exceptions
+ 0.0.1-SNAPSHOT
+ core-java-exceptions
-
- com.baeldung
- parent-java
- 0.0.1-SNAPSHOT
- ../../parent-java
-
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../../parent-java
+
-
-
- junit
- junit
- 4.12
- test
-
-
+
+ 3.9
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/exceptions/RootCauseFinder.java b/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/RootCauseFinder.java
similarity index 100%
rename from core-java-modules/core-java/src/main/java/com/baeldung/exceptions/RootCauseFinder.java
rename to core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/RootCauseFinder.java
diff --git a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java b/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java
index de56fb7113..6dcd0d72e0 100644
--- a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java
+++ b/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java
@@ -1,7 +1,6 @@
-package com.baeldung.error;
+package com.baeldung.exception.error;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
public class ErrorGeneratorUnitTest {
diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/exceptions/RootCauseFinderUnitTest.java b/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/RootCauseFinderUnitTest.java
similarity index 100%
rename from core-java-modules/core-java/src/test/java/com/baeldung/exceptions/RootCauseFinderUnitTest.java
rename to core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/RootCauseFinderUnitTest.java
diff --git a/core-java-modules/core-java-lambdas/README.MD b/core-java-modules/core-java-lambdas/README.MD
deleted file mode 100644
index 31790ffbb1..0000000000
--- a/core-java-modules/core-java-lambdas/README.MD
+++ /dev/null
@@ -1,3 +0,0 @@
-### Relevant Articles
-
-- [Why Do Local Variables Used in Lambdas Have to Be Final or Effectively Final?](https://www.baeldung.com/java-lambda-effectively-final-local-variables)
diff --git a/core-java-modules/core-java-lambdas/README.md b/core-java-modules/core-java-lambdas/README.md
deleted file mode 100644
index 10b876735e..0000000000
--- a/core-java-modules/core-java-lambdas/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## Relevant articles:
-
-- [Why Do Local Variables Used in Lambdas Have to Be Final or Effectively Final?](https://www.baeldung.com/java-lambda-effectively-final-local-variables)
diff --git a/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/rawtype/RawTypeDemo.java b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/rawtype/RawTypeDemo.java
new file mode 100644
index 0000000000..e358219d24
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/rawtype/RawTypeDemo.java
@@ -0,0 +1,25 @@
+package com.baeldung.rawtype;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RawTypeDemo {
+
+ public static void main(String[] args) {
+ RawTypeDemo rawTypeDemo = new RawTypeDemo();
+ rawTypeDemo.methodA();
+ }
+
+ public void methodA() {
+ // parameterized type
+ List listStr = new ArrayList<>();
+ listStr.add("Hello Folks!");
+ methodB(listStr);
+ String s = listStr.get(1); // ClassCastException at run time
+ }
+
+ public void methodB(List rawList) { // Inexpressive raw type
+ rawList.add(1); // Unsafe operation
+ }
+
+}
diff --git a/java-collections-conversions/src/test/java/com/baeldung/convertiteratortolist/ConvertIteratorToListServiceUnitTest.java b/java-collections-conversions/src/test/java/com/baeldung/convertiteratortolist/ConvertIteratorToListServiceUnitTest.java
new file mode 100644
index 0000000000..4d6cba7d27
--- /dev/null
+++ b/java-collections-conversions/src/test/java/com/baeldung/convertiteratortolist/ConvertIteratorToListServiceUnitTest.java
@@ -0,0 +1,100 @@
+package com.baeldung.convertiteratortolist;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.apache.commons.collections4.IteratorUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class ConvertIteratorToListServiceUnitTest {
+
+ Iterator iterator;
+
+ @Before
+ public void setUp() throws Exception {
+ iterator = Arrays.asList(1, 2, 3)
+ .iterator();
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToListUsingWhileLoop_thenReturnAList() {
+
+ List actualList = new ArrayList();
+
+ // Convert Iterator to List using while loop dsf
+ while (iterator.hasNext()) {
+ actualList.add(iterator.next());
+ }
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToListAfterJava8_thenReturnAList() {
+ List actualList = new ArrayList();
+
+ // Convert Iterator to List using Java 8
+ iterator.forEachRemaining(actualList::add);
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToListJava8Stream_thenReturnAList() {
+
+ // Convert iterator to iterable
+ Iterable iterable = () -> iterator;
+
+ // Extract List from stream
+ List actualList = StreamSupport
+ .stream(iterable.spliterator(), false)
+ .collect(Collectors.toList());
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToImmutableListWithGuava_thenReturnAList() {
+
+ // Convert Iterator to an Immutable list using Guava library in Java
+ List actualList = ImmutableList.copyOf(iterator);
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToMutableListWithGuava_thenReturnAList() {
+
+ // Convert Iterator to a mutable list using Guava library in Java
+ List actualList = Lists.newArrayList(iterator);
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+
+ @Test
+ public void givenAnIterator_whenConvertIteratorToMutableListWithApacheCommons_thenReturnAList() {
+
+ // Convert Iterator to a mutable list using Apache Commons library in Java
+ List actualList = IteratorUtils.toList(iterator);
+
+ assertThat(actualList, hasSize(3));
+ assertThat(actualList, containsInAnyOrder(1, 2, 3));
+ }
+}
diff --git a/java-collections-conversions/src/test/java/org/baeldung/java/collections/IterableToCollectionUnitTest.java b/java-collections-conversions/src/test/java/org/baeldung/java/collections/IterableToCollectionUnitTest.java
new file mode 100644
index 0000000000..f2c80429d1
--- /dev/null
+++ b/java-collections-conversions/src/test/java/org/baeldung/java/collections/IterableToCollectionUnitTest.java
@@ -0,0 +1,122 @@
+package org.baeldung.java.collections;
+
+import static org.hamcrest.Matchers.contains;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.IteratorUtils;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class IterableToCollectionUnitTest {
+
+ Iterable iterable = Arrays.asList("john", "tom", "jane");
+ Iterator iterator = iterable.iterator();
+
+ @Test
+ public void whenConvertIterableToListUsingJava_thenSuccess() {
+ List result = new ArrayList();
+ for (String str : iterable) {
+ result.add(str);
+ }
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIterableToListUsingJava8_thenSuccess() {
+ List result = new ArrayList();
+ iterable.forEach(result::add);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIterableToListUsingJava8WithSpliterator_thenSuccess() {
+ List result = StreamSupport.stream(iterable.spliterator(), false)
+ .collect(Collectors.toList());
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIterableToListUsingGuava_thenSuccess() {
+ List result = Lists.newArrayList(iterable);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIterableToImmutableListUsingGuava_thenSuccess() {
+ List result = ImmutableList.copyOf(iterable);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIterableToListUsingApacheCommons_thenSuccess() {
+ List result = IterableUtils.toList(iterable);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ // ======================== Iterator
+
+ @Test
+ public void whenConvertIteratorToListUsingJava_thenSuccess() {
+ List result = new ArrayList();
+ while (iterator.hasNext()) {
+ result.add(iterator.next());
+ }
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIteratorToListUsingJava8_thenSuccess() {
+ List result = new ArrayList();
+ iterator.forEachRemaining(result::add);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIteratorToListUsingJava8WithSpliterator_thenSuccess() {
+ List result = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
+ .collect(Collectors.toList());
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIteratorToListUsingGuava_thenSuccess() {
+ List result = Lists.newArrayList(iterator);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIteratorToImmutableListUsingGuava_thenSuccess() {
+ List result = ImmutableList.copyOf(iterator);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+
+ @Test
+ public void whenConvertIteratorToListUsingApacheCommons_thenSuccess() {
+ List result = IteratorUtils.toList(iterator);
+
+ assertThat(result, contains("john", "tom", "jane"));
+ }
+}
diff --git a/java-streams/src/test/java/com/baeldung/intstreams/conversion/IntStreamsConversionsUnitTest.java b/java-streams/src/test/java/com/baeldung/intstreams/conversion/IntStreamsConversionsUnitTest.java
new file mode 100644
index 0000000000..6cd773e634
--- /dev/null
+++ b/java-streams/src/test/java/com/baeldung/intstreams/conversion/IntStreamsConversionsUnitTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.intstreams.conversion;
+
+import org.junit.Test;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IntStreamsConversionsUnitTest {
+
+ @Test
+ public void intStreamToArray() {
+ int[] first50EvenNumbers = IntStream.iterate(0, i -> i + 2)
+ .limit(50)
+ .toArray();
+
+ assertThat(first50EvenNumbers).hasSize(50);
+ assertThat(first50EvenNumbers[2]).isEqualTo(4);
+ }
+
+ @Test
+ public void intStreamToList() {
+ List first50IntegerNumbers = IntStream.range(0, 50)
+ .boxed()
+ .collect(Collectors.toList());
+
+ assertThat(first50IntegerNumbers).hasSize(50);
+ assertThat(first50IntegerNumbers.get(2)).isEqualTo(2);
+ }
+
+ @Test
+ public void intStreamToString() {
+ String first3numbers = IntStream.of(0, 1, 2)
+ .mapToObj(String::valueOf)
+ .collect(Collectors.joining(", ", "[", "]"));
+
+ assertThat(first3numbers).isEqualTo("[0, 1, 2]");
+ }
+}
diff --git a/libraries-2/pom.xml b/libraries-2/pom.xml
index 8e493e2d05..c18b4aae64 100644
--- a/libraries-2/pom.xml
+++ b/libraries-2/pom.xml
@@ -50,11 +50,42 @@
picocli
${picocli.version}
+
+ org.ejml
+ ejml-all
+ ${ejml.version}
+
+
+ org.nd4j
+ nd4j-native
+ ${nd4j.version}
+
+
+ org.la4j
+ la4j
+ ${la4j.version}
+
+
+ colt
+ colt
+ ${colt.version}
+
org.springframework.boot
spring-boot-starter
${spring-boot-starter.version}
+
+ net.openhft
+ chronicle-map
+ ${chronicle.map.version}
+
+
+ com.sun.java
+ tools
+
+
+
@@ -82,10 +113,22 @@
test
-
- edu.uci.ics
- crawler4j
- ${crawler4j.version}
+
+ edu.uci.ics
+ crawler4j
+ ${crawler4j.version}
+
+
+
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
@@ -95,7 +138,13 @@
4.8.28
6.0.0.Final
3.9.6
+ 3.17.2
4.4.0
2.1.4.RELEASE
+ 0.38
+ 1.0.0-beta4
+ 1.2.0
+ 0.6.0
+ 1.19
diff --git a/libraries-2/src/test/java/com/baeldung/chroniclemap/ChronicleMapUnitTest.java b/libraries-2/src/test/java/com/baeldung/chroniclemap/ChronicleMapUnitTest.java
new file mode 100644
index 0000000000..7f36a9abdb
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/chroniclemap/ChronicleMapUnitTest.java
@@ -0,0 +1,132 @@
+package com.baeldung.chroniclemap;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import net.openhft.chronicle.core.values.LongValue;
+import net.openhft.chronicle.map.ChronicleMap;
+import net.openhft.chronicle.map.ExternalMapQueryContext;
+import net.openhft.chronicle.map.MapEntry;
+import net.openhft.chronicle.values.Values;
+
+public class ChronicleMapUnitTest {
+
+ static ChronicleMap persistedCountryMap = null;
+
+ static ChronicleMap inMemoryCountryMap = null;
+
+ static ChronicleMap> multiMap = null;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @BeforeClass
+ public static void init() {
+ try {
+ inMemoryCountryMap = ChronicleMap.of(LongValue.class, CharSequence.class)
+ .name("country-map")
+ .entries(50)
+ .averageValue("America")
+ .create();
+
+ persistedCountryMap = ChronicleMap.of(LongValue.class, CharSequence.class)
+ .name("country-map")
+ .entries(50)
+ .averageValue("America")
+ .createPersistedTo(new File(System.getProperty("user.home") + "/country-details.dat"));
+
+ Set averageValue = IntStream.of(1, 2)
+ .boxed()
+ .collect(Collectors.toSet());
+ multiMap = ChronicleMap.of(Integer.class, (Class>) (Class) Set.class)
+ .name("multi-map")
+ .entries(50)
+ .averageValue(averageValue)
+ .create();
+
+ LongValue qatarKey = Values.newHeapInstance(LongValue.class);
+ qatarKey.setValue(1);
+ inMemoryCountryMap.put(qatarKey, "Qatar");
+
+ LongValue key = Values.newHeapInstance(LongValue.class);
+ key.setValue(1);
+ persistedCountryMap.put(key, "Romania");
+ key.setValue(2);
+ persistedCountryMap.put(key, "India");
+
+ Set set1 = new HashSet<>();
+ set1.add(1);
+ set1.add(2);
+ multiMap.put(1, set1);
+
+ Set set2 = new HashSet<>();
+ set2.add(3);
+ multiMap.put(2, set2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void givenGetQuery_whenCalled_shouldReturnResult() {
+ LongValue key = Values.newHeapInstance(LongValue.class);
+ key.setValue(1);
+ CharSequence country = inMemoryCountryMap.get(key);
+ assertThat(country.toString(), is(equalTo("Qatar")));
+ }
+
+ @Test
+ public void givenGetUsingQuery_whenCalled_shouldReturnResult() {
+ LongValue key = Values.newHeapInstance(LongValue.class);
+ StringBuilder country = new StringBuilder();
+ key.setValue(1);
+ persistedCountryMap.getUsing(key, country);
+ assertThat(country.toString(), is(equalTo("Romania")));
+ key.setValue(2);
+ persistedCountryMap.getUsing(key, country);
+ assertThat(country.toString(), is(equalTo("India")));
+ }
+
+ @Test
+ public void givenMultipleKeyQuery_whenProcessed_shouldChangeTheValue() {
+ try (ExternalMapQueryContext, ?> fistContext = multiMap.queryContext(1)) {
+ try (ExternalMapQueryContext, ?> secondContext = multiMap.queryContext(2)) {
+ fistContext.updateLock()
+ .lock();
+ secondContext.updateLock()
+ .lock();
+ MapEntry> firstEntry = fistContext.entry();
+ Set firstSet = firstEntry.value()
+ .get();
+ firstSet.remove(2);
+ MapEntry> secondEntry = secondContext.entry();
+ Set secondSet = secondEntry.value()
+ .get();
+ secondSet.add(4);
+ firstEntry.doReplaceValue(fistContext.wrapValueAsData(firstSet));
+ secondEntry.doReplaceValue(secondContext.wrapValueAsData(secondSet));
+ }
+ } finally {
+ assertThat(multiMap.get(1)
+ .size(), is(equalTo(1)));
+ assertThat(multiMap.get(2)
+ .size(), is(equalTo(2)));
+ }
+ }
+
+ @AfterClass
+ public static void finish() {
+ persistedCountryMap.close();
+ inMemoryCountryMap.close();
+ multiMap.close();
+ }
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java b/libraries-2/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java
new file mode 100644
index 0000000000..1e3b183aa7
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java
@@ -0,0 +1,9 @@
+package com.baeldung.matrices;
+
+public class MatrixMultiplicationBenchmarking {
+
+ public static void main(String[] args) throws Exception {
+ org.openjdk.jmh.Main.main(args);
+ }
+
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java
new file mode 100644
index 0000000000..05944e7b3a
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java
@@ -0,0 +1,47 @@
+package com.baeldung.matrices.apache;
+
+import org.apache.commons.math3.linear.Array2DRowRealMatrix;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.junit.jupiter.api.Test;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class RealMatrixUnitTest {
+
+ @Test
+ @Benchmark
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ RealMatrix firstMatrix = new Array2DRowRealMatrix(
+ new double[][] {
+ new double[] {1d, 5d},
+ new double[] {2d, 3d},
+ new double[] {1d ,7d}
+ }
+ );
+
+ RealMatrix secondMatrix = new Array2DRowRealMatrix(
+ new double[][] {
+ new double[] {1d, 2d, 3d, 7d},
+ new double[] {5d, 2d, 8d, 1d}
+ }
+ );
+
+ RealMatrix expected = new Array2DRowRealMatrix(
+ new double[][] {
+ new double[] {26d, 12d, 43d, 12d},
+ new double[] {17d, 10d, 30d, 17d},
+ new double[] {36d, 16d, 59d, 14d}
+ }
+ );
+
+ RealMatrix actual = firstMatrix.multiply(secondMatrix);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java
new file mode 100644
index 0000000000..fb4a419eb0
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.matrices.colt;
+
+import cern.colt.matrix.DoubleFactory2D;
+import cern.colt.matrix.DoubleMatrix2D;
+import cern.colt.matrix.linalg.Algebra;
+import org.junit.jupiter.api.Test;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class DoubleMatrix2DUnitTest {
+
+ @Test
+ @Benchmark
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ DoubleFactory2D doubleFactory2D = DoubleFactory2D.dense;
+
+ DoubleMatrix2D firstMatrix = doubleFactory2D.make(
+ new double[][] {
+ new double[] {1d, 5d},
+ new double[] {2d, 3d},
+ new double[] {1d ,7d}
+ }
+ );
+
+ DoubleMatrix2D secondMatrix = doubleFactory2D.make(
+ new double[][] {
+ new double[] {1d, 2d, 3d, 7d},
+ new double[] {5d, 2d, 8d, 1d}
+ }
+ );
+
+ DoubleMatrix2D expected = doubleFactory2D.make(
+ new double[][] {
+ new double[] {26d, 12d, 43d, 12d},
+ new double[] {17d, 10d, 30d, 17d},
+ new double[] {36d, 16d, 59d, 14d}
+ }
+ );
+
+ Algebra algebra = new Algebra();
+ DoubleMatrix2D actual = algebra.mult(firstMatrix, secondMatrix);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java
new file mode 100644
index 0000000000..b025266a1d
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.matrices.ejml;
+
+import org.ejml.simple.SimpleMatrix;
+import org.junit.jupiter.api.Test;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class SimpleMatrixUnitTest {
+
+ @Test
+ @Benchmark
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ SimpleMatrix firstMatrix = new SimpleMatrix(
+ new double[][] {
+ new double[] {1d, 5d},
+ new double[] {2d, 3d},
+ new double[] {1d ,7d}
+ }
+ );
+
+ SimpleMatrix secondMatrix = new SimpleMatrix(
+ new double[][] {
+ new double[] {1d, 2d, 3d, 7d},
+ new double[] {5d, 2d, 8d, 1d}
+ }
+ );
+
+ SimpleMatrix expected = new SimpleMatrix(
+ new double[][] {
+ new double[] {26d, 12d, 43d, 12d},
+ new double[] {17d, 10d, 30d, 17d},
+ new double[] {36d, 16d, 59d, 14d}
+ }
+ );
+
+ SimpleMatrix actual = firstMatrix.mult(secondMatrix);
+
+ assertThat(actual).matches(m -> m.isIdentical(expected, 0d));
+ }
+
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java
new file mode 100644
index 0000000000..be9e483d5b
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java
@@ -0,0 +1,58 @@
+package com.baeldung.matrices.homemade;
+
+import org.junit.jupiter.api.Test;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class HomemadeMatrixUnitTest {
+
+ @Test
+ @Benchmark
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ double[][] firstMatrix = {
+ new double[]{1d, 5d},
+ new double[]{2d, 3d},
+ new double[]{1d, 7d}
+ };
+
+ double[][] secondMatrix = {
+ new double[]{1d, 2d, 3d, 7d},
+ new double[]{5d, 2d, 8d, 1d}
+ };
+
+ double[][] expected = {
+ new double[]{26d, 12d, 43d, 12d},
+ new double[]{17d, 10d, 30d, 17d},
+ new double[]{36d, 16d, 59d, 14d}
+ };
+
+ double[][] actual = multiplyMatrices(firstMatrix, secondMatrix);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ private double[][] multiplyMatrices(double[][] firstMatrix, double[][] secondMatrix) {
+ double[][] result = new double[firstMatrix.length][secondMatrix[0].length];
+
+ for (int row = 0; row < result.length; row++) {
+ for (int col = 0; col < result[row].length; col++) {
+ result[row][col] = multiplyMatricesCell(firstMatrix, secondMatrix, row, col);
+ }
+ }
+
+ return result;
+ }
+
+ private double multiplyMatricesCell(double[][] firstMatrix, double[][] secondMatrix, int row, int col) {
+ double cell = 0;
+ for (int i = 0; i < secondMatrix.length; i++) {
+ cell += firstMatrix[row][i] * secondMatrix[i][col];
+ }
+ return cell;
+ }
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java
new file mode 100644
index 0000000000..afb84ff3db
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java
@@ -0,0 +1,47 @@
+package com.baeldung.matrices.la4j;
+
+import org.junit.jupiter.api.Test;
+import org.la4j.Matrix;
+import org.la4j.matrix.dense.Basic2DMatrix;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class Basic2DMatrixUnitTest {
+
+ @Test
+ @Benchmark
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ Matrix firstMatrix = new Basic2DMatrix(
+ new double[][]{
+ new double[]{1d, 5d},
+ new double[]{2d, 3d},
+ new double[]{1d, 7d}
+ }
+ );
+
+ Matrix secondMatrix = new Basic2DMatrix(
+ new double[][]{
+ new double[]{1d, 2d, 3d, 7d},
+ new double[]{5d, 2d, 8d, 1d}
+ }
+ );
+
+ Matrix expected = new Basic2DMatrix(
+ new double[][]{
+ new double[]{26d, 12d, 43d, 12d},
+ new double[]{17d, 10d, 30d, 17d},
+ new double[]{36d, 16d, 59d, 14d}
+ }
+ );
+
+ Matrix actual = firstMatrix.multiply(secondMatrix);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+}
diff --git a/libraries-2/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java b/libraries-2/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java
new file mode 100644
index 0000000000..fb3030bccf
--- /dev/null
+++ b/libraries-2/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.matrices.nd4j;
+
+import org.junit.jupiter.api.Test;
+import org.nd4j.linalg.api.ndarray.INDArray;
+import org.nd4j.linalg.factory.Nd4j;
+import org.openjdk.jmh.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 2)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+public class INDArrayUnitTest {
+
+ @Test
+ public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ INDArray firstMatrix = Nd4j.create(
+ new double[][]{
+ new double[]{1d, 5d},
+ new double[]{2d, 3d},
+ new double[]{1d, 7d}
+ }
+ );
+
+ INDArray secondMatrix = Nd4j.create(
+ new double[][] {
+ new double[] {1d, 2d, 3d, 7d},
+ new double[] {5d, 2d, 8d, 1d}
+ }
+ );
+
+ INDArray expected = Nd4j.create(
+ new double[][] {
+ new double[] {26d, 12d, 43d, 12d},
+ new double[] {17d, 10d, 30d, 17d},
+ new double[] {36d, 16d, 59d, 14d}
+ }
+ );
+
+ INDArray actual = firstMatrix.mmul(secondMatrix);
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+}
diff --git a/libraries-server/pom.xml b/libraries-server/pom.xml
index a6ead8fb31..873cca9b9b 100644
--- a/libraries-server/pom.xml
+++ b/libraries-server/pom.xml
@@ -96,6 +96,19 @@
smack-java7
${smack.version}
+
+
+
+ org.nanohttpd
+ nanohttpd
+ ${nanohttpd.version}
+
+
+ org.nanohttpd
+ nanohttpd-nanolets
+ ${nanohttpd.version}
+
+
@@ -108,6 +121,7 @@
8.5.24
4.3.1
1.2.0
+ 2.3.1
\ No newline at end of file
diff --git a/libraries-server/src/main/java/com/baeldung/nanohttpd/ApplicationController.java b/libraries-server/src/main/java/com/baeldung/nanohttpd/ApplicationController.java
new file mode 100644
index 0000000000..2fa54c3ae2
--- /dev/null
+++ b/libraries-server/src/main/java/com/baeldung/nanohttpd/ApplicationController.java
@@ -0,0 +1,38 @@
+package com.baeldung.nanohttpd;
+
+import fi.iki.elonen.NanoHTTPD;
+import fi.iki.elonen.router.RouterNanoHTTPD;
+
+import java.io.IOException;
+
+public class ApplicationController extends RouterNanoHTTPD {
+
+ ApplicationController() throws IOException {
+ super(8072);
+ addMappings();
+ start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
+ }
+
+ @Override
+ public void addMappings() {
+ addRoute("/", IndexHandler.class);
+ addRoute("/users", UserHandler.class);
+ }
+
+ public static class UserHandler extends DefaultHandler {
+ @Override
+ public String getText() {
+ return "UserA, UserB, UserC";
+ }
+
+ @Override
+ public String getMimeType() {
+ return MIME_PLAINTEXT;
+ }
+
+ @Override
+ public Response.IStatus getStatus() {
+ return Response.Status.OK;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries-server/src/main/java/com/baeldung/nanohttpd/ItemGetController.java b/libraries-server/src/main/java/com/baeldung/nanohttpd/ItemGetController.java
new file mode 100644
index 0000000000..4a9c48fbfd
--- /dev/null
+++ b/libraries-server/src/main/java/com/baeldung/nanohttpd/ItemGetController.java
@@ -0,0 +1,22 @@
+package com.baeldung.nanohttpd;
+
+import fi.iki.elonen.NanoHTTPD;
+
+import java.io.IOException;
+
+public class ItemGetController extends NanoHTTPD {
+
+ ItemGetController() throws IOException {
+ super(8071);
+ start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
+ }
+
+ @Override
+ public Response serve(IHTTPSession session) {
+ if (session.getMethod() == Method.GET) {
+ String itemIdRequestParam = session.getParameters().get("itemId").get(0);
+ return newFixedLengthResponse("Requested itemId = " + itemIdRequestParam);
+ }
+ return newFixedLengthResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "The requested resource does not exist");
+ }
+}
\ No newline at end of file
diff --git a/libraries-server/src/test/java/com/baeldung/nanohttpd/ApplicationControllerUnitTest.java b/libraries-server/src/test/java/com/baeldung/nanohttpd/ApplicationControllerUnitTest.java
new file mode 100644
index 0000000000..003f6ee3b7
--- /dev/null
+++ b/libraries-server/src/test/java/com/baeldung/nanohttpd/ApplicationControllerUnitTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.nanohttpd;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class ApplicationControllerUnitTest {
+
+ private static final String BASE_URL = "http://localhost:8072/";
+ private static final HttpClient CLIENT = HttpClientBuilder.create().build();
+
+ @BeforeClass
+ public static void setUp() throws IOException {
+ new ApplicationController();
+ }
+
+ @Test
+ public void givenServer_whenRootRouteRequested_thenHelloWorldReturned() throws IOException {
+ HttpResponse response = CLIENT.execute(new HttpGet(BASE_URL));
+ assertTrue(IOUtils.toString(response.getEntity().getContent()).contains("Hello world!"));
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void givenServer_whenUsersRequested_thenThenAllUsersReturned() throws IOException {
+ HttpResponse response = CLIENT.execute(new HttpGet(BASE_URL + "users"));
+ assertEquals("UserA, UserB, UserC", IOUtils.toString(response.getEntity().getContent()));
+ }
+}
\ No newline at end of file
diff --git a/libraries-server/src/test/java/com/baeldung/nanohttpd/ItemGetControllerUnitTest.java b/libraries-server/src/test/java/com/baeldung/nanohttpd/ItemGetControllerUnitTest.java
new file mode 100644
index 0000000000..3a4f0a4d98
--- /dev/null
+++ b/libraries-server/src/test/java/com/baeldung/nanohttpd/ItemGetControllerUnitTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.nanohttpd;
+
+import static org.junit.Assert.*;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class ItemGetControllerUnitTest {
+
+ private static final String URL = "http://localhost:8071";
+ private static final HttpClient CLIENT = HttpClientBuilder.create().build();
+
+ @BeforeClass
+ public static void setUp() throws IOException {
+ new ItemGetController();
+ }
+
+ @Test
+ public void givenServer_whenDoingGet_thenParamIsReadCorrectly() throws IOException {
+ HttpResponse response = CLIENT.execute(new HttpGet(URL + "?itemId=1234"));
+ assertEquals("Requested itemId = 1234", IOUtils.toString(response.getEntity().getContent()));
+ }
+
+ @Test
+ public void givenServer_whenDoingPost_then404IsReturned() throws IOException {
+ HttpResponse response = CLIENT.execute(new HttpPost(URL));
+ assertEquals(404, response.getStatusLine().getStatusCode());
+ }
+}
\ No newline at end of file
diff --git a/parent-boot-performance/README.md b/parent-boot-performance/README.md
new file mode 100644
index 0000000000..fce9e101da
--- /dev/null
+++ b/parent-boot-performance/README.md
@@ -0,0 +1 @@
+This is a parent module for projects that want to take advantage of the latest Spring Boot improvements/features.
\ No newline at end of file
diff --git a/parent-boot-performance/pom.xml b/parent-boot-performance/pom.xml
new file mode 100644
index 0000000000..b1c6854eae
--- /dev/null
+++ b/parent-boot-performance/pom.xml
@@ -0,0 +1,91 @@
+
+ 4.0.0
+ parent-boot-performance
+ 0.0.1-SNAPSHOT
+ parent-boot-performance
+ pom
+ Parent for all modules that want to take advantage of the latest Spring Boot improvements/features. Current version: 2.2
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+ 3.1.0
+
+ 1.0.21.RELEASE
+ 2.2.0.M3
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+ io.rest-assured
+ rest-assured
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+ ${start-class}
+
+
+
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+
+
+
+
+ thin-jar
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.springframework.boot.experimental
+ spring-boot-thin-layout
+ ${thin.version}
+
+
+
+
+
+
+
+
diff --git a/persistence-modules/elasticsearch/.gitignore b/persistence-modules/elasticsearch/.gitignore
new file mode 100644
index 0000000000..153c9335eb
--- /dev/null
+++ b/persistence-modules/elasticsearch/.gitignore
@@ -0,0 +1,29 @@
+HELP.md
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
+
+### VS Code ###
+.vscode/
diff --git a/persistence-modules/elasticsearch/pom.xml b/persistence-modules/elasticsearch/pom.xml
new file mode 100644
index 0000000000..ceed88aa24
--- /dev/null
+++ b/persistence-modules/elasticsearch/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+ com.baeldung
+ elasticsearch
+ 0.0.1-SNAPSHOT
+ elasticsearch
+ Demo project for Java Elasticsearch libraries
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../../
+
+
+
+
+
+ io.searchbox
+ jest
+ 6.3.1
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.6
+
+
+
diff --git a/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/Employee.java b/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/Employee.java
new file mode 100644
index 0000000000..6f28a42a9c
--- /dev/null
+++ b/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/Employee.java
@@ -0,0 +1,42 @@
+package com.baeldung.jest;
+
+import java.util.List;
+
+public class Employee {
+ String name;
+ String title;
+ List skills;
+ int yearsOfService;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public List getSkills() {
+ return skills;
+ }
+
+ public void setSkills(List skills) {
+ this.skills = skills;
+ }
+
+ public int getYearsOfService() {
+ return yearsOfService;
+ }
+
+ public void setYearsOfService(int yearsOfService) {
+ this.yearsOfService = yearsOfService;
+ }
+}
diff --git a/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/JestDemoApplication.java b/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/JestDemoApplication.java
new file mode 100644
index 0000000000..91e499da2e
--- /dev/null
+++ b/persistence-modules/elasticsearch/src/main/java/com/baeldung/jest/JestDemoApplication.java
@@ -0,0 +1,174 @@
+package com.baeldung.jest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.searchbox.client.JestClient;
+import io.searchbox.client.JestClientFactory;
+import io.searchbox.client.JestResult;
+import io.searchbox.client.JestResultHandler;
+import io.searchbox.client.config.HttpClientConfig;
+import io.searchbox.core.*;
+import io.searchbox.indices.CreateIndex;
+import io.searchbox.indices.IndicesExists;
+import io.searchbox.indices.aliases.AddAliasMapping;
+import io.searchbox.indices.aliases.ModifyAliases;
+import io.searchbox.indices.aliases.RemoveAliasMapping;
+
+import java.io.IOException;
+import java.util.*;
+
+public class JestDemoApplication {
+
+ public static void main(String[] args) throws IOException {
+
+ // Demo the JestClient
+ JestClient jestClient = jestClient();
+
+ // Check an index
+ JestResult result = jestClient.execute(new IndicesExists.Builder("employees").build());
+ if(!result.isSucceeded()) {
+ System.out.println(result.getErrorMessage());
+ }
+
+ // Create an index
+ jestClient.execute(new CreateIndex.Builder("employees").build());
+
+ // Create an index with options
+ Map settings = new HashMap<>();
+ settings.put("number_of_shards", 11);
+ settings.put("number_of_replicas", 2);
+ jestClient.execute(new CreateIndex.Builder("employees").settings(settings).build());
+
+ // Create an alias, then remove it
+ jestClient.execute(new ModifyAliases.Builder(
+ new AddAliasMapping.Builder(
+ "employees",
+ "e")
+ .build())
+ .build());
+ JestResult jestResult = jestClient.execute(new ModifyAliases.Builder(
+ new RemoveAliasMapping.Builder(
+ "employees",
+ "e")
+ .build())
+ .build());
+
+ if(jestResult.isSucceeded()) {
+ System.out.println("Success!");
+ }
+ else {
+ System.out.println(jestResult.getErrorMessage());
+ }
+
+ // Sample JSON for indexing
+
+ // {
+ // "name": "Michael Pratt",
+ // "title": "Java Developer",
+ // "skills": ["java", "spring", "elasticsearch"],
+ // "yearsOfService": 2
+ // }
+
+ // Index a document from String
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode employeeJsonNode = mapper.createObjectNode()
+ .put("name", "Michael Pratt")
+ .put("title", "Java Developer")
+ .put("yearsOfService", 2)
+ .set("skills", mapper.createArrayNode()
+ .add("java")
+ .add("spring")
+ .add("elasticsearch"));
+ jestClient.execute(new Index.Builder(employeeJsonNode.toString()).index("employees").build());
+
+ // Index a document from Map
+ Map employeeHashMap = new LinkedHashMap<>();
+ employeeHashMap.put("name", "Michael Pratt");
+ employeeHashMap.put("title", "Java Developer");
+ employeeHashMap.put("yearsOfService", 2);
+ employeeHashMap.put("skills", Arrays.asList("java", "spring", "elasticsearch"));
+ jestClient.execute(new Index.Builder(employeeHashMap).index("employees").build());
+
+ // Index a document from POJO
+ Employee employee = new Employee();
+ employee.setName("Michael Pratt");
+ employee.setTitle("Java Developer");
+ employee.setYearsOfService(2);
+ employee.setSkills(Arrays.asList("java", "spring", "elasticsearch"));
+ jestClient.execute(new Index.Builder(employee).index("employees").build());
+
+ // Read document by ID
+ Employee getResult = jestClient.execute(new Get.Builder("employees", "1").build()).getSourceAsObject(Employee.class);
+
+ // Search documents
+ String search = "{\n" +
+ " \"query\": {\n" +
+ " \"bool\": {\n" +
+ " \"must\": [\n" +
+ " { \"match\": { \"name\": \"Michael Pratt\" }}\n" +
+ " ]\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ List> searchResults =
+ jestClient.execute(new Search.Builder(search).build())
+ .getHits(Employee.class);
+
+ searchResults.forEach(hit -> {
+ System.out.println(String.format("Document %s has score %s", hit.id, hit.score));
+ });
+
+ // Update document
+ employee.setYearsOfService(3);
+ jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());
+
+ // Delete documents
+ jestClient.execute(new Delete.Builder("2") .index("employees") .build());
+
+ // Bulk operations
+ Employee employeeObject1 = new Employee();
+ employee.setName("John Smith");
+ employee.setTitle("Python Developer");
+ employee.setYearsOfService(10);
+ employee.setSkills(Arrays.asList("python"));
+
+ Employee employeeObject2 = new Employee();
+ employee.setName("Kate Smith");
+ employee.setTitle("Senior JavaScript Developer");
+ employee.setYearsOfService(10);
+ employee.setSkills(Arrays.asList("javascript", "angular"));
+
+ jestClient.execute(new Bulk.Builder().defaultIndex("employees")
+ .addAction(new Index.Builder(employeeObject1).build())
+ .addAction(new Index.Builder(employeeObject2).build())
+ .addAction(new Delete.Builder("3").build()) .build());
+
+ // Async operations
+ Employee employeeObject3 = new Employee();
+ employee.setName("Jane Doe");
+ employee.setTitle("Manager");
+ employee.setYearsOfService(20);
+ employee.setSkills(Arrays.asList("managing"));
+
+ jestClient.executeAsync( new Index.Builder(employeeObject3).build(), new JestResultHandler() {
+ @Override public void completed(JestResult result) {
+ // handle result
+ }
+ @Override public void failed(Exception ex) {
+ // handle exception
+ }
+ });
+ }
+
+ private static JestClient jestClient()
+ {
+ JestClientFactory factory = new JestClientFactory();
+ factory.setHttpClientConfig(
+ new HttpClientConfig.Builder("http://localhost:9200")
+ .multiThreaded(true)
+ .defaultMaxTotalConnectionPerRoute(2)
+ .maxTotalConnection(20)
+ .build());
+ return factory.getObject();
+ }
+}
diff --git a/persistence-modules/java-jpa/pom.xml b/persistence-modules/java-jpa/pom.xml
index f23040fbdc..51cc401332 100644
--- a/persistence-modules/java-jpa/pom.xml
+++ b/persistence-modules/java-jpa/pom.xml
@@ -19,6 +19,11 @@
hibernate-core
${hibernate.version}
+
+ org.hibernate
+ hibernate-jpamodelgen
+ ${hibernate.version}
+
com.h2database
h2
@@ -47,6 +52,58 @@
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ -proc:none
+
+
+
+ org.bsc.maven
+ maven-processor-plugin
+ 3.3.3
+
+
+ process
+
+ process
+
+ generate-sources
+
+ target/metamodel
+
+ org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.0.0
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ target/metamodel
+
+
+
+
+
+
+
5.4.0.Final
2.7.4-RC1
diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/queryparams/Employee.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/queryparams/Employee.java
new file mode 100644
index 0000000000..bf3d459530
--- /dev/null
+++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/queryparams/Employee.java
@@ -0,0 +1,79 @@
+package com.baeldung.jpa.queryparams;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "employees")
+public class Employee {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "employee_number", unique = true)
+ private String empNumber;
+
+ @Column(name = "employee_name")
+ private String name;
+
+ @Column(name = "employee_age")
+ private int age;
+
+ public Employee() {
+ super();
+ }
+
+ public Employee(Long id, String empNumber) {
+ super();
+ this.id = id;
+ this.empNumber = empNumber;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getEmpNumber() {
+ return empNumber;
+ }
+
+ public void setEmpNumber(String empNumber) {
+ this.empNumber = empNumber;
+ }
+
+ public static long getSerialversionuid() {
+ return serialVersionUID;
+ }
+
+}
diff --git a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml
index 1f16bee3ba..6a236f0840 100644
--- a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml
+++ b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml
@@ -224,4 +224,26 @@
value="products_jpa.sql" />
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+ com.baeldung.jpa.queryparams.Employee
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/queryparams/JPAQueryParamsUnitTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/queryparams/JPAQueryParamsUnitTest.java
new file mode 100644
index 0000000000..4f320935cf
--- /dev/null
+++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/queryparams/JPAQueryParamsUnitTest.java
@@ -0,0 +1,109 @@
+package com.baeldung.jpa.queryparams;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Root;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * JPAQueryParamsTest class tests.
+ *
+ * @author gmlopez.mackinnon@gmail.com
+ */
+public class JPAQueryParamsUnitTest {
+
+ private static EntityManager entityManager;
+
+ @BeforeClass
+ public static void setup() {
+ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-queryparams");
+ entityManager = factory.createEntityManager();
+ }
+
+ @Test
+ public void givenEmpNumber_whenUsingPositionalParameter_thenReturnExpectedEmployee() {
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.empNumber = ?1", Employee.class);
+ String empNumber = "A123";
+ Employee employee = query.setParameter(1, empNumber)
+ .getSingleResult();
+ Assert.assertNotNull("Employee not found", employee);
+ }
+
+ @Test
+ public void givenEmpNumberList_whenUsingPositionalParameter_thenReturnExpectedEmployee() {
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.empNumber IN (?1)", Employee.class);
+ List empNumbers = Arrays.asList("A123", "A124");
+ List employees = query.setParameter(1, empNumbers)
+ .getResultList();
+ Assert.assertNotNull("Employees not found", employees);
+ Assert.assertFalse("Employees not found", employees.isEmpty());
+ }
+
+ @Test
+ public void givenEmpNumber_whenUsingNamedParameter_thenReturnExpectedEmployee() {
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.empNumber = :number", Employee.class);
+ String empNumber = "A123";
+ Employee employee = query.setParameter("number", empNumber)
+ .getSingleResult();
+ Assert.assertNotNull("Employee not found", employee);
+ }
+
+ @Test
+ public void givenEmpNumberList_whenUsingNamedParameter_thenReturnExpectedEmployee() {
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.empNumber IN (:numbers)", Employee.class);
+ List empNumbers = Arrays.asList("A123", "A124");
+ List employees = query.setParameter("numbers", empNumbers)
+ .getResultList();
+ Assert.assertNotNull("Employees not found", employees);
+ Assert.assertFalse("Employees not found", employees.isEmpty());
+ }
+
+ @Test
+ public void givenEmpNameAndEmpAge_whenUsingTwoNamedParameters_thenReturnExpectedEmployees() {
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.name = :name AND e.age = :empAge", Employee.class);
+ String empName = "John Doe";
+ int empAge = 55;
+ List employees = query.setParameter("name", empName)
+ .setParameter("empAge", empAge)
+ .getResultList();
+ Assert.assertNotNull("Employees not found!", employees);
+ Assert.assertTrue("Employees not found!", !employees.isEmpty());
+ }
+
+ @Test
+ public void givenEmpNumber_whenUsingCriteriaQuery_thenReturnExpectedEmployee() {
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+
+ CriteriaQuery cQuery = cb.createQuery(Employee.class);
+ Root c = cQuery.from(Employee.class);
+ ParameterExpression paramEmpNumber = cb.parameter(String.class);
+ cQuery.select(c)
+ .where(cb.equal(c.get(Employee_.empNumber), paramEmpNumber));
+
+ TypedQuery query = entityManager.createQuery(cQuery);
+ String empNumber = "A123";
+ query.setParameter(paramEmpNumber, empNumber);
+ Employee employee = query.getSingleResult();
+ Assert.assertNotNull("Employee not found!", employee);
+ }
+
+ @Test
+ public void givenEmpNumber_whenUsingLiteral_thenReturnExpectedEmployee() {
+ String empNumber = "A123";
+ TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.empNumber = '" + empNumber + "'", Employee.class);
+ Employee employee = query.getSingleResult();
+ Assert.assertNotNull("Employee not found!", employee);
+ }
+
+}
diff --git a/persistence-modules/java-jpa/src/test/resources/employees2.sql b/persistence-modules/java-jpa/src/test/resources/employees2.sql
new file mode 100644
index 0000000000..d3ae46f6a0
--- /dev/null
+++ b/persistence-modules/java-jpa/src/test/resources/employees2.sql
@@ -0,0 +1,2 @@
+INSERT INTO employees (employee_number, employee_name, employee_age) VALUES ('111', 'John Doe', 55);
+INSERT INTO employees (employee_number, employee_name, employee_age) VALUES ('A123', 'John Doe Junior', 25);
\ No newline at end of file
diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml
index ba3baf6636..e6d883334f 100644
--- a/persistence-modules/pom.xml
+++ b/persistence-modules/pom.xml
@@ -18,6 +18,7 @@
apache-cayenne
core-java-persistence
deltaspike
+ elasticsearch
flyway
hbase
hibernate5
diff --git a/persistence-modules/spring-data-cassandra-reactive/pom.xml b/persistence-modules/spring-data-cassandra-reactive/pom.xml
index 5a34d90c9f..288f842201 100644
--- a/persistence-modules/spring-data-cassandra-reactive/pom.xml
+++ b/persistence-modules/spring-data-cassandra-reactive/pom.xml
@@ -46,6 +46,13 @@
reactor-test
test
+
+ org.cassandraunit
+ cassandra-unit-spring
+ ${cassandra-unit-spring.version}
+ test
+
+
@@ -53,6 +60,7 @@
UTF-8
2.1.2.RELEASE
+ 3.11.2.0
diff --git a/persistence-modules/spring-data-cassandra-reactive/src/test/java/com/baeldung/cassandra/reactive/ReactiveEmployeeRepositoryIntegrationTest.java b/persistence-modules/spring-data-cassandra-reactive/src/test/java/com/baeldung/cassandra/reactive/ReactiveEmployeeRepositoryIntegrationTest.java
index ad726fe969..ae314db5e7 100644
--- a/persistence-modules/spring-data-cassandra-reactive/src/test/java/com/baeldung/cassandra/reactive/ReactiveEmployeeRepositoryIntegrationTest.java
+++ b/persistence-modules/spring-data-cassandra-reactive/src/test/java/com/baeldung/cassandra/reactive/ReactiveEmployeeRepositoryIntegrationTest.java
@@ -1,13 +1,23 @@
package com.baeldung.cassandra.reactive;
-import com.baeldung.cassandra.reactive.model.Employee;
-import com.baeldung.cassandra.reactive.repository.EmployeeRepository;
+import org.cassandraunit.spring.CassandraDataSet;
+import org.cassandraunit.spring.CassandraUnitDependencyInjectionTestExecutionListener;
+import org.cassandraunit.spring.CassandraUnitTestExecutionListener;
+import org.cassandraunit.spring.EmbeddedCassandra;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+
+import com.baeldung.cassandra.reactive.model.Employee;
+import com.baeldung.cassandra.reactive.repository.EmployeeRepository;
+
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@@ -15,6 +25,15 @@ import reactor.test.StepVerifier;
@RunWith(SpringRunner.class)
@SpringBootTest
+@TestExecutionListeners(listeners = {
+ CassandraUnitDependencyInjectionTestExecutionListener.class,
+ CassandraUnitTestExecutionListener.class,
+ ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class
+})
+@EmbeddedCassandra(timeout = 60000, configuration = "cassandra-server.yaml")
+@CassandraDataSet(value = {"cassandra-init.cql"}, keyspace = "practice")
public class ReactiveEmployeeRepositoryIntegrationTest {
@Autowired
diff --git a/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-init.cql b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-init.cql
new file mode 100644
index 0000000000..b28fda5320
--- /dev/null
+++ b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-init.cql
@@ -0,0 +1,7 @@
+CREATE TABLE employee(
+ id int PRIMARY KEY,
+ name text,
+ address text,
+ email text,
+ age int
+);
\ No newline at end of file
diff --git a/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-server.yaml b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-server.yaml
new file mode 100644
index 0000000000..af3fb21e54
--- /dev/null
+++ b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/cassandra-server.yaml
@@ -0,0 +1,590 @@
+# Cassandra storage config YAML
+
+# NOTE:
+# See http://wiki.apache.org/cassandra/StorageConfiguration for
+# full explanations of configuration directives
+# /NOTE
+
+# The name of the cluster. This is mainly used to prevent machines in
+# one logical cluster from joining another.
+cluster_name: 'Test Cluster'
+
+# You should always specify InitialToken when setting up a production
+# cluster for the first time, and often when adding capacity later.
+# The principle is that each node should be given an equal slice of
+# the token ring; see http://wiki.apache.org/cassandra/Operations
+# for more details.
+#
+# If blank, Cassandra will request a token bisecting the range of
+# the heaviest-loaded existing node. If there is no load information
+# available, such as is the case with a new cluster, it will pick
+# a random token, which will lead to hot spots.
+#initial_token:
+
+# See http://wiki.apache.org/cassandra/HintedHandoff
+hinted_handoff_enabled: true
+# this defines the maximum amount of time a dead host will have hints
+# generated. After it has been dead this long, new hints for it will not be
+# created until it has been seen alive and gone down again.
+max_hint_window_in_ms: 10800000 # 3 hours
+# Maximum throttle in KBs per second, per delivery thread. This will be
+# reduced proportionally to the number of nodes in the cluster. (If there
+# are two nodes in the cluster, each delivery thread will use the maximum
+# rate; if there are three, each will throttle to half of the maximum,
+# since we expect two nodes to be delivering hints simultaneously.)
+hinted_handoff_throttle_in_kb: 1024
+# Number of threads with which to deliver hints;
+# Consider increasing this number when you have multi-dc deployments, since
+# cross-dc handoff tends to be slower
+max_hints_delivery_threads: 2
+
+hints_directory: target/embeddedCassandra/hints
+
+# The following setting populates the page cache on memtable flush and compaction
+# WARNING: Enable this setting only when the whole node's data fits in memory.
+# Defaults to: false
+# populate_io_cache_on_flush: false
+
+# Authentication backend, implementing IAuthenticator; used to identify users
+# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthenticator,
+# PasswordAuthenticator}.
+#
+# - AllowAllAuthenticator performs no checks - set it to disable authentication.
+# - PasswordAuthenticator relies on username/password pairs to authenticate
+# users. It keeps usernames and hashed passwords in system_auth.credentials table.
+# Please increase system_auth keyspace replication factor if you use this authenticator.
+authenticator: AllowAllAuthenticator
+
+# Authorization backend, implementing IAuthorizer; used to limit access/provide permissions
+# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthorizer,
+# CassandraAuthorizer}.
+#
+# - AllowAllAuthorizer allows any action to any user - set it to disable authorization.
+# - CassandraAuthorizer stores permissions in system_auth.permissions table. Please
+# increase system_auth keyspace replication factor if you use this authorizer.
+authorizer: AllowAllAuthorizer
+
+# Validity period for permissions cache (fetching permissions can be an
+# expensive operation depending on the authorizer, CassandraAuthorizer is
+# one example). Defaults to 2000, set to 0 to disable.
+# Will be disabled automatically for AllowAllAuthorizer.
+permissions_validity_in_ms: 2000
+
+
+# The partitioner is responsible for distributing rows (by key) across
+# nodes in the cluster. Any IPartitioner may be used, including your/m
+# own as long as it is on the classpath. Out of the box, Cassandra
+# provides org.apache.cassandra.dht.{Murmur3Partitioner, RandomPartitioner
+# ByteOrderedPartitioner, OrderPreservingPartitioner (deprecated)}.
+#
+# - RandomPartitioner distributes rows across the cluster evenly by md5.
+# This is the default prior to 1.2 and is retained for compatibility.
+# - Murmur3Partitioner is similar to RandomPartioner but uses Murmur3_128
+# Hash Function instead of md5. When in doubt, this is the best option.
+# - ByteOrderedPartitioner orders rows lexically by key bytes. BOP allows
+# scanning rows in key order, but the ordering can generate hot spots
+# for sequential insertion workloads.
+# - OrderPreservingPartitioner is an obsolete form of BOP, that stores
+# - keys in a less-efficient format and only works with keys that are
+# UTF8-encoded Strings.
+# - CollatingOPP collates according to EN,US rules rather than lexical byte
+# ordering. Use this as an example if you need custom collation.
+#
+# See http://wiki.apache.org/cassandra/Operations for more on
+# partitioners and token selection.
+partitioner: org.apache.cassandra.dht.Murmur3Partitioner
+
+# directories where Cassandra should store data on disk.
+data_file_directories:
+ - target/embeddedCassandra/data
+
+# commit log
+commitlog_directory: target/embeddedCassandra/commitlog
+
+cdc_raw_directory: target/embeddedCassandra/cdc
+
+# policy for data disk failures:
+# stop: shut down gossip and Thrift, leaving the node effectively dead, but
+# can still be inspected via JMX.
+# best_effort: stop using the failed disk and respond to requests based on
+# remaining available sstables. This means you WILL see obsolete
+# data at CL.ONE!
+# ignore: ignore fatal errors and let requests fail, as in pre-1.2 Cassandra
+disk_failure_policy: stop
+
+
+# Maximum size of the key cache in memory.
+#
+# Each key cache hit saves 1 seek and each row cache hit saves 2 seeks at the
+# minimum, sometimes more. The key cache is fairly tiny for the amount of
+# time it saves, so it's worthwhile to use it at large numbers.
+# The row cache saves even more time, but must store the whole values of
+# its rows, so it is extremely space-intensive. It's best to only use the
+# row cache if you have hot rows or static rows.
+#
+# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.
+#
+# Default value is empty to make it "auto" (min(5% of Heap (in MB), 100MB)). Set to 0 to disable key cache.
+key_cache_size_in_mb:
+
+# Duration in seconds after which Cassandra should
+# safe the keys cache. Caches are saved to saved_caches_directory as
+# specified in this configuration file.
+#
+# Saved caches greatly improve cold-start speeds, and is relatively cheap in
+# terms of I/O for the key cache. Row cache saving is much more expensive and
+# has limited use.
+#
+# Default is 14400 or 4 hours.
+key_cache_save_period: 14400
+
+# Number of keys from the key cache to save
+# Disabled by default, meaning all keys are going to be saved
+# key_cache_keys_to_save: 100
+
+# Maximum size of the row cache in memory.
+# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.
+#
+# Default value is 0, to disable row caching.
+row_cache_size_in_mb: 0
+
+# Duration in seconds after which Cassandra should
+# safe the row cache. Caches are saved to saved_caches_directory as specified
+# in this configuration file.
+#
+# Saved caches greatly improve cold-start speeds, and is relatively cheap in
+# terms of I/O for the key cache. Row cache saving is much more expensive and
+# has limited use.
+#
+# Default is 0 to disable saving the row cache.
+row_cache_save_period: 0
+
+# Number of keys from the row cache to save
+# Disabled by default, meaning all keys are going to be saved
+# row_cache_keys_to_save: 100
+
+# saved caches
+saved_caches_directory: target/embeddedCassandra/saved_caches
+
+# commitlog_sync may be either "periodic" or "batch."
+# When in batch mode, Cassandra won't ack writes until the commit log
+# has been fsynced to disk. It will wait up to
+# commitlog_sync_batch_window_in_ms milliseconds for other writes, before
+# performing the sync.
+#
+# commitlog_sync: batch
+# commitlog_sync_batch_window_in_ms: 50
+#
+# the other option is "periodic" where writes may be acked immediately
+# and the CommitLog is simply synced every commitlog_sync_period_in_ms
+# milliseconds.
+commitlog_sync: periodic
+commitlog_sync_period_in_ms: 10000
+
+# The size of the individual commitlog file segments. A commitlog
+# segment may be archived, deleted, or recycled once all the data
+# in it (potentially from each columnfamily in the system) has been
+# flushed to sstables.
+#
+# The default size is 32, which is almost always fine, but if you are
+# archiving commitlog segments (see commitlog_archiving.properties),
+# then you probably want a finer granularity of archiving; 8 or 16 MB
+# is reasonable.
+commitlog_segment_size_in_mb: 32
+
+# any class that implements the SeedProvider interface and has a
+# constructor that takes a Map of parameters will do.
+seed_provider:
+ # Addresses of hosts that are deemed contact points.
+ # Cassandra nodes use this list of hosts to find each other and learn
+ # the topology of the ring. You must change this if you are running
+ # multiple nodes!
+ - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+ parameters:
+ # seeds is actually a comma-delimited list of addresses.
+ # Ex: ",,"
+ - seeds: "127.0.0.1"
+
+
+# For workloads with more data than can fit in memory, Cassandra's
+# bottleneck will be reads that need to fetch data from
+# disk. "concurrent_reads" should be set to (16 * number_of_drives) in
+# order to allow the operations to enqueue low enough in the stack
+# that the OS and drives can reorder them.
+#
+# On the other hand, since writes are almost never IO bound, the ideal
+# number of "concurrent_writes" is dependent on the number of cores in
+# your system; (8 * number_of_cores) is a good rule of thumb.
+concurrent_reads: 32
+concurrent_writes: 32
+
+# Total memory to use for memtables. Cassandra will flush the largest
+# memtable when this much memory is used.
+# If omitted, Cassandra will set it to 1/3 of the heap.
+# memtable_total_space_in_mb: 2048
+
+# Total space to use for commitlogs.
+# If space gets above this value (it will round up to the next nearest
+# segment multiple), Cassandra will flush every dirty CF in the oldest
+# segment and remove it.
+# commitlog_total_space_in_mb: 4096
+
+# This sets the amount of memtable flush writer threads. These will
+# be blocked by disk io, and each one will hold a memtable in memory
+# while blocked. If you have a large heap and many data directories,
+# you can increase this value for better flush performance.
+# By default this will be set to the amount of data directories defined.
+#memtable_flush_writers: 1
+
+# the number of full memtables to allow pending flush, that is,
+# waiting for a writer thread. At a minimum, this should be set to
+# the maximum number of secondary indexes created on a single CF.
+#memtable_flush_queue_size: 4
+
+# Whether to, when doing sequential writing, fsync() at intervals in
+# order to force the operating system to flush the dirty
+# buffers. Enable this to avoid sudden dirty buffer flushing from
+# impacting read latencies. Almost always a good idea on SSD:s; not
+# necessarily on platters.
+trickle_fsync: false
+trickle_fsync_interval_in_kb: 10240
+
+# TCP port, for commands and data
+storage_port: 7010
+
+# SSL port, for encrypted communication. Unused unless enabled in
+# encryption_options
+ssl_storage_port: 7011
+
+# Address to bind to and tell other Cassandra nodes to connect to. You
+# _must_ change this if you want multiple nodes to be able to
+# communicate!
+#
+# Leaving it blank leaves it up to InetAddress.getLocalHost(). This
+# will always do the Right Thing *if* the node is properly configured
+# (hostname, name resolution, etc), and the Right Thing is to use the
+# address associated with the hostname (it might not be).
+#
+# Setting this to 0.0.0.0 is always wrong.
+listen_address: 127.0.0.1
+
+start_native_transport: true
+# port for the CQL native transport to listen for clients on
+native_transport_port: 9042
+
+# Whether to start the thrift rpc server.
+start_rpc: true
+
+# Address to broadcast to other Cassandra nodes
+# Leaving this blank will set it to the same value as listen_address
+# broadcast_address: 1.2.3.4
+
+# The address to bind the Thrift RPC service to -- clients connect
+# here. Unlike ListenAddress above, you *can* specify 0.0.0.0 here if
+# you want Thrift to listen on all interfaces.
+#
+# Leaving this blank has the same effect it does for ListenAddress,
+# (i.e. it will be based on the configured hostname of the node).
+rpc_address: localhost
+# port for Thrift to listen for clients on
+rpc_port: 9171
+
+# enable or disable keepalive on rpc connections
+rpc_keepalive: true
+
+# Cassandra provides three options for the RPC Server:
+#
+# sync -> One connection per thread in the rpc pool (see below).
+# For a very large number of clients, memory will be your limiting
+# factor; on a 64 bit JVM, 128KB is the minimum stack size per thread.
+# Connection pooling is very, very strongly recommended.
+#
+# async -> Nonblocking server implementation with one thread to serve
+# rpc connections. This is not recommended for high throughput use
+# cases. Async has been tested to be about 50% slower than sync
+# or hsha and is deprecated: it will be removed in the next major release.
+#
+# hsha -> Stands for "half synchronous, half asynchronous." The rpc thread pool
+# (see below) is used to manage requests, but the threads are multiplexed
+# across the different clients.
+#
+# The default is sync because on Windows hsha is about 30% slower. On Linux,
+# sync/hsha performance is about the same, with hsha of course using less memory.
+rpc_server_type: sync
+
+# Uncomment rpc_min|max|thread to set request pool size.
+# You would primarily set max for the sync server to safeguard against
+# misbehaved clients; if you do hit the max, Cassandra will block until one
+# disconnects before accepting more. The defaults for sync are min of 16 and max
+# unlimited.
+#
+# For the Hsha server, the min and max both default to quadruple the number of
+# CPU cores.
+#
+# This configuration is ignored by the async server.
+#
+# rpc_min_threads: 16
+# rpc_max_threads: 2048
+
+# uncomment to set socket buffer sizes on rpc connections
+# rpc_send_buff_size_in_bytes:
+# rpc_recv_buff_size_in_bytes:
+
+# Frame size for thrift (maximum field length).
+# 0 disables TFramedTransport in favor of TSocket. This option
+# is deprecated; we strongly recommend using Framed mode.
+thrift_framed_transport_size_in_mb: 15
+
+# The max length of a thrift message, including all fields and
+# internal thrift overhead.
+thrift_max_message_length_in_mb: 16
+
+# Set to true to have Cassandra create a hard link to each sstable
+# flushed or streamed locally in a backups/ subdirectory of the
+# Keyspace data. Removing these links is the operator's
+# responsibility.
+incremental_backups: false
+
+# Whether or not to take a snapshot before each compaction. Be
+# careful using this option, since Cassandra won't clean up the
+# snapshots for you. Mostly useful if you're paranoid when there
+# is a data format change.
+snapshot_before_compaction: false
+
+# Whether or not a snapshot is taken of the data before keyspace truncation
+# or dropping of column families. The STRONGLY advised default of true
+# should be used to provide data safety. If you set this flag to false, you will
+# lose data on truncation or drop.
+auto_snapshot: false
+
+# Add column indexes to a row after its contents reach this size.
+# Increase if your column values are large, or if you have a very large
+# number of columns. The competing causes are, Cassandra has to
+# deserialize this much of the row to read a single column, so you want
+# it to be small - at least if you do many partial-row reads - but all
+# the index data is read for each access, so you don't want to generate
+# that wastefully either.
+column_index_size_in_kb: 64
+
+# Size limit for rows being compacted in memory. Larger rows will spill
+# over to disk and use a slower two-pass compaction process. A message
+# will be logged specifying the row key.
+#in_memory_compaction_limit_in_mb: 64
+
+# Number of simultaneous compactions to allow, NOT including
+# validation "compactions" for anti-entropy repair. Simultaneous
+# compactions can help preserve read performance in a mixed read/write
+# workload, by mitigating the tendency of small sstables to accumulate
+# during a single long running compactions. The default is usually
+# fine and if you experience problems with compaction running too
+# slowly or too fast, you should look at
+# compaction_throughput_mb_per_sec first.
+#
+# This setting has no effect on LeveledCompactionStrategy.
+#
+# concurrent_compactors defaults to the number of cores.
+# Uncomment to make compaction mono-threaded, the pre-0.8 default.
+#concurrent_compactors: 1
+
+# Multi-threaded compaction. When enabled, each compaction will use
+# up to one thread per core, plus one thread per sstable being merged.
+# This is usually only useful for SSD-based hardware: otherwise,
+# your concern is usually to get compaction to do LESS i/o (see:
+# compaction_throughput_mb_per_sec), not more.
+#multithreaded_compaction: false
+
+# Throttles compaction to the given total throughput across the entire
+# system. The faster you insert data, the faster you need to compact in
+# order to keep the sstable count down, but in general, setting this to
+# 16 to 32 times the rate you are inserting data is more than sufficient.
+# Setting this to 0 disables throttling. Note that this account for all types
+# of compaction, including validation compaction.
+compaction_throughput_mb_per_sec: 16
+
+# Track cached row keys during compaction, and re-cache their new
+# positions in the compacted sstable. Disable if you use really large
+# key caches.
+#compaction_preheat_key_cache: true
+
+# Throttles all outbound streaming file transfers on this node to the
+# given total throughput in Mbps. This is necessary because Cassandra does
+# mostly sequential IO when streaming data during bootstrap or repair, which
+# can lead to saturating the network connection and degrading rpc performance.
+# When unset, the default is 200 Mbps or 25 MB/s.
+# stream_throughput_outbound_megabits_per_sec: 200
+
+# How long the coordinator should wait for read operations to complete
+read_request_timeout_in_ms: 5000
+# How long the coordinator should wait for seq or index scans to complete
+range_request_timeout_in_ms: 10000
+# How long the coordinator should wait for writes to complete
+write_request_timeout_in_ms: 2000
+# How long a coordinator should continue to retry a CAS operation
+# that contends with other proposals for the same row
+cas_contention_timeout_in_ms: 1000
+# How long the coordinator should wait for truncates to complete
+# (This can be much longer, because unless auto_snapshot is disabled
+# we need to flush first so we can snapshot before removing the data.)
+truncate_request_timeout_in_ms: 60000
+# The default timeout for other, miscellaneous operations
+request_timeout_in_ms: 10000
+
+# Enable operation timeout information exchange between nodes to accurately
+# measure request timeouts. If disabled, replicas will assume that requests
+# were forwarded to them instantly by the coordinator, which means that
+# under overload conditions we will waste that much extra time processing
+# already-timed-out requests.
+#
+# Warning: before enabling this property make sure to ntp is installed
+# and the times are synchronized between the nodes.
+cross_node_timeout: false
+
+# Enable socket timeout for streaming operation.
+# When a timeout occurs during streaming, streaming is retried from the start
+# of the current file. This _can_ involve re-streaming an important amount of
+# data, so you should avoid setting the value too low.
+# Default value is 0, which never timeout streams.
+# streaming_socket_timeout_in_ms: 0
+
+# phi value that must be reached for a host to be marked down.
+# most users should never need to adjust this.
+# phi_convict_threshold: 8
+
+# endpoint_snitch -- Set this to a class that implements
+# IEndpointSnitch. The snitch has two functions:
+# - it teaches Cassandra enough about your network topology to route
+# requests efficiently
+# - it allows Cassandra to spread replicas around your cluster to avoid
+# correlated failures. It does this by grouping machines into
+# "datacenters" and "racks." Cassandra will do its best not to have
+# more than one replica on the same "rack" (which may not actually
+# be a physical location)
+#
+# IF YOU CHANGE THE SNITCH AFTER DATA IS INSERTED INTO THE CLUSTER,
+# YOU MUST RUN A FULL REPAIR, SINCE THE SNITCH AFFECTS WHERE REPLICAS
+# ARE PLACED.
+#
+# Out of the box, Cassandra provides
+# - SimpleSnitch:
+# Treats Strategy order as proximity. This improves cache locality
+# when disabling read repair, which can further improve throughput.
+# Only appropriate for single-datacenter deployments.
+# - PropertyFileSnitch:
+# Proximity is determined by rack and data center, which are
+# explicitly configured in cassandra-topology.properties.
+# - RackInferringSnitch:
+# Proximity is determined by rack and data center, which are
+# assumed to correspond to the 3rd and 2nd octet of each node's
+# IP address, respectively. Unless this happens to match your
+# deployment conventions (as it did Facebook's), this is best used
+# as an example of writing a custom Snitch class.
+# - Ec2Snitch:
+# Appropriate for EC2 deployments in a single Region. Loads Region
+# and Availability Zone information from the EC2 API. The Region is
+# treated as the Datacenter, and the Availability Zone as the rack.
+# Only private IPs are used, so this will not work across multiple
+# Regions.
+# - Ec2MultiRegionSnitch:
+# Uses public IPs as broadcast_address to allow cross-region
+# connectivity. (Thus, you should set seed addresses to the public
+# IP as well.) You will need to open the storage_port or
+# ssl_storage_port on the public IP firewall. (For intra-Region
+# traffic, Cassandra will switch to the private IP after
+# establishing a connection.)
+#
+# You can use a custom Snitch by setting this to the full class name
+# of the snitch, which will be assumed to be on your classpath.
+endpoint_snitch: SimpleSnitch
+
+# controls how often to perform the more expensive part of host score
+# calculation
+dynamic_snitch_update_interval_in_ms: 100
+# controls how often to reset all host scores, allowing a bad host to
+# possibly recover
+dynamic_snitch_reset_interval_in_ms: 600000
+# if set greater than zero and read_repair_chance is < 1.0, this will allow
+# 'pinning' of replicas to hosts in order to increase cache capacity.
+# The badness threshold will control how much worse the pinned host has to be
+# before the dynamic snitch will prefer other replicas over it. This is
+# expressed as a double which represents a percentage. Thus, a value of
+# 0.2 means Cassandra would continue to prefer the static snitch values
+# until the pinned host was 20% worse than the fastest.
+dynamic_snitch_badness_threshold: 0.1
+
+# request_scheduler -- Set this to a class that implements
+# RequestScheduler, which will schedule incoming client requests
+# according to the specific policy. This is useful for multi-tenancy
+# with a single Cassandra cluster.
+# NOTE: This is specifically for requests from the client and does
+# not affect inter node communication.
+# org.apache.cassandra.scheduler.NoScheduler - No scheduling takes place
+# org.apache.cassandra.scheduler.RoundRobinScheduler - Round robin of
+# client requests to a node with a separate queue for each
+# request_scheduler_id. The scheduler is further customized by
+# request_scheduler_options as described below.
+request_scheduler: org.apache.cassandra.scheduler.NoScheduler
+
+# Scheduler Options vary based on the type of scheduler
+# NoScheduler - Has no options
+# RoundRobin
+# - throttle_limit -- The throttle_limit is the number of in-flight
+# requests per client. Requests beyond
+# that limit are queued up until
+# running requests can complete.
+# The value of 80 here is twice the number of
+# concurrent_reads + concurrent_writes.
+# - default_weight -- default_weight is optional and allows for
+# overriding the default which is 1.
+# - weights -- Weights are optional and will default to 1 or the
+# overridden default_weight. The weight translates into how
+# many requests are handled during each turn of the
+# RoundRobin, based on the scheduler id.
+#
+# request_scheduler_options:
+# throttle_limit: 80
+# default_weight: 5
+# weights:
+# Keyspace1: 1
+# Keyspace2: 5
+
+# request_scheduler_id -- An identifer based on which to perform
+# the request scheduling. Currently the only valid option is keyspace.
+# request_scheduler_id: keyspace
+
+# index_interval controls the sampling of entries from the primrary
+# row index in terms of space versus time. The larger the interval,
+# the smaller and less effective the sampling will be. In technicial
+# terms, the interval coresponds to the number of index entries that
+# are skipped between taking each sample. All the sampled entries
+# must fit in memory. Generally, a value between 128 and 512 here
+# coupled with a large key cache size on CFs results in the best trade
+# offs. This value is not often changed, however if you have many
+# very small rows (many to an OS page), then increasing this will
+# often lower memory usage without a impact on performance.
+index_interval: 128
+
+# Enable or disable inter-node encryption
+# Default settings are TLS v1, RSA 1024-bit keys (it is imperative that
+# users generate their own keys) TLS_RSA_WITH_AES_128_CBC_SHA as the cipher
+# suite for authentication, key exchange and encryption of the actual data transfers.
+# NOTE: No custom encryption options are enabled at the moment
+# The available internode options are : all, none, dc, rack
+#
+# If set to dc cassandra will encrypt the traffic between the DCs
+# If set to rack cassandra will encrypt the traffic between the racks
+#
+# The passwords used in these options must match the passwords used when generating
+# the keystore and truststore. For instructions on generating these files, see:
+# http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore
+#
+encryption_options:
+ internode_encryption: none
+ keystore: conf/.keystore
+ keystore_password: cassandra
+ truststore: conf/.truststore
+ truststore_password: cassandra
+ # More advanced defaults below:
+ # protocol: TLS
+ # algorithm: SunX509
+ # store_type: JKS
+ # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA]
\ No newline at end of file
diff --git a/ratpack/build.gradle b/ratpack/build.gradle
index 25af3ddb51..c997b4e697 100644
--- a/ratpack/build.gradle
+++ b/ratpack/build.gradle
@@ -14,6 +14,8 @@ if (!JavaVersion.current().java8Compatible) {
apply plugin: "io.ratpack.ratpack-java"
apply plugin: 'java'
+apply plugin: 'groovy'
+apply plugin: 'io.ratpack.ratpack-groovy'
repositories {
jcenter()
diff --git a/ratpack/pom.xml b/ratpack/pom.xml
index 7c145eff91..0df313c05e 100644
--- a/ratpack/pom.xml
+++ b/ratpack/pom.xml
@@ -26,11 +26,21 @@
ratpack-core
${ratpack.version}
+
+ org.codehaus.groovy
+ groovy-sql
+ ${groovy.sql.version}
+
io.ratpack
ratpack-hikari
${ratpack.version}
+
+ io.ratpack
+ ratpack-groovy-test
+ ${ratpack.test.latest.version}
+
io.ratpack
ratpack-hystrix
@@ -91,6 +101,7 @@
4.5.3
4.4.6
1.5.12
+ 2.4.15
+ 1.6.1
-
diff --git a/ratpack/src/main/groovy/com/baeldung/Ratpack.groovy b/ratpack/src/main/groovy/com/baeldung/Ratpack.groovy
new file mode 100644
index 0000000000..4d8814b627
--- /dev/null
+++ b/ratpack/src/main/groovy/com/baeldung/Ratpack.groovy
@@ -0,0 +1,76 @@
+package com.baeldung;
+
+@Grab('io.ratpack:ratpack-groovy:1.6.1')
+import static ratpack.groovy.Groovy.ratpack
+
+import com.baeldung.model.User
+import com.google.common.reflect.TypeToken
+import ratpack.exec.Promise
+import ratpack.handling.Context
+import ratpack.jackson.Jackson
+import groovy.sql.Sql
+import java.sql.Connection
+import java.sql.PreparedStatement
+import java.sql.ResultSet
+import ratpack.hikari.HikariModule
+import javax.sql.DataSource;
+
+ratpack {
+ serverConfig { port(5050) }
+ bindings {
+ module(HikariModule) { config ->
+ config.dataSourceClassName = 'org.h2.jdbcx.JdbcDataSource'
+ config.addDataSourceProperty('URL', "jdbc:h2:mem:devDB;INIT=RUNSCRIPT FROM 'classpath:/User.sql'")
+ }
+ }
+
+ handlers {
+
+ get { render 'Hello World from Ratpack with Groovy!!' }
+
+ get("greet/:name") { Context ctx ->
+ render "Hello " + ctx.getPathTokens().get("name") + "!!!"
+ }
+
+ get("data") {
+ render Jackson.json([title: "Mr", name: "Norman", country: "USA"])
+ }
+
+ post("user") {
+ Promise user = parse(Jackson.fromJson(User))
+ user.then { u -> render u.name }
+ }
+
+ get('fetchUserName/:id') { Context ctx ->
+ Connection connection = ctx.get(DataSource.class).getConnection()
+ PreparedStatement queryStatement = connection.prepareStatement("SELECT NAME FROM USER WHERE ID=?")
+ queryStatement.setInt(1, Integer.parseInt(ctx.getPathTokens().get("id")))
+ ResultSet resultSet = queryStatement.executeQuery()
+ resultSet.next()
+ render resultSet.getString(1)
+ }
+
+ get('fetchUsers') {
+ def db = [url:'jdbc:h2:mem:devDB']
+ def sql = Sql.newInstance(db.url, db.user, db.password)
+ def users = sql.rows("SELECT * FROM USER");
+ render(Jackson.json(users))
+ }
+
+ post('addUser') {
+ parse(Jackson.fromJson(User))
+ .then { u ->
+ def db = [url:'jdbc:h2:mem:devDB']
+ Sql sql = Sql.newInstance(db.url, db.user, db.password)
+ sql.executeInsert("INSERT INTO USER VALUES (?,?,?,?)", [
+ u.id,
+ u.title,
+ u.name,
+ u.country
+ ])
+ render "User $u.name inserted"
+ }
+ }
+ }
+}
+
diff --git a/ratpack/src/main/groovy/com/baeldung/RatpackGroovyApp.groovy b/ratpack/src/main/groovy/com/baeldung/RatpackGroovyApp.groovy
new file mode 100644
index 0000000000..95ada25e60
--- /dev/null
+++ b/ratpack/src/main/groovy/com/baeldung/RatpackGroovyApp.groovy
@@ -0,0 +1,12 @@
+package com.baeldung;
+
+public class RatpackGroovyApp {
+
+ public static void main(String[] args) {
+ File file = new File("src/main/groovy/com/baeldung/Ratpack.groovy");
+ def shell = new GroovyShell()
+ shell.evaluate(file)
+ }
+
+}
+
diff --git a/ratpack/src/main/groovy/com/baeldung/model/User.groovy b/ratpack/src/main/groovy/com/baeldung/model/User.groovy
new file mode 100644
index 0000000000..0fe4c6c367
--- /dev/null
+++ b/ratpack/src/main/groovy/com/baeldung/model/User.groovy
@@ -0,0 +1,9 @@
+package com.baeldung.model
+
+class User {
+
+ long id
+ String title
+ String name
+ String country
+}
diff --git a/ratpack/src/main/resources/User.sql b/ratpack/src/main/resources/User.sql
new file mode 100644
index 0000000000..a3e2242283
--- /dev/null
+++ b/ratpack/src/main/resources/User.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS USER;
+CREATE TABLE USER (
+ ID BIGINT AUTO_INCREMENT PRIMARY KEY,
+ TITLE VARCHAR(255),
+ NAME VARCHAR(255),
+ COUNTRY VARCHAR(255)
+);
+
+INSERT INTO USER VALUES(1,'Mr','Norman Potter', 'USA');
+INSERT INTO USER VALUES(2,'Miss','Ketty Smith', 'FRANCE');
\ No newline at end of file
diff --git a/ratpack/src/test/groovy/com/baeldung/RatpackGroovySpec.groovy b/ratpack/src/test/groovy/com/baeldung/RatpackGroovySpec.groovy
new file mode 100644
index 0000000000..726d703a06
--- /dev/null
+++ b/ratpack/src/test/groovy/com/baeldung/RatpackGroovySpec.groovy
@@ -0,0 +1,46 @@
+package com.baeldung;
+
+import ratpack.groovy.Groovy
+import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest;
+import ratpack.test.http.TestHttpClient;
+import ratpack.test.ServerBackedApplicationUnderTest;
+import org.junit.Test;
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import ratpack.test.MainClassApplicationUnderTest
+
+class RatpackGroovySpec {
+
+ ServerBackedApplicationUnderTest ratpackGroovyApp = new MainClassApplicationUnderTest(RatpackGroovyApp.class)
+ @Delegate TestHttpClient client = TestHttpClient.testHttpClient(ratpackGroovyApp)
+
+ @Test
+ void "test if app is started"() {
+ when:
+ get("")
+
+ then:
+ assert response.statusCode == 200
+ assert response.body.text == "Hello World from Ratpack with Groovy!!"
+ }
+
+ @Test
+ void "test greet with name"() {
+ when:
+ get("greet/Lewis")
+
+ then:
+ assert response.statusCode == 200
+ assert response.body.text == "Hello Lewis!!!"
+ }
+
+ @Test
+ void "test fetchUsers"() {
+ when:
+ get("fetchUsers")
+
+ then:
+ assert response.statusCode == 200
+ assert response.body.text == '[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]'
+ }
+}
diff --git a/spring-5-data-reactive/pom.xml b/spring-5-data-reactive/pom.xml
index aa73cf11ae..8c16851de0 100644
--- a/spring-5-data-reactive/pom.xml
+++ b/spring-5-data-reactive/pom.xml
@@ -63,6 +63,11 @@
spring-boot-starter-test
test
+
+ de.flapdoodle.embed
+ de.flapdoodle.embed.mongo
+ test
+
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/LogsCounterApplication.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/LogsCounterApplication.java
new file mode 100644
index 0000000000..8b2511a8f3
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/LogsCounterApplication.java
@@ -0,0 +1,11 @@
+package com.baeldung.tailablecursor;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class LogsCounterApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(LogsCounterApplication.class, args);
+ }
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/Log.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/Log.java
new file mode 100644
index 0000000000..717a367751
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/Log.java
@@ -0,0 +1,21 @@
+package com.baeldung.tailablecursor.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@Document
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Log {
+ @Id
+ private String id;
+ private String service;
+ private LogLevel level;
+ private String message;
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/LogLevel.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/LogLevel.java
new file mode 100644
index 0000000000..6826fbffd3
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/domain/LogLevel.java
@@ -0,0 +1,5 @@
+package com.baeldung.tailablecursor.domain;
+
+public enum LogLevel {
+ ERROR, WARN, INFO
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/repository/LogsRepository.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/repository/LogsRepository.java
new file mode 100644
index 0000000000..dce11c548c
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/repository/LogsRepository.java
@@ -0,0 +1,12 @@
+package com.baeldung.tailablecursor.repository;
+
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import org.springframework.data.mongodb.repository.Tailable;
+import org.springframework.data.repository.reactive.ReactiveCrudRepository;
+import reactor.core.publisher.Flux;
+
+public interface LogsRepository extends ReactiveCrudRepository {
+ @Tailable
+ Flux findByLevel(LogLevel level);
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/ErrorLogsCounter.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/ErrorLogsCounter.java
new file mode 100644
index 0000000000..c243e64f97
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/ErrorLogsCounter.java
@@ -0,0 +1,62 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.messaging.DefaultMessageListenerContainer;
+import org.springframework.data.mongodb.core.messaging.MessageListener;
+import org.springframework.data.mongodb.core.messaging.MessageListenerContainer;
+import org.springframework.data.mongodb.core.messaging.TailableCursorRequest;
+
+import javax.annotation.PreDestroy;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Slf4j
+public class ErrorLogsCounter implements LogsCounter {
+
+ private static final String LEVEL_FIELD_NAME = "level";
+
+ private final String collectionName;
+ private final MessageListenerContainer container;
+
+ private final AtomicInteger counter = new AtomicInteger();
+
+ public ErrorLogsCounter(MongoTemplate mongoTemplate,
+ String collectionName) {
+ this.collectionName = collectionName;
+ this.container = new DefaultMessageListenerContainer(mongoTemplate);
+
+ container.start();
+ TailableCursorRequest request = getTailableCursorRequest();
+ container.register(request, Log.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private TailableCursorRequest getTailableCursorRequest() {
+ MessageListener listener = message -> {
+ log.info("ERROR log received: {}", message.getBody());
+ counter.incrementAndGet();
+ };
+
+ return TailableCursorRequest.builder()
+ .collection(collectionName)
+ .filter(query(where(LEVEL_FIELD_NAME).is(LogLevel.ERROR)))
+ .publishTo(listener)
+ .build();
+ }
+
+ @Override
+ public int count() {
+ return counter.get();
+ }
+
+ @PreDestroy
+ public void close() {
+ container.stop();
+ }
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/InfoLogsCounter.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/InfoLogsCounter.java
new file mode 100644
index 0000000000..b30eba0b25
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/InfoLogsCounter.java
@@ -0,0 +1,36 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import com.baeldung.tailablecursor.repository.LogsRepository;
+import lombok.extern.slf4j.Slf4j;
+import reactor.core.Disposable;
+import reactor.core.publisher.Flux;
+
+import javax.annotation.PreDestroy;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Slf4j
+public class InfoLogsCounter implements LogsCounter {
+
+ private final AtomicInteger counter = new AtomicInteger();
+ private final Disposable subscription;
+
+ public InfoLogsCounter(LogsRepository repository) {
+ Flux stream = repository.findByLevel(LogLevel.INFO);
+ this.subscription = stream.subscribe(l -> {
+ log.info("INFO log received: " + l);
+ counter.incrementAndGet();
+ });
+ }
+
+ @Override
+ public int count() {
+ return this.counter.get();
+ }
+
+ @PreDestroy
+ public void close() {
+ this.subscription.dispose();
+ }
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/LogsCounter.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/LogsCounter.java
new file mode 100644
index 0000000000..e14a3eadd7
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/LogsCounter.java
@@ -0,0 +1,5 @@
+package com.baeldung.tailablecursor.service;
+
+public interface LogsCounter {
+ int count();
+}
diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/WarnLogsCounter.java b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/WarnLogsCounter.java
new file mode 100644
index 0000000000..b21f61fa88
--- /dev/null
+++ b/spring-5-data-reactive/src/main/java/com/baeldung/tailablecursor/service/WarnLogsCounter.java
@@ -0,0 +1,41 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
+import reactor.core.Disposable;
+import reactor.core.publisher.Flux;
+
+import javax.annotation.PreDestroy;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Slf4j
+public class WarnLogsCounter implements LogsCounter {
+
+ private static final String LEVEL_FIELD_NAME = "level";
+
+ private final AtomicInteger counter = new AtomicInteger();
+ private final Disposable subscription;
+
+ public WarnLogsCounter(ReactiveMongoTemplate template) {
+ Flux stream = template.tail(query(where(LEVEL_FIELD_NAME).is(LogLevel.WARN)), Log.class);
+ subscription = stream.subscribe(l -> {
+ log.warn("WARN log received: " + l);
+ counter.incrementAndGet();
+ });
+ }
+
+ @Override
+ public int count() {
+ return counter.get();
+ }
+
+ @PreDestroy
+ public void close() {
+ subscription.dispose();
+ }
+}
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/ErrorLogsCounterManualTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/ErrorLogsCounterManualTest.java
new file mode 100644
index 0000000000..5e20d3ec79
--- /dev/null
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/ErrorLogsCounterManualTest.java
@@ -0,0 +1,112 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.CreateCollectionOptions;
+import de.flapdoodle.embed.mongo.MongodExecutable;
+import de.flapdoodle.embed.mongo.MongodProcess;
+import de.flapdoodle.embed.mongo.MongodStarter;
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
+import de.flapdoodle.embed.mongo.config.Net;
+import de.flapdoodle.embed.mongo.distribution.Version;
+import de.flapdoodle.embed.process.runtime.Network;
+import org.bson.Document;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.util.SocketUtils;
+
+import java.io.IOException;
+import java.util.stream.IntStream;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class ErrorLogsCounterManualTest {
+
+ private static final String SERVER = "localhost";
+ private static final int PORT = SocketUtils.findAvailableTcpPort(10000);
+ private static final String DB_NAME = "test";
+ private static final String COLLECTION_NAME = Log.class.getName().toLowerCase();
+
+ private static final MongodStarter starter = MongodStarter.getDefaultInstance();
+ private static final int MAX_DOCUMENTS_IN_COLLECTION = 3;
+
+ private ErrorLogsCounter errorLogsCounter;
+ private MongodExecutable mongodExecutable;
+ private MongodProcess mongoDaemon;
+ private MongoDatabase db;
+
+ @Before
+ public void setup() throws Exception {
+ MongoTemplate mongoTemplate = initMongoTemplate();
+
+ MongoCollection collection = createCappedCollection();
+
+ persistDocument(collection, -1, LogLevel.ERROR, "my-service", "Initial log");
+
+ errorLogsCounter = new ErrorLogsCounter(mongoTemplate, COLLECTION_NAME);
+ Thread.sleep(1000L); // wait for initialization
+ }
+
+ private MongoTemplate initMongoTemplate() throws IOException {
+ mongodExecutable = starter.prepare(new MongodConfigBuilder()
+ .version(Version.Main.PRODUCTION)
+ .net(new Net(SERVER, PORT, Network.localhostIsIPv6()))
+ .build());
+ mongoDaemon = mongodExecutable.start();
+
+ MongoClient mongoClient = new MongoClient(SERVER, PORT);
+ db = mongoClient.getDatabase(DB_NAME);
+
+ return new MongoTemplate(mongoClient, DB_NAME);
+ }
+
+ private MongoCollection createCappedCollection() {
+ db.createCollection(COLLECTION_NAME, new CreateCollectionOptions()
+ .capped(true)
+ .sizeInBytes(100000)
+ .maxDocuments(MAX_DOCUMENTS_IN_COLLECTION));
+ return db.getCollection(COLLECTION_NAME);
+ }
+
+ private void persistDocument(MongoCollection collection,
+ int i, LogLevel level, String service, String message) {
+ Document logMessage = new Document();
+ logMessage.append("_id", i);
+ logMessage.append("level", level.toString());
+ logMessage.append("service", service);
+ logMessage.append("message", message);
+ collection.insertOne(logMessage);
+ }
+
+ @After
+ public void tearDown() {
+ errorLogsCounter.close();
+ mongoDaemon.stop();
+ mongodExecutable.stop();
+ }
+
+ @Test
+ public void whenErrorLogsArePersisted_thenTheyAreReceivedByLogsCounter() throws Exception {
+ MongoCollection collection = db.getCollection(COLLECTION_NAME);
+
+ IntStream.range(1, 10)
+ .forEach(i -> persistDocument(collection,
+ i,
+ i > 5 ? LogLevel.ERROR : LogLevel.INFO,
+ "service" + i,
+ "Message from service " + i)
+ );
+
+ Thread.sleep(1000L); // wait to receive all messages from the reactive mongodb driver
+
+ assertThat(collection.countDocuments(), is((long) MAX_DOCUMENTS_IN_COLLECTION));
+ assertThat(errorLogsCounter.count(), is(5));
+ }
+
+}
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/InfoLogsCounterManualTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/InfoLogsCounterManualTest.java
new file mode 100644
index 0000000000..cd8bd68257
--- /dev/null
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/InfoLogsCounterManualTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.LogsCounterApplication;
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import com.baeldung.tailablecursor.repository.LogsRepository;
+import lombok.extern.slf4j.Slf4j;
+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.mongodb.core.CollectionOptions;
+import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Flux;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = LogsCounterApplication.class)
+@Slf4j
+public class InfoLogsCounterManualTest {
+ @Autowired
+ private LogsRepository repository;
+
+ @Autowired
+ private ReactiveMongoTemplate template;
+
+ @Before
+ public void setUp() {
+ createCappedCollectionUsingReactiveMongoTemplate(template);
+
+ persistDocument(Log.builder()
+ .level(LogLevel.INFO)
+ .service("Service 2")
+ .message("Initial INFO message")
+ .build());
+ }
+
+ private void createCappedCollectionUsingReactiveMongoTemplate(ReactiveMongoTemplate reactiveMongoTemplate) {
+ reactiveMongoTemplate.dropCollection(Log.class).block();
+ reactiveMongoTemplate.createCollection(Log.class, CollectionOptions.empty()
+ .maxDocuments(5)
+ .size(1024 * 1024L)
+ .capped()).block();
+ }
+
+ private void persistDocument(Log log) {
+ repository.save(log).block();
+ }
+
+ @Test
+ public void wheInfoLogsArePersisted_thenTheyAreReceivedByLogsCounter() throws Exception {
+ InfoLogsCounter infoLogsCounter = new InfoLogsCounter(repository);
+
+ Thread.sleep(1000L); // wait for initialization
+
+ Flux.range(0,10)
+ .map(i -> Log.builder()
+ .level(i > 5 ? LogLevel.WARN : LogLevel.INFO)
+ .service("some-service")
+ .message("some log message")
+ .build())
+ .map(entity -> repository.save(entity).subscribe())
+ .blockLast();
+
+ Thread.sleep(1000L); // wait to receive all messages from the reactive mongodb driver
+
+ assertThat(infoLogsCounter.count(), is(7));
+ infoLogsCounter.close();
+ }
+}
\ No newline at end of file
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/WarnLogsCounterManualTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/WarnLogsCounterManualTest.java
new file mode 100644
index 0000000000..79d94b6784
--- /dev/null
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/tailablecursor/service/WarnLogsCounterManualTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.tailablecursor.service;
+
+import com.baeldung.tailablecursor.LogsCounterApplication;
+import com.baeldung.tailablecursor.domain.Log;
+import com.baeldung.tailablecursor.domain.LogLevel;
+import com.baeldung.tailablecursor.repository.LogsRepository;
+import lombok.extern.slf4j.Slf4j;
+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.mongodb.core.CollectionOptions;
+import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Flux;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = LogsCounterApplication.class)
+@Slf4j
+public class WarnLogsCounterManualTest {
+ @Autowired
+ private LogsRepository repository;
+
+ @Autowired
+ private ReactiveMongoTemplate template;
+
+ @Before
+ public void setUp() {
+ createCappedCollectionUsingReactiveMongoTemplate(template);
+
+ persistDocument(Log.builder()
+ .level(LogLevel.WARN)
+ .service("Service 1")
+ .message("Initial Warn message")
+ .build());
+ }
+
+ private void createCappedCollectionUsingReactiveMongoTemplate(ReactiveMongoTemplate reactiveMongoTemplate) {
+ reactiveMongoTemplate.dropCollection(Log.class).block();
+ reactiveMongoTemplate.createCollection(Log.class, CollectionOptions.empty()
+ .maxDocuments(5)
+ .size(1024 * 1024L)
+ .capped()).block();
+ }
+
+ private void persistDocument(Log log) {
+ repository.save(log).block();
+ }
+
+ @Test
+ public void whenWarnLogsArePersisted_thenTheyAreReceivedByLogsCounter() throws Exception {
+ WarnLogsCounter warnLogsCounter = new WarnLogsCounter(template);
+
+ Thread.sleep(1000L); // wait for initialization
+
+ Flux.range(0,10)
+ .map(i -> Log.builder()
+ .level(i > 5 ? LogLevel.WARN : LogLevel.INFO)
+ .service("some-service")
+ .message("some log message")
+ .build())
+ .map(entity -> repository.save(entity).subscribe())
+ .blockLast();
+
+ Thread.sleep(1000L); // wait to receive all messages from the reactive mongodb driver
+
+ assertThat(warnLogsCounter.count(), is(5));
+ warnLogsCounter.close();
+ }
+}
\ No newline at end of file
diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java
index 10cfaffce4..42da90ecd5 100644
--- a/spring-5-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java
+++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java
@@ -1,10 +1,13 @@
package com.baeldung.reactive.errorhandling;
-import java.io.IOException;
import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
@@ -15,6 +18,7 @@ import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
@WithMockUser
+@AutoConfigureWebTestClient(timeout = "10000")
public class ErrorHandlingIntegrationTest {
@Autowired
diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java
index fbf46a93cc..c1523cb5ee 100644
--- a/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java
+++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java
@@ -3,6 +3,7 @@ package com.baeldung.reactive.filters;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
@@ -14,6 +15,7 @@ import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@WithMockUser
+@AutoConfigureWebTestClient(timeout = "10000")
public class PlayerHandlerIntegrationTest {
@Autowired
diff --git a/spring-5-reactive/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java b/spring-5-reactive/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java
index 17fea6b50b..4395e0b048 100644
--- a/spring-5-reactive/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java
+++ b/spring-5-reactive/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java
@@ -28,7 +28,7 @@ public class PostExecutionUnitTest {
.expectComplete()
.verifyThenAssertThat()
.hasDropped(4)
- .tookLessThan(Duration.ofMillis(1050));
+ .tookLessThan(Duration.ofMillis(1500));
}
}
diff --git a/spring-activiti/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/SpringContextIntegrationTest.java
index ce48080753..89411df976 100644
--- a/spring-activiti/src/test/java/com/baeldung/SpringContextIntegrationTest.java
+++ b/spring-activiti/src/test/java/com/baeldung/SpringContextIntegrationTest.java
@@ -2,6 +2,7 @@ package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@@ -9,6 +10,7 @@ import com.baeldung.activitiwithspring.ActivitiWithSpringApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ActivitiWithSpringApplication.class)
+@AutoConfigureTestDatabase
public class SpringContextIntegrationTest {
@Test
diff --git a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java
index 53bdcee888..7f99483fcf 100644
--- a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java
+++ b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java
@@ -4,6 +4,7 @@ import org.activiti.engine.IdentityService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.test.context.junit4.SpringRunner;
@@ -14,6 +15,7 @@ import com.baeldung.activiti.security.withspring.ActivitiSpringSecurityApplicati
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ActivitiSpringSecurityApplication.class)
@WebAppConfiguration
+@AutoConfigureTestDatabase
public class ActivitiSpringSecurityIntegrationTest {
@Autowired
private IdentityService identityService;
diff --git a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java
index 8c1e400215..d289693a73 100644
--- a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java
+++ b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java
@@ -2,11 +2,13 @@ package com.baeldung.activitiwithspring;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
-@SpringBootTest
+@SpringBootTest(classes = ActivitiWithSpringApplication.class)
+@AutoConfigureTestDatabase
public class ActivitiWithSpringApplicationIntegrationTest {
@Test
diff --git a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ProcessEngineCreationIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ProcessEngineCreationIntegrationTest.java
index 00538f8e6e..5052f84d6a 100644
--- a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ProcessEngineCreationIntegrationTest.java
+++ b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ProcessEngineCreationIntegrationTest.java
@@ -4,7 +4,7 @@ import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.junit.Test;
-
+import org.junit.After;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -62,4 +62,9 @@ public class ProcessEngineCreationIntegrationTest {
assertNotNull(processEngine);
assertEquals("sa", processEngine.getProcessEngineConfiguration().getJdbcUsername());
}
+
+ @After
+ public void cleanup() {
+ ProcessEngines.destroy();
+ }
}
diff --git a/spring-boot-performance/pom.xml b/spring-boot-performance/pom.xml
new file mode 100644
index 0000000000..bbee7493cc
--- /dev/null
+++ b/spring-boot-performance/pom.xml
@@ -0,0 +1,45 @@
+
+ 4.0.0
+ spring-boot-performance
+ spring-boot-performance
+ war
+ This is a simple Spring Boot application taking advantage of the latest Spring Boot improvements/features. Current version: 2.2
+
+
+ parent-boot-performance
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-performance
+
+
+
+
+ com.baeldung.lazyinitialization.Application
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ spring-boot-performance
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/Application.java b/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/Application.java
new file mode 100644
index 0000000000..195b260399
--- /dev/null
+++ b/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/Application.java
@@ -0,0 +1,32 @@
+package com.baeldung.lazyinitialization;
+
+import com.baeldung.lazyinitialization.services.Writer;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class Application {
+
+ @Bean("writer1")
+ public Writer getWriter1() {
+ return new Writer("Writer 1");
+ }
+
+ @Bean("writer2")
+ public Writer getWriter2() {
+ return new Writer("Writer 2");
+ }
+
+ public static void main(String[] args) {
+ ApplicationContext ctx = SpringApplication.run(Application.class, args);
+ System.out.println("Application context initialized!!!");
+
+ Writer writer1 = ctx.getBean("writer1", Writer.class);
+ writer1.write("First message");
+
+ Writer writer2 = ctx.getBean("writer2", Writer.class);
+ writer2.write("Second message");
+ }
+}
diff --git a/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/services/Writer.java b/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/services/Writer.java
new file mode 100644
index 0000000000..7c67fb7ea4
--- /dev/null
+++ b/spring-boot-performance/src/main/java/com/baeldung/lazyinitialization/services/Writer.java
@@ -0,0 +1,16 @@
+package com.baeldung.lazyinitialization.services;
+
+public class Writer {
+
+ private final String writerId;
+
+ public Writer(String writerId) {
+ this.writerId = writerId;
+ System.out.println(writerId + " initialized!!!");
+ }
+
+ public void write(String message) {
+ System.out.println(writerId + ": " + message);
+ }
+
+}
diff --git a/spring-boot-performance/src/main/resources/application.yml b/spring-boot-performance/src/main/resources/application.yml
new file mode 100644
index 0000000000..25f03eed56
--- /dev/null
+++ b/spring-boot-performance/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+spring:
+ main:
+ lazy-initialization: true
\ No newline at end of file
diff --git a/spring-boot/src/main/java/org/baeldung/properties/AdditionalConfiguration.java b/spring-boot/src/main/java/org/baeldung/properties/AdditionalConfiguration.java
new file mode 100644
index 0000000000..499666c143
--- /dev/null
+++ b/spring-boot/src/main/java/org/baeldung/properties/AdditionalConfiguration.java
@@ -0,0 +1,14 @@
+package org.baeldung.properties;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties(AdditionalProperties.class)
+public class AdditionalConfiguration {
+
+ @Autowired
+ private AdditionalProperties additionalProperties;
+
+}
diff --git a/spring-boot/src/main/java/org/baeldung/properties/AdditionalProperties.java b/spring-boot/src/main/java/org/baeldung/properties/AdditionalProperties.java
new file mode 100644
index 0000000000..64e39b1475
--- /dev/null
+++ b/spring-boot/src/main/java/org/baeldung/properties/AdditionalProperties.java
@@ -0,0 +1,26 @@
+package org.baeldung.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "additional")
+public class AdditionalProperties {
+
+ private String unit;
+ private int max;
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ public int getMax() {
+ return max;
+ }
+
+ public void setMax(int max) {
+ this.max = max;
+ }
+}
diff --git a/spring-boot/src/main/java/org/baeldung/properties/ConfigPropertiesDemoApplication.java b/spring-boot/src/main/java/org/baeldung/properties/ConfigPropertiesDemoApplication.java
index 395d68060b..7b8f2c3411 100644
--- a/spring-boot/src/main/java/org/baeldung/properties/ConfigPropertiesDemoApplication.java
+++ b/spring-boot/src/main/java/org/baeldung/properties/ConfigPropertiesDemoApplication.java
@@ -5,11 +5,14 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
-@ComponentScan(basePackageClasses = { ConfigProperties.class, JsonProperties.class, CustomJsonProperties.class })
+@ComponentScan(basePackageClasses = {ConfigProperties.class,
+ JsonProperties.class,
+ CustomJsonProperties.class,
+ AdditionalConfiguration.class})
public class ConfigPropertiesDemoApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer())
- .run();
+ .run();
}
}
diff --git a/spring-boot/src/test/java/com/baeldung/properties/ConfigPropertiesIntegrationTest.java b/spring-boot/src/test/java/com/baeldung/properties/ConfigPropertiesIntegrationTest.java
index 3a4b6551b1..8f07b2da35 100644
--- a/spring-boot/src/test/java/com/baeldung/properties/ConfigPropertiesIntegrationTest.java
+++ b/spring-boot/src/test/java/com/baeldung/properties/ConfigPropertiesIntegrationTest.java
@@ -1,5 +1,6 @@
package com.baeldung.properties;
+import org.baeldung.properties.AdditionalProperties;
import org.baeldung.properties.ConfigProperties;
import org.baeldung.properties.ConfigPropertiesDemoApplication;
import org.junit.Assert;
@@ -18,6 +19,9 @@ public class ConfigPropertiesIntegrationTest {
@Autowired
private ConfigProperties properties;
+ @Autowired
+ private AdditionalProperties additionalProperties;
+
@Test
public void whenSimplePropertyQueriedthenReturnsProperty() throws Exception {
Assert.assertTrue("From address is read as null!", properties.getFrom() != null);
@@ -42,4 +46,10 @@ public class ConfigPropertiesIntegrationTest {
Assert.assertTrue("Incorrectly bound object property!", properties.getCredentials().getUsername().equals("john"));
Assert.assertTrue("Incorrectly bound object property!", properties.getCredentials().getPassword().equals("password"));
}
+
+ @Test
+ public void whenAdditionalPropertyQueriedthenReturnsProperty() {
+ Assert.assertTrue(additionalProperties.getUnit().equals("km"));
+ Assert.assertTrue(additionalProperties.getMax() == 100);
+ }
}
diff --git a/spring-boot/src/test/resources/configprops-test.properties b/spring-boot/src/test/resources/configprops-test.properties
index ea11f2159e..5eed93a22b 100644
--- a/spring-boot/src/test/resources/configprops-test.properties
+++ b/spring-boot/src/test/resources/configprops-test.properties
@@ -20,3 +20,7 @@ mail.credentials.authMethod=SHA1
#Bean method properties
item.name=Test item name
item.size=21
+
+#Additional properties
+additional.unit=km
+additional.max=100
diff --git a/spring-core/pom.xml b/spring-core/pom.xml
index 814addecdd..75e9fd7131 100644
--- a/spring-core/pom.xml
+++ b/spring-core/pom.xml
@@ -56,6 +56,12 @@
spring-boot-test
${mockito.spring.boot.version}
test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
commons-io
@@ -85,6 +91,7 @@
2.5
1.5.2.RELEASE
1.10.19
+ 3.12.2
\ No newline at end of file
diff --git a/spring-core/src/main/resources/constructordi.xml b/spring-core/src/main/resources/constructordi.xml
index 231e72adcb..983a00a80f 100644
--- a/spring-core/src/main/resources/constructordi.xml
+++ b/spring-core/src/main/resources/constructordi.xml
@@ -1,19 +1,21 @@
+ https://www.springframework.org/schema/beans/spring-beans.xsd">
-
+
-
+
diff --git a/spring-core/src/test/java/com/baeldung/constructordi/ConstructorDependencyInjectionIntegrationTest.java b/spring-core/src/test/java/com/baeldung/constructordi/ConstructorDependencyInjectionIntegrationTest.java
new file mode 100644
index 0000000000..7bd0ad0c86
--- /dev/null
+++ b/spring-core/src/test/java/com/baeldung/constructordi/ConstructorDependencyInjectionIntegrationTest.java
@@ -0,0 +1,33 @@
+package com.baeldung.constructordi;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import com.baeldung.constructordi.domain.Car;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = Config.class)
+public class ConstructorDependencyInjectionIntegrationTest {
+
+ @Test
+ public void givenPrototypeInjection_WhenObjectFactory_ThenNewInstanceReturn() {
+ ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
+ Car firstContextCar = context.getBean(Car.class);
+
+ ApplicationContext xmlContext = new ClassPathXmlApplicationContext("constructordi.xml");
+ Car secondContextCar = xmlContext.getBean(Car.class);
+
+ assertThat(firstContextCar).isNotSameAs(secondContextCar);
+ assertThat(firstContextCar).hasToString("Engine: v8 5 Transmission: sliding");
+ assertThat(secondContextCar).hasToString("Engine: v4 2 Transmission: sliding");
+ }
+
+}
diff --git a/spring-security-rest-custom/src/main/java/org/baeldung/config/child/MethodSecurityConfig.java b/spring-security-rest-custom/src/main/java/org/baeldung/config/child/MethodSecurityConfig.java
new file mode 100644
index 0000000000..bc9a9f161b
--- /dev/null
+++ b/spring-security-rest-custom/src/main/java/org/baeldung/config/child/MethodSecurityConfig.java
@@ -0,0 +1,37 @@
+package org.baeldung.config.child;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.intercept.RunAsImplAuthenticationProvider;
+import org.springframework.security.access.intercept.RunAsManager;
+import org.springframework.security.access.intercept.RunAsManagerImpl;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
+
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true)
+public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
+
+ @Override
+ protected RunAsManager runAsManager() {
+ RunAsManagerImpl runAsManager = new RunAsManagerImpl();
+ runAsManager.setKey("MyRunAsKey");
+ return runAsManager;
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth.authenticationProvider(runAsAuthenticationProvider());
+ }
+
+ @Bean
+ public AuthenticationProvider runAsAuthenticationProvider() {
+ RunAsImplAuthenticationProvider authProvider = new RunAsImplAuthenticationProvider();
+ authProvider.setKey("MyRunAsKey");
+ return authProvider;
+ }
+}
\ No newline at end of file
diff --git a/spring-security-rest-custom/src/main/java/org/baeldung/service/RunAsService.java b/spring-security-rest-custom/src/main/java/org/baeldung/service/RunAsService.java
new file mode 100644
index 0000000000..a6320f8b81
--- /dev/null
+++ b/spring-security-rest-custom/src/main/java/org/baeldung/service/RunAsService.java
@@ -0,0 +1,17 @@
+package org.baeldung.service;
+
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RunAsService {
+
+ @Secured({ "ROLE_RUN_AS_REPORTER" })
+ public Authentication getCurrentUser() {
+ Authentication authentication =
+ SecurityContextHolder.getContext().getAuthentication();
+ return authentication;
+ }
+}
\ No newline at end of file
diff --git a/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/RunAsController.java b/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/RunAsController.java
new file mode 100644
index 0000000000..08f39aa5f2
--- /dev/null
+++ b/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/RunAsController.java
@@ -0,0 +1,23 @@
+package org.baeldung.web.controller;
+
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+
+@Controller
+@RequestMapping("/runas")
+public class RunAsController {
+
+ @Secured({ "ROLE_USER", "RUN_AS_REPORTER" })
+ @RequestMapping
+ @ResponseBody
+ public String tryRunAs() {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ return "Current User Authorities inside this RunAS method only " +
+ auth.getAuthorities().toString();
+ }
+}
diff --git a/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/ViewController.java b/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/ViewController.java
index 83c0292d98..fbcb9b979e 100644
--- a/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/ViewController.java
+++ b/spring-security-rest-custom/src/main/java/org/baeldung/web/controller/ViewController.java
@@ -10,4 +10,9 @@ public class ViewController {
public String index() {
return "index";
}
+
+ @RequestMapping({ "/runashome" })
+ public String run() {
+ return "runas";
+ }
}
diff --git a/spring-security-rest-custom/src/main/webapp/WEB-INF/templates/runas.html b/spring-security-rest-custom/src/main/webapp/WEB-INF/templates/runas.html
new file mode 100644
index 0000000000..c7c3b2e0e4
--- /dev/null
+++ b/spring-security-rest-custom/src/main/webapp/WEB-INF/templates/runas.html
@@ -0,0 +1,23 @@
+
+
+
+ Current user authorities:
+ user
+
+
+ Generate Report As Super User
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-static-resources/pom.xml b/spring-static-resources/pom.xml
index f01e807919..84519a37c1 100644
--- a/spring-static-resources/pom.xml
+++ b/spring-static-resources/pom.xml
@@ -140,6 +140,13 @@
handlebars
${handlebars.version}
+
+
+
+ commons-io
+ commons-io
+ ${commons.io.version}
+
org.springframework
@@ -208,6 +215,9 @@
1.5.1
+
+
+ 2.5
\ No newline at end of file
diff --git a/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/LoadResourceConfig.java b/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/LoadResourceConfig.java
new file mode 100644
index 0000000000..32b9ba84d0
--- /dev/null
+++ b/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/LoadResourceConfig.java
@@ -0,0 +1,15 @@
+package com.baeldung.loadresourceasstring;
+
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class LoadResourceConfig {
+
+ @Bean
+ public String resourceString() {
+ return ResourceReader.readFileToString("resource.txt");
+ }
+
+}
diff --git a/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/ResourceReader.java b/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/ResourceReader.java
new file mode 100644
index 0000000000..7bc1babe91
--- /dev/null
+++ b/spring-static-resources/src/main/java/com/baeldung/loadresourceasstring/ResourceReader.java
@@ -0,0 +1,30 @@
+package com.baeldung.loadresourceasstring;
+
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.FileCopyUtils;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+
+public class ResourceReader {
+
+ public static String readFileToString(String path) {
+ ResourceLoader resourceLoader = new DefaultResourceLoader();
+ Resource resource = resourceLoader.getResource(path);
+ return asString(resource);
+ }
+
+ public static String asString(Resource resource) {
+ try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
+ return FileCopyUtils.copyToString(reader);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git a/spring-static-resources/src/main/resources/resource.txt b/spring-static-resources/src/main/resources/resource.txt
new file mode 100644
index 0000000000..e78cfa90c2
--- /dev/null
+++ b/spring-static-resources/src/main/resources/resource.txt
@@ -0,0 +1 @@
+This is a resource text file. This file will be loaded as a resource and use its contents as a string.
\ No newline at end of file
diff --git a/spring-static-resources/src/test/java/com/baeldung/loadresourceasstring/LoadResourceAsStringIntegrationTest.java b/spring-static-resources/src/test/java/com/baeldung/loadresourceasstring/LoadResourceAsStringIntegrationTest.java
new file mode 100644
index 0000000000..c16c1a9720
--- /dev/null
+++ b/spring-static-resources/src/test/java/com/baeldung/loadresourceasstring/LoadResourceAsStringIntegrationTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.loadresourceasstring;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.InputStreamReader;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = LoadResourceConfig.class)
+public class LoadResourceAsStringIntegrationTest {
+
+ private static final String EXPECTED_RESOURCE_VALUE = "This is a resource text file. This file will be loaded as a " + "resource and use its contents as a string.";
+
+ @Value("#{T(com.baeldung.loadresourceasstring.ResourceReader).readFileToString('classpath:resource.txt')}")
+ private String resourceStringUsingSpel;
+
+ @Autowired
+ @Qualifier("resourceString")
+ private String resourceString;
+
+ @Autowired
+ private ResourceLoader resourceLoader;
+
+ @Test
+ public void givenUsingResourceLoadAndFileCopyUtils_whenConvertingAResourceToAString_thenCorrect() {
+ Resource resource = resourceLoader.getResource("classpath:resource.txt");
+ assertEquals(EXPECTED_RESOURCE_VALUE, ResourceReader.asString(resource));
+ }
+
+ @Test
+ public void givenUsingResourceStringBean_whenConvertingAResourceToAString_thenCorrect() {
+ assertEquals(EXPECTED_RESOURCE_VALUE, resourceString);
+ }
+
+ @Test
+ public void givenUsingSpel_whenConvertingAResourceToAString_thenCorrect() {
+ assertEquals(EXPECTED_RESOURCE_VALUE, resourceStringUsingSpel);
+ }
+
+
+
+
+}
diff --git a/testing-modules/junit-5-advanced/pom.xml b/testing-modules/junit-5-advanced/pom.xml
new file mode 100644
index 0000000000..f65f7e2a2f
--- /dev/null
+++ b/testing-modules/junit-5-advanced/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+ junit-5-advanced
+ 1.0-SNAPSHOT
+ junit-5-advanced
+ Advanced JUnit 5 Topics
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../../
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit-jupiter.version}
+ test
+
+
+
+
+ 5.4.2
+ 2.21.0
+
+
+
diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/displayname/DisplayNameGeneratorUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/displayname/DisplayNameGeneratorUnitTest.java
new file mode 100644
index 0000000000..311539f760
--- /dev/null
+++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/displayname/DisplayNameGeneratorUnitTest.java
@@ -0,0 +1,87 @@
+package com.baeldung.displayname;
+
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.lang.reflect.Method;
+
+@DisplayNameGeneration(DisplayNameGeneratorUnitTest.ReplaceCamelCase.class)
+class DisplayNameGeneratorUnitTest {
+
+ @Test
+ void camelCaseName() {
+ }
+
+ @Nested
+ @DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
+ class ANumberIsFizz {
+ @Test
+ void ifItIsDivisibleByThree() {
+ }
+
+ @ParameterizedTest(name = "Number {0} is fizz.")
+ @ValueSource(ints = { 3, 12, 18 })
+ void ifItIsOneOfTheFollowingNumbers(int number) {
+ }
+ }
+
+ @Nested
+ @DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
+ class ANumberIsBuzz {
+ @Test
+ void ifItIsDivisibleByFive() {
+ }
+
+ @ParameterizedTest(name = "Number {0} is buzz.")
+ @ValueSource(ints = { 5, 10, 20 })
+ void ifItIsOneOfTheFollowingNumbers(int number) {
+ }
+ }
+
+ static class IndicativeSentences extends ReplaceCamelCase {
+ @Override
+ public String generateDisplayNameForNestedClass(Class> nestedClass) {
+ return super.generateDisplayNameForNestedClass(nestedClass) + "...";
+ }
+
+ @Override
+ public String generateDisplayNameForMethod(Class> testClass, Method testMethod) {
+ return replaceCamelCase(testClass.getSimpleName() + " " + testMethod.getName()) + ".";
+ }
+ }
+
+ static class ReplaceCamelCase extends DisplayNameGenerator.Standard {
+ @Override
+ public String generateDisplayNameForClass(Class> testClass) {
+ return replaceCamelCase(super.generateDisplayNameForClass(testClass));
+ }
+
+ @Override
+ public String generateDisplayNameForNestedClass(Class> nestedClass) {
+ return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));
+ }
+
+ @Override
+ public String generateDisplayNameForMethod(Class> testClass, Method testMethod) {
+ return this.replaceCamelCase(testMethod.getName()) + DisplayNameGenerator.parameterTypesAsString(testMethod);
+ }
+
+ String replaceCamelCase(String camelCase) {
+ StringBuilder result = new StringBuilder();
+ result.append(camelCase.charAt(0));
+ for (int i=1; i
-
- org.junit.platform
- junit-platform-engine
- ${junit.platform.version}
-
-
- org.junit.jupiter
- junit-jupiter-params
- ${junit.jupiter.version}
-
org.junit.platform
junit-platform-runner
- ${junit.platform.version}
+ ${junit-platform.version}
test
@@ -44,6 +34,24 @@
${junit.vintage.version}
test
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit-jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit-jupiter.version}
+ test
+
com.h2database
h2
@@ -92,13 +100,7 @@
maven-surefire-plugin
${maven-surefire-plugin.version}
-
-
- org.junit.platform
- junit-platform-surefire-provider
- ${junit.platform.version}
-
-
+
**/*IntegrationTest.java
@@ -148,9 +150,9 @@
- 5.4.2
- 1.2.0
- 5.2.0
+ 5.4.2
+ 1.2.0
+ 5.4.2
1.4.196
5.0.6.RELEASE
2.21.0
diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/SharedTemporaryDirectoryUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/SharedTemporaryDirectoryUnitTest.java
new file mode 100644
index 0000000000..9483a33143
--- /dev/null
+++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/SharedTemporaryDirectoryUnitTest.java
@@ -0,0 +1,49 @@
+package com.baeldung.extensions.tempdir;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertLinesMatch;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.io.TempDir;
+
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+
+@TestMethodOrder(OrderAnnotation.class)
+class SharedTemporaryDirectoryUnitTest {
+
+ @TempDir
+ static Path sharedTempDir;
+
+ @Test
+ @Order(1)
+ void givenFieldWithSharedTempDirectoryPath_whenWriteToFile_thenContentIsCorrect() throws IOException {
+ Path numbers = sharedTempDir.resolve("numbers.txt");
+
+ List lines = Arrays.asList("1", "2", "3");
+ Files.write(numbers, lines);
+
+ assertAll(
+ () -> assertTrue("File should exist", Files.exists(numbers)),
+ () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
+
+ Files.createTempDirectory("bpb");
+ }
+
+ @Test
+ @Order(2)
+ void givenAlreadyWrittenToSharedFile_whenCheckContents_thenContentIsCorrect() throws IOException {
+ Path numbers = sharedTempDir.resolve("numbers.txt");
+
+ assertLinesMatch(Arrays.asList("1", "2", "3"), Files.readAllLines(numbers));
+ }
+
+}
diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/TemporaryDirectoryUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/TemporaryDirectoryUnitTest.java
new file mode 100644
index 0000000000..c6f1a7cd77
--- /dev/null
+++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/extensions/tempdir/TemporaryDirectoryUnitTest.java
@@ -0,0 +1,48 @@
+package com.baeldung.extensions.tempdir;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertLinesMatch;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class TemporaryDirectoryUnitTest {
+
+ @Test
+ void givenTestMethodWithTempDirectoryPath_whenWriteToFile_thenContentIsCorrect(@TempDir Path tempDir) throws IOException {
+ Path numbers = tempDir.resolve("numbers.txt");
+
+ List lines = Arrays.asList("1", "2", "3");
+ Files.write(numbers, lines);
+
+ assertAll(
+ () -> assertTrue("File should exist", Files.exists(numbers)),
+ () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
+ }
+
+ @TempDir
+ File anotherTempDir;
+
+ @Test
+ void givenFieldWithTempDirectoryFile_whenWriteToFile_thenContentIsCorrect() throws IOException {
+ assertTrue("Should be a directory ", this.anotherTempDir.isDirectory());
+
+ File letters = new File(anotherTempDir, "letters.txt");
+ List lines = Arrays.asList("x", "y", "z");
+
+ Files.write(letters.toPath(), lines);
+
+ assertAll(
+ () -> assertTrue("File should exist", Files.exists(letters.toPath())),
+ () -> assertLinesMatch(lines, Files.readAllLines(letters.toPath())));
+ }
+
+}
diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml
index 90ec857b7f..95a19c2557 100644
--- a/testing-modules/pom.xml
+++ b/testing-modules/pom.xml
@@ -33,5 +33,6 @@
testing
testng
junit-5-basics
+ junit-5-advanced