diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md
index 6a25f8cac8..25e2733538 100644
--- a/algorithms-miscellaneous-1/README.md
+++ b/algorithms-miscellaneous-1/README.md
@@ -7,8 +7,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Validating Input With Finite Automata in Java](https://www.baeldung.com/java-finite-automata)
- [Example of Hill Climbing Algorithm](https://www.baeldung.com/java-hill-climbing-algorithm)
-- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search)
-- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search)
- [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm)
- [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance)
- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element)
diff --git a/algorithms-miscellaneous-3/README.md b/algorithms-miscellaneous-3/README.md
index 93426b3e0d..23a10258a3 100644
--- a/algorithms-miscellaneous-3/README.md
+++ b/algorithms-miscellaneous-3/README.md
@@ -14,8 +14,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique)
- [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle)
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
-- [Interpolation Search in Java](https://www.baeldung.com/java-interpolation-search)
- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm)
- [Creating a Custom Annotation in Java](https://www.baeldung.com/java-custom-annotation)
-- [Breadth-First Search Algorithm in Java](https://www.baeldung.com/java-breadth-first-search)
- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4)
diff --git a/algorithms-miscellaneous-4/README.md b/algorithms-miscellaneous-4/README.md
index df2eafb733..fd33b58d72 100644
--- a/algorithms-miscellaneous-4/README.md
+++ b/algorithms-miscellaneous-4/README.md
@@ -5,10 +5,10 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
### Relevant articles:
- [Multi-Swarm Optimization Algorithm in Java](https://www.baeldung.com/java-multi-swarm-algorithm)
-- [String Search Algorithms for Large Texts](https://www.baeldung.com/java-full-text-search-algorithms)
- [Check If a String Contains All The Letters of The Alphabet](https://www.baeldung.com/java-string-contains-all-letters)
- [Find the Middle Element of a Linked List](https://www.baeldung.com/java-linked-list-middle-element)
- [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings)
- [Find the Longest Substring without Repeating Characters](https://www.baeldung.com/java-longest-substring-without-repeated-characters)
- [Permutations of an Array in Java](https://www.baeldung.com/java-array-permutations)
+- [Find the Smallest Missing Integer in an Array](https://www.baeldung.com/java-smallest-missing-integer-in-array)
- More articles: [[<-- prev]](/algorithms-miscellaneous-3) [[next -->]](/algorithms-miscellaneous-5)
diff --git a/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java b/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java
deleted file mode 100755
index dfe015aad2..0000000000
--- a/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/StringSearchAlgorithmsUnitTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.baeldung.algorithms;
-
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.baeldung.algorithms.string.search.StringSearchAlgorithms;
-
-public class StringSearchAlgorithmsUnitTest {
-
-
- @Test
- public void testStringSearchAlgorithms(){
- String text = "This is some nice text.";
- String pattern = "some";
-
- int realPosition = text.indexOf(pattern);
- Assert.assertTrue(realPosition == StringSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray()));
- Assert.assertTrue(realPosition == StringSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray()));
- Assert.assertTrue(realPosition == StringSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray()));
- Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray()));
- Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray()));
- }
-
-}
diff --git a/algorithms-miscellaneous-5/README.md b/algorithms-miscellaneous-5/README.md
index 598fbab8b5..27ab303210 100644
--- a/algorithms-miscellaneous-5/README.md
+++ b/algorithms-miscellaneous-5/README.md
@@ -9,4 +9,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Reversing a Binary Tree in Java](https://www.baeldung.com/java-reversing-a-binary-tree)
- [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers)
- [Knapsack Problem Implementation in Java](https://www.baeldung.com/java-knapsack)
+- [How to Determine if a Binary Tree is Balanced](https://www.baeldung.com/java-balanced-binary-tree)
- More articles: [[<-- prev]](/../algorithms-miscellaneous-4)
diff --git a/algorithms-searching/README.md b/algorithms-searching/README.md
new file mode 100644
index 0000000000..d86c3e3de8
--- /dev/null
+++ b/algorithms-searching/README.md
@@ -0,0 +1,11 @@
+## Algorithms - Searching
+
+This module contains articles about searching algorithms.
+
+### Relevant articles:
+- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search)
+- [Depth First Search in Java](https://www.baeldung.com/java-depth-first-search)
+- [Interpolation Search in Java](https://www.baeldung.com/java-interpolation-search)
+- [Breadth-First Search Algorithm in Java](https://www.baeldung.com/java-breadth-first-search)
+- [String Search Algorithms for Large Texts](https://www.baeldung.com/java-full-text-search-algorithms)
+- [Monte Carlo Tree Search for Tic-Tac-Toe Game](https://www.baeldung.com/java-monte-carlo-tree-search)
diff --git a/algorithms-searching/pom.xml b/algorithms-searching/pom.xml
new file mode 100644
index 0000000000..6bd4b0233e
--- /dev/null
+++ b/algorithms-searching/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+ algorithms-searching
+ 0.0.1-SNAPSHOT
+ algorithms-searching
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.assertj
+ assertj-core
+ ${org.assertj.core.version}
+ test
+
+
+
+
+ algorithms-searching
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ 3.9.0
+
+
+
\ No newline at end of file
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
similarity index 96%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
index 5b2ac49d4e..82aefe282b 100644
--- a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
+++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
@@ -1,55 +1,55 @@
-package com.baeldung.algorithms.binarysearch;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-public class BinarySearch {
-
- public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) {
-
- int index = Integer.MAX_VALUE;
-
- while (low <= high) {
-
- int mid = (low + high) / 2;
-
- if (sortedArray[mid] < key) {
- low = mid + 1;
- } else if (sortedArray[mid] > key) {
- high = mid - 1;
- } else if (sortedArray[mid] == key) {
- index = mid;
- break;
- }
- }
- return index;
- }
-
- public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) {
-
- int middle = (low + high) / 2;
- if (high < low) {
- return -1;
- }
-
- if (key == sortedArray[middle]) {
- return middle;
- } else if (key < sortedArray[middle]) {
- return runBinarySearchRecursively(sortedArray, key, low, middle - 1);
- } else {
- return runBinarySearchRecursively(sortedArray, key, middle + 1, high);
- }
- }
-
- public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) {
- int index = Arrays.binarySearch(sortedArray, key);
- return index;
- }
-
- public int runBinarySearchUsingJavaCollections(List sortedList, Integer key) {
- int index = Collections.binarySearch(sortedList, key);
- return index;
- }
-
-}
+package com.baeldung.algorithms.binarysearch;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class BinarySearch {
+
+ public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) {
+
+ int index = Integer.MAX_VALUE;
+
+ while (low <= high) {
+
+ int mid = (low + high) / 2;
+
+ if (sortedArray[mid] < key) {
+ low = mid + 1;
+ } else if (sortedArray[mid] > key) {
+ high = mid - 1;
+ } else if (sortedArray[mid] == key) {
+ index = mid;
+ break;
+ }
+ }
+ return index;
+ }
+
+ public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) {
+
+ int middle = (low + high) / 2;
+ if (high < low) {
+ return -1;
+ }
+
+ if (key == sortedArray[middle]) {
+ return middle;
+ } else if (key < sortedArray[middle]) {
+ return runBinarySearchRecursively(sortedArray, key, low, middle - 1);
+ } else {
+ return runBinarySearchRecursively(sortedArray, key, middle + 1, high);
+ }
+ }
+
+ public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) {
+ int index = Arrays.binarySearch(sortedArray, key);
+ return index;
+ }
+
+ public int runBinarySearchUsingJavaCollections(List sortedList, Integer key) {
+ int index = Collections.binarySearch(sortedList, key);
+ return index;
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithm.java
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Node.java
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/breadthfirstsearch/Tree.java
diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java
new file mode 100644
index 0000000000..a6019ea9f9
--- /dev/null
+++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/BinaryTree.java
@@ -0,0 +1,227 @@
+package com.baeldung.algorithms.dfs;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Stack;
+
+public class BinaryTree {
+
+ Node root;
+
+ public void add(int value) {
+ root = addRecursive(root, value);
+ }
+
+ private Node addRecursive(Node current, int value) {
+
+ if (current == null) {
+ return new Node(value);
+ }
+
+ if (value < current.value) {
+ current.left = addRecursive(current.left, value);
+ } else if (value > current.value) {
+ current.right = addRecursive(current.right, value);
+ }
+
+ return current;
+ }
+
+ public boolean isEmpty() {
+ return root == null;
+ }
+
+ public int getSize() {
+ return getSizeRecursive(root);
+ }
+
+ private int getSizeRecursive(Node current) {
+ return current == null ? 0 : getSizeRecursive(current.left) + 1 + getSizeRecursive(current.right);
+ }
+
+ public boolean containsNode(int value) {
+ return containsNodeRecursive(root, value);
+ }
+
+ private boolean containsNodeRecursive(Node current, int value) {
+ if (current == null) {
+ return false;
+ }
+
+ if (value == current.value) {
+ return true;
+ }
+
+ return value < current.value
+ ? containsNodeRecursive(current.left, value)
+ : containsNodeRecursive(current.right, value);
+ }
+
+ public void delete(int value) {
+ root = deleteRecursive(root, value);
+ }
+
+ private Node deleteRecursive(Node current, int value) {
+ if (current == null) {
+ return null;
+ }
+
+ if (value == current.value) {
+ // Case 1: no children
+ if (current.left == null && current.right == null) {
+ return null;
+ }
+
+ // Case 2: only 1 child
+ if (current.right == null) {
+ return current.left;
+ }
+
+ if (current.left == null) {
+ return current.right;
+ }
+
+ // Case 3: 2 children
+ int smallestValue = findSmallestValue(current.right);
+ current.value = smallestValue;
+ current.right = deleteRecursive(current.right, smallestValue);
+ return current;
+ }
+ if (value < current.value) {
+ current.left = deleteRecursive(current.left, value);
+ return current;
+ }
+
+ current.right = deleteRecursive(current.right, value);
+ return current;
+ }
+
+ private int findSmallestValue(Node root) {
+ return root.left == null ? root.value : findSmallestValue(root.left);
+ }
+
+ public void traverseInOrder(Node node) {
+ if (node != null) {
+ traverseInOrder(node.left);
+ visit(node.value);
+ traverseInOrder(node.right);
+ }
+ }
+
+ public void traversePreOrder(Node node) {
+ if (node != null) {
+ visit(node.value);
+ traversePreOrder(node.left);
+ traversePreOrder(node.right);
+ }
+ }
+
+ public void traversePostOrder(Node node) {
+ if (node != null) {
+ traversePostOrder(node.left);
+ traversePostOrder(node.right);
+ visit(node.value);
+ }
+ }
+
+ public void traverseLevelOrder() {
+ if (root == null) {
+ return;
+ }
+
+ Queue nodes = new LinkedList<>();
+ nodes.add(root);
+
+ while (!nodes.isEmpty()) {
+
+ Node node = nodes.remove();
+
+ System.out.print(" " + node.value);
+
+ if (node.left != null) {
+ nodes.add(node.left);
+ }
+
+ if (node.left != null) {
+ nodes.add(node.right);
+ }
+ }
+ }
+
+
+ public void traverseInOrderWithoutRecursion() {
+ Stack stack = new Stack();
+ Node current = root;
+ stack.push(root);
+ while(! stack.isEmpty()) {
+ while(current.left != null) {
+ current = current.left;
+ stack.push(current);
+ }
+ current = stack.pop();
+ visit(current.value);
+ if(current.right != null) {
+ current = current.right;
+ stack.push(current);
+ }
+ }
+ }
+
+ public void traversePreOrderWithoutRecursion() {
+ Stack stack = new Stack();
+ Node current = root;
+ stack.push(root);
+ while(! stack.isEmpty()) {
+ current = stack.pop();
+ visit(current.value);
+
+ if(current.right != null)
+ stack.push(current.right);
+
+ if(current.left != null)
+ stack.push(current.left);
+ }
+ }
+
+ public void traversePostOrderWithoutRecursion() {
+ Stack stack = new Stack();
+ Node prev = root;
+ Node current = root;
+ stack.push(root);
+
+ while (!stack.isEmpty()) {
+ current = stack.peek();
+ boolean hasChild = (current.left != null || current.right != null);
+ boolean isPrevLastChild = (prev == current.right || (prev == current.left && current.right == null));
+
+ if (!hasChild || isPrevLastChild) {
+ current = stack.pop();
+ visit(current.value);
+ prev = current;
+ } else {
+ if (current.right != null) {
+ stack.push(current.right);
+ }
+ if (current.left != null) {
+ stack.push(current.left);
+ }
+ }
+ }
+ }
+
+ private void visit(int value) {
+ System.out.print(" " + value);
+ }
+
+ class Node {
+ int value;
+ Node left;
+ Node right;
+
+ Node(int value) {
+ this.value = value;
+ right = null;
+ left = null;
+ }
+ }
+}
diff --git a/data-structures/src/main/java/com/baeldung/graph/Graph.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java
similarity index 98%
rename from data-structures/src/main/java/com/baeldung/graph/Graph.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java
index 40df2c713a..d2cc723cf9 100644
--- a/data-structures/src/main/java/com/baeldung/graph/Graph.java
+++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java
@@ -1,4 +1,4 @@
-package com.baeldung.graph;
+package com.baeldung.algorithms.dfs;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/MonteCarloTreeSearch.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/State.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/montecarlo/UCT.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Board.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tictactoe/Position.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Node.java
diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/mcts/tree/Tree.java
diff --git a/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java
old mode 100755
new mode 100644
similarity index 94%
rename from algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java
rename to algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java
index 45ac53e039..16b45ed886
--- a/algorithms-miscellaneous-4/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java
+++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithms.java
@@ -1,194 +1,194 @@
-package com.baeldung.algorithms.string.search;
-
-import java.math.BigInteger;
-import java.util.Random;
-
-public class StringSearchAlgorithms {
- public static long getBiggerPrime(int m) {
- BigInteger prime = BigInteger.probablePrime(getNumberOfBits(m) + 1, new Random());
- return prime.longValue();
- }
-
- public static long getLowerPrime(long number) {
- BigInteger prime = BigInteger.probablePrime(getNumberOfBits(number) - 1, new Random());
- return prime.longValue();
- }
-
- private static int getNumberOfBits(final int number) {
- return Integer.SIZE - Integer.numberOfLeadingZeros(number);
- }
-
- private static int getNumberOfBits(final long number) {
- return Long.SIZE - Long.numberOfLeadingZeros(number);
- }
-
- public static int simpleTextSearch(char[] pattern, char[] text) {
- int patternSize = pattern.length;
- int textSize = text.length;
-
- int i = 0;
-
- while ((i + patternSize) <= textSize) {
- int j = 0;
- while (text[i + j] == pattern[j]) {
- j += 1;
- if (j >= patternSize)
- return i;
- }
- i += 1;
- }
-
- return -1;
- }
-
- public static int RabinKarpMethod(char[] pattern, char[] text) {
- int patternSize = pattern.length; // m
- int textSize = text.length; // n
-
- long prime = getBiggerPrime(patternSize);
-
- long r = 1;
- for (int i = 0; i < patternSize - 1; i++) {
- r *= 2;
- r = r % prime;
- }
-
- long[] t = new long[textSize];
- t[0] = 0;
-
- long pfinger = 0;
-
- for (int j = 0; j < patternSize; j++) {
- t[0] = (2 * t[0] + text[j]) % prime;
- pfinger = (2 * pfinger + pattern[j]) % prime;
- }
-
- int i = 0;
- boolean passed = false;
-
- int diff = textSize - patternSize;
- for (i = 0; i <= diff; i++) {
- if (t[i] == pfinger) {
- passed = true;
- for (int k = 0; k < patternSize; k++) {
- if (text[i + k] != pattern[k]) {
- passed = false;
- break;
- }
- }
-
- if (passed) {
- return i;
- }
- }
-
- if (i < diff) {
- long value = 2 * (t[i] - r * text[i]) + text[i + patternSize];
- t[i + 1] = ((value % prime) + prime) % prime;
- }
- }
- return -1;
-
- }
-
- public static int KnuthMorrisPrattSearch(char[] pattern, char[] text) {
- int patternSize = pattern.length; // m
- int textSize = text.length; // n
-
- int i = 0, j = 0;
-
- int[] shift = KnuthMorrisPrattShift(pattern);
-
- while ((i + patternSize) <= textSize) {
- while (text[i + j] == pattern[j]) {
- j += 1;
- if (j >= patternSize)
- return i;
- }
-
- if (j > 0) {
- i += shift[j - 1];
- j = Math.max(j - shift[j - 1], 0);
- } else {
- i++;
- j = 0;
- }
- }
- return -1;
- }
-
- public static int[] KnuthMorrisPrattShift(char[] pattern) {
- int patternSize = pattern.length;
-
- int[] shift = new int[patternSize];
- shift[0] = 1;
-
- int i = 1, j = 0;
-
- while ((i + j) < patternSize) {
- if (pattern[i + j] == pattern[j]) {
- shift[i + j] = i;
- j++;
- } else {
- if (j == 0)
- shift[i] = i + 1;
-
- if (j > 0) {
- i = i + shift[j - 1];
- j = Math.max(j - shift[j - 1], 0);
- } else {
- i = i + 1;
- j = 0;
- }
- }
- }
- return shift;
- }
-
- public static int BoyerMooreHorspoolSimpleSearch(char[] pattern, char[] text) {
- int patternSize = pattern.length;
- int textSize = text.length;
-
- int i = 0, j = 0;
-
- while ((i + patternSize) <= textSize) {
- j = patternSize - 1;
- while (text[i + j] == pattern[j]) {
- j--;
- if (j < 0)
- return i;
- }
- i++;
- }
- return -1;
- }
-
- public static int BoyerMooreHorspoolSearch(char[] pattern, char[] text) {
-
- int shift[] = new int[256];
-
- for (int k = 0; k < 256; k++) {
- shift[k] = pattern.length;
- }
-
- for (int k = 0; k < pattern.length - 1; k++) {
- shift[pattern[k]] = pattern.length - 1 - k;
- }
-
- int i = 0, j = 0;
-
- while ((i + pattern.length) <= text.length) {
- j = pattern.length - 1;
-
- while (text[i + j] == pattern[j]) {
- j -= 1;
- if (j < 0)
- return i;
- }
-
- i = i + shift[text[i + pattern.length - 1]];
-
- }
- return -1;
- }
-}
+package com.baeldung.algorithms.textsearch;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+public class TextSearchAlgorithms {
+ public static long getBiggerPrime(int m) {
+ BigInteger prime = BigInteger.probablePrime(getNumberOfBits(m) + 1, new Random());
+ return prime.longValue();
+ }
+
+ public static long getLowerPrime(long number) {
+ BigInteger prime = BigInteger.probablePrime(getNumberOfBits(number) - 1, new Random());
+ return prime.longValue();
+ }
+
+ private static int getNumberOfBits(final int number) {
+ return Integer.SIZE - Integer.numberOfLeadingZeros(number);
+ }
+
+ private static int getNumberOfBits(final long number) {
+ return Long.SIZE - Long.numberOfLeadingZeros(number);
+ }
+
+ public static int simpleTextSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length;
+ int textSize = text.length;
+
+ int i = 0;
+
+ while ((i + patternSize) <= textSize) {
+ int j = 0;
+ while (text[i + j] == pattern[j]) {
+ j += 1;
+ if (j >= patternSize)
+ return i;
+ }
+ i += 1;
+ }
+
+ return -1;
+ }
+
+ public static int RabinKarpMethod(char[] pattern, char[] text) {
+ int patternSize = pattern.length; // m
+ int textSize = text.length; // n
+
+ long prime = getBiggerPrime(patternSize);
+
+ long r = 1;
+ for (int i = 0; i < patternSize - 1; i++) {
+ r *= 2;
+ r = r % prime;
+ }
+
+ long[] t = new long[textSize];
+ t[0] = 0;
+
+ long pfinger = 0;
+
+ for (int j = 0; j < patternSize; j++) {
+ t[0] = (2 * t[0] + text[j]) % prime;
+ pfinger = (2 * pfinger + pattern[j]) % prime;
+ }
+
+ int i = 0;
+ boolean passed = false;
+
+ int diff = textSize - patternSize;
+ for (i = 0; i <= diff; i++) {
+ if (t[i] == pfinger) {
+ passed = true;
+ for (int k = 0; k < patternSize; k++) {
+ if (text[i + k] != pattern[k]) {
+ passed = false;
+ break;
+ }
+ }
+
+ if (passed) {
+ return i;
+ }
+ }
+
+ if (i < diff) {
+ long value = 2 * (t[i] - r * text[i]) + text[i + patternSize];
+ t[i + 1] = ((value % prime) + prime) % prime;
+ }
+ }
+ return -1;
+
+ }
+
+ public static int KnuthMorrisPrattSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length; // m
+ int textSize = text.length; // n
+
+ int i = 0, j = 0;
+
+ int[] shift = KnuthMorrisPrattShift(pattern);
+
+ while ((i + patternSize) <= textSize) {
+ while (text[i + j] == pattern[j]) {
+ j += 1;
+ if (j >= patternSize)
+ return i;
+ }
+
+ if (j > 0) {
+ i += shift[j - 1];
+ j = Math.max(j - shift[j - 1], 0);
+ } else {
+ i++;
+ j = 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int[] KnuthMorrisPrattShift(char[] pattern) {
+ int patternSize = pattern.length;
+
+ int[] shift = new int[patternSize];
+ shift[0] = 1;
+
+ int i = 1, j = 0;
+
+ while ((i + j) < patternSize) {
+ if (pattern[i + j] == pattern[j]) {
+ shift[i + j] = i;
+ j++;
+ } else {
+ if (j == 0)
+ shift[i] = i + 1;
+
+ if (j > 0) {
+ i = i + shift[j - 1];
+ j = Math.max(j - shift[j - 1], 0);
+ } else {
+ i = i + 1;
+ j = 0;
+ }
+ }
+ }
+ return shift;
+ }
+
+ public static int BoyerMooreHorspoolSimpleSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length;
+ int textSize = text.length;
+
+ int i = 0, j = 0;
+
+ while ((i + patternSize) <= textSize) {
+ j = patternSize - 1;
+ while (text[i + j] == pattern[j]) {
+ j--;
+ if (j < 0)
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ public static int BoyerMooreHorspoolSearch(char[] pattern, char[] text) {
+
+ int shift[] = new int[256];
+
+ for (int k = 0; k < 256; k++) {
+ shift[k] = pattern.length;
+ }
+
+ for (int k = 0; k < pattern.length - 1; k++) {
+ shift[pattern[k]] = pattern.length - 1 - k;
+ }
+
+ int i = 0, j = 0;
+
+ while ((i + pattern.length) <= text.length) {
+ j = pattern.length - 1;
+
+ while (text[i + j] == pattern[j]) {
+ j -= 1;
+ if (j < 0)
+ return i;
+ }
+
+ i = i + shift[text[i + pattern.length - 1]];
+
+ }
+ return -1;
+ }
+}
diff --git a/algorithms-searching/src/main/resources/logback.xml b/algorithms-searching/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/algorithms-searching/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java
similarity index 94%
rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java
rename to algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java
index 826682d373..eb3fb4f718 100644
--- a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java
+++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java
@@ -1,43 +1,41 @@
-package com.baeldung.algorithms.binarysearch;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Assert;
-import org.junit.Test;
-import com.baeldung.algorithms.binarysearch.BinarySearch;
-
-public class BinarySearchUnitTest {
-
- int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 };
- int key = 6;
- int expectedIndexForSearchKey = 7;
- int low = 0;
- int high = sortedArray.length - 1;
- List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9);
-
- @Test
- public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() {
- BinarySearch binSearch = new BinarySearch();
- Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high));
- }
-
- @Test
- public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() {
- BinarySearch binSearch = new BinarySearch();
- Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high));
- }
-
- @Test
- public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
- BinarySearch binSearch = new BinarySearch();
- Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key));
- }
-
- @Test
- public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
- BinarySearch binSearch = new BinarySearch();
- Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key));
- }
-
-}
+package com.baeldung.algorithms.binarysearch;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BinarySearchUnitTest {
+
+ int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 };
+ int key = 6;
+ int expectedIndexForSearchKey = 7;
+ int low = 0;
+ int high = sortedArray.length - 1;
+ List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9);
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high));
+ }
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high));
+ }
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key));
+ }
+
+ @Test
+ public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key));
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java
rename to algorithms-searching/src/test/java/com/baeldung/algorithms/breadthfirstsearch/BreadthFirstSearchAlgorithmUnitTest.java
diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java
new file mode 100644
index 0000000000..076da14f81
--- /dev/null
+++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java
@@ -0,0 +1,136 @@
+package com.baeldung.algorithms.dfs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class BinaryTreeUnitTest {
+
+ @Test
+ public void givenABinaryTree_WhenAddingElements_ThenTreeNotEmpty() {
+
+ BinaryTree bt = createBinaryTree();
+
+ assertTrue(!bt.isEmpty());
+ }
+
+ @Test
+ public void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() {
+
+ BinaryTree bt = createBinaryTree();
+
+ assertTrue(bt.containsNode(6));
+ assertTrue(bt.containsNode(4));
+
+ assertFalse(bt.containsNode(1));
+ }
+
+ @Test
+ public void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() {
+
+ BinaryTree bt = createBinaryTree();
+
+ int initialSize = bt.getSize();
+
+ assertTrue(bt.containsNode(3));
+ bt.add(3);
+ assertEquals(initialSize, bt.getSize());
+ }
+
+ @Test
+ public void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() {
+
+ BinaryTree bt = createBinaryTree();
+
+ assertFalse(bt.containsNode(99));
+ }
+
+ @Test
+ public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() {
+
+ BinaryTree bt = createBinaryTree();
+
+ assertTrue(bt.containsNode(9));
+ bt.delete(9);
+ assertFalse(bt.containsNode(9));
+ }
+
+ @Test
+ public void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() {
+
+ BinaryTree bt = createBinaryTree();
+
+ int initialSize = bt.getSize();
+
+ assertFalse(bt.containsNode(99));
+ bt.delete(99);
+ assertFalse(bt.containsNode(99));
+ assertEquals(initialSize, bt.getSize());
+ }
+
+ @Test
+ public void it_deletes_the_root() {
+ int value = 12;
+ BinaryTree bt = new BinaryTree();
+ bt.add(value);
+
+ assertTrue(bt.containsNode(value));
+ bt.delete(value);
+ assertFalse(bt.containsNode(value));
+ }
+
+ @Test
+ public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() {
+
+ BinaryTree bt = createBinaryTree();
+
+ bt.traverseInOrder(bt.root);
+ System.out.println();
+ bt.traverseInOrderWithoutRecursion();
+ }
+
+ @Test
+ public void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() {
+
+ BinaryTree bt = createBinaryTree();
+
+ bt.traversePreOrder(bt.root);
+ System.out.println();
+ bt.traversePreOrderWithoutRecursion();
+ }
+
+ @Test
+ public void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() {
+
+ BinaryTree bt = createBinaryTree();
+
+ bt.traversePostOrder(bt.root);
+ System.out.println();
+ bt.traversePostOrderWithoutRecursion();
+ }
+
+ @Test
+ public void givenABinaryTree_WhenTraversingLevelOrder_ThenPrintValues() {
+
+ BinaryTree bt = createBinaryTree();
+
+ bt.traverseLevelOrder();
+ }
+
+ private BinaryTree createBinaryTree() {
+ BinaryTree bt = new BinaryTree();
+
+ bt.add(6);
+ bt.add(4);
+ bt.add(8);
+ bt.add(3);
+ bt.add(5);
+ bt.add(7);
+ bt.add(9);
+
+ return bt;
+ }
+
+}
diff --git a/data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java
similarity index 92%
rename from data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java
rename to algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java
index 09b92115d2..715bb55fcb 100644
--- a/data-structures/src/test/java/com/baeldung/graph/GraphUnitTest.java
+++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java
@@ -1,7 +1,8 @@
-package com.baeldung.graph;
+package com.baeldung.algorithms.dfs;
import java.util.List;
+import com.baeldung.algorithms.dfs.Graph;
import org.junit.Test;
public class GraphUnitTest {
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
similarity index 100%
rename from algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
rename to algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
index 8ad962055e..cabedcefad 100644
--- a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
+++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
@@ -1,10 +1,10 @@
package com.baeldung.algorithms.interpolationsearch;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.junit.Before;
import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
public class InterpolationSearchUnitTest {
private int[] myData;
diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java
similarity index 100%
rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java
rename to algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java
diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java
new file mode 100644
index 0000000000..543ccb912f
--- /dev/null
+++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.algorithms.textsearch;
+
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TextSearchAlgorithmsUnitTest {
+
+
+ @Test
+ public void testStringSearchAlgorithms() {
+ String text = "This is some nice text.";
+ String pattern = "some";
+
+ int realPosition = text.indexOf(pattern);
+ Assert.assertTrue(realPosition == TextSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == TextSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == TextSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray()));
+ }
+
+}
diff --git a/aws/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java b/aws/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java
index 45a107103d..cfc9f87a60 100644
--- a/aws/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java
+++ b/aws/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java
@@ -15,7 +15,7 @@ public class LocalDbCreationRule extends ExternalResource {
@Override
protected void before() throws Exception {
String port = "8000";
- this.server = ServerRunner.createServerFromCommandLineArgs(new String[]{"-inMemory", "-port", port});
+ this.server = ServerRunner.createServerFromCommandLineArgs(new String[]{"-inMemory","-sharedDb" ,"-port", port});
server.start();
}
diff --git a/code-generation/README.md b/code-generation/README.md
index 289a336f99..d45a113a8f 100644
--- a/code-generation/README.md
+++ b/code-generation/README.md
@@ -7,3 +7,4 @@ This module contains articles about automatic code generation
- [Introduction to AutoValue](https://www.baeldung.com/introduction-to-autovalue)
- [Introduction to AutoFactory](https://www.baeldung.com/autofactory)
- [Google AutoService](https://www.baeldung.com/google-autoservice)
+- [Defensive Copies for Collections Using AutoValue](https://www.baeldung.com/autovalue-defensive-copies)
diff --git a/core-java-modules/core-java-collections-list-3/README.md b/core-java-modules/core-java-collections-list-3/README.md
index 3d4004de6f..65c377bd99 100644
--- a/core-java-modules/core-java-collections-list-3/README.md
+++ b/core-java-modules/core-java-collections-list-3/README.md
@@ -9,4 +9,5 @@ This module contains articles about the Java List collection
- [List of Primitive Integer Values in Java](https://www.baeldung.com/java-list-primitive-int)
- [Performance Comparison of Primitive Lists in Java](https://www.baeldung.com/java-list-primitive-performance)
- [Filtering a Java Collection by a List](https://www.baeldung.com/java-filter-collection-by-list)
+- [How to Count Duplicate Elements in Arraylist](https://www.baeldung.com/java-count-duplicate-elements-arraylist)
- [[<-- Prev]](/core-java-modules/core-java-collections-list-2)
diff --git a/core-java-modules/core-java-concurrency-advanced-3/pom.xml b/core-java-modules/core-java-concurrency-advanced-3/pom.xml
index cc7b7b1e70..5858232001 100644
--- a/core-java-modules/core-java-concurrency-advanced-3/pom.xml
+++ b/core-java-modules/core-java-concurrency-advanced-3/pom.xml
@@ -14,11 +14,18 @@
../../parent-java
-
-
-
core-java-concurrency-advanced-3
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ ${maven.compiler.target}
+
+
+
src/main/resources
@@ -28,6 +35,8 @@
+ 1.8
+ 1.8
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java
new file mode 100644
index 0000000000..cd68bf0709
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java
@@ -0,0 +1,53 @@
+package com.baeldung.commonissues;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class CollectionsConcurrencyIssues {
+
+ private void putIfAbsentList_NonAtomicOperation_ProneToConcurrencyIssues() {
+ List list = Collections.synchronizedList(new ArrayList<>());
+ if (!list.contains("foo")) {
+ list.add("foo");
+ }
+ }
+
+ private void putIfAbsentList_AtomicOperation_ThreadSafe() {
+ List list = Collections.synchronizedList(new ArrayList<>());
+ synchronized (list) {
+ if (!list.contains("foo")) {
+ list.add("foo");
+ }
+ }
+ }
+
+ private void putIfAbsentMap_NonAtomicOperation_ProneToConcurrencyIssues() {
+ Map map = new ConcurrentHashMap<>();
+ if (!map.containsKey("foo")) {
+ map.put("foo", "bar");
+ }
+ }
+
+ private void putIfAbsentMap_AtomicOperation_BetterApproach() {
+ Map map = new ConcurrentHashMap<>();
+ synchronized (map) {
+ if (!map.containsKey("foo")) {
+ map.put("foo", "bar");
+ }
+ }
+ }
+
+ private void putIfAbsentMap_AtomicOperation_BestApproach() {
+ Map map = new ConcurrentHashMap<>();
+ map.putIfAbsent("foo", "bar");
+ }
+
+ private void computeIfAbsentMap_AtomicOperation() {
+ Map map = new ConcurrentHashMap<>();
+ map.computeIfAbsent("foo", key -> key + "bar");
+ }
+
+}
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java
new file mode 100644
index 0000000000..53892b9ad6
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java
@@ -0,0 +1,13 @@
+package com.baeldung.commonissues;
+
+class Counter {
+ private int counter = 0;
+
+ public void increment() {
+ counter++;
+ }
+
+ public int getValue() {
+ return counter;
+ }
+}
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java
new file mode 100644
index 0000000000..b7b65d1197
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java
@@ -0,0 +1,42 @@
+package com.baeldung.commonissues;
+
+public class DeadlockExample {
+
+ public static Object lock1 = new Object();
+ public static Object lock2 = new Object();
+
+ public static void main(String args[]) {
+ Thread threadA = new Thread(() -> {
+ synchronized (lock1) {
+ System.out.println("ThreadA: Holding lock 1...");
+ sleep();
+ System.out.println("ThreadA: Waiting for lock 2...");
+
+ synchronized (lock2) {
+ System.out.println("ThreadA: Holding lock 1 & 2...");
+ }
+ }
+ });
+ Thread threadB = new Thread(() -> {
+ synchronized (lock2) {
+ System.out.println("ThreadB: Holding lock 2...");
+ sleep();
+ System.out.println("ThreadB: Waiting for lock 1...");
+
+ synchronized (lock1) {
+ System.out.println("ThreadB: Holding lock 1 & 2...");
+ }
+ }
+ });
+ threadA.start();
+ threadB.start();
+ }
+
+ private static void sleep() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ throw new RuntimeException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java
new file mode 100644
index 0000000000..feb2322569
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java
@@ -0,0 +1,35 @@
+package com.baeldung.commonissues;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class SimpleDateFormatThreadUnsafetyExample {
+
+ private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
+ public static void main(String[] args) {
+ String dateStr = "2019-10-29T11:12:21";
+
+ ExecutorService executorService = Executors.newFixedThreadPool(10);
+
+ for (int i = 0; i < 20; i++) {
+ executorService.submit(() -> parseDate(dateStr));
+ }
+
+ executorService.shutdown();
+ }
+
+ private static void parseDate(String dateStr) {
+ try {
+ Date date = simpleDateFormat.parse(dateStr);
+ System.out.println("Successfully Parsed Date " + date);
+ } catch (ParseException e) {
+ System.out.println("ParseError " + e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java
new file mode 100644
index 0000000000..7054db6356
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java
@@ -0,0 +1,13 @@
+package com.baeldung.commonissues;
+
+class SynchronizedCounter {
+ private int counter = 0;
+
+ public synchronized void increment() {
+ counter++;
+ }
+
+ public synchronized int getValue() {
+ return counter;
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java
new file mode 100644
index 0000000000..5434365ca9
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java
@@ -0,0 +1,13 @@
+package com.baeldung.commonissues;
+
+class SynchronizedVolatileCounter {
+ private volatile int counter = 0;
+
+ public synchronized void increment() {
+ counter++;
+ }
+
+ public int getValue() {
+ return counter;
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-date-operations/README.md b/core-java-modules/core-java-date-operations/README.md
new file mode 100644
index 0000000000..98616a32c3
--- /dev/null
+++ b/core-java-modules/core-java-date-operations/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+- [Get the Current Date Prior to Java 8](https://www.baeldung.com/java-get-the-current-date-legacy)
+- [Skipping Weekends While Adding Days to LocalDate in Java 8](https://www.baeldung.com/java-localdate-add-days-skip-weekends)
diff --git a/core-java-modules/core-java-datetime-java8/README.md b/core-java-modules/core-java-datetime-java8/README.md
index 044f6f3fe3..dfbe9c997f 100644
--- a/core-java-modules/core-java-datetime-java8/README.md
+++ b/core-java-modules/core-java-datetime-java8/README.md
@@ -13,3 +13,4 @@ This module contains articles about the Date and Time API introduced with Java 8
- [How to Get the Start and the End of a Day using Java](http://www.baeldung.com/java-day-start-end)
- [Set the Time Zone of a Date in Java](https://www.baeldung.com/java-set-date-time-zone)
- [Comparing Dates in Java](https://www.baeldung.com/java-comparing-dates)
+- [Generating Random Dates in Java](https://www.baeldung.com/java-random-dates)
diff --git a/core-java-modules/core-java-exceptions/README.md b/core-java-modules/core-java-exceptions/README.md
index f7b0c37e73..429474003c 100644
--- a/core-java-modules/core-java-exceptions/README.md
+++ b/core-java-modules/core-java-exceptions/README.md
@@ -17,3 +17,4 @@ This module contains articles about core java exceptions
- [Common Java Exceptions](https://www.baeldung.com/java-common-exceptions)
- [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception)
- [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause)
+- [Is It a Bad Practice to Catch Throwable?](https://www.baeldung.com/java-catch-throwable-bad-practice)
diff --git a/core-java-modules/core-java-lang-2/README.md b/core-java-modules/core-java-lang-2/README.md
index ee57ec6198..5d51f3cea4 100644
--- a/core-java-modules/core-java-lang-2/README.md
+++ b/core-java-modules/core-java-lang-2/README.md
@@ -5,4 +5,5 @@ This module contains articles about core features in the Java language
### Relevant Articles:
- [Java Primitives versus Objects](https://www.baeldung.com/java-primitives-vs-objects)
- [Command-Line Arguments in Java](https://www.baeldung.com/java-command-line-arguments)
+- [What is a POJO Class?](https://www.baeldung.com/java-pojo-class)
- [[<-- Prev]](/core-java-modules/core-java-lang)
diff --git a/core-java-modules/core-java-lang-math/README.md b/core-java-modules/core-java-lang-math/README.md
index b316ed1cfb..aec339574b 100644
--- a/core-java-modules/core-java-lang-math/README.md
+++ b/core-java-modules/core-java-lang-math/README.md
@@ -6,3 +6,4 @@
- [Java 8 Math New Methods](https://www.baeldung.com/java-8-math)
- [Java 8 Unsigned Arithmetic Support](https://www.baeldung.com/java-unsigned-arithmetic)
- [How to Separate Double into Integer and Decimal Parts](https://www.baeldung.com/java-separate-double-into-integer-decimal-parts)
+- [The strictfp Keyword in Java](https://www.baeldung.com/java-strictfp)
diff --git a/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorIfElse.java b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorIfElse.java
new file mode 100644
index 0000000000..87f274db51
--- /dev/null
+++ b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorIfElse.java
@@ -0,0 +1,50 @@
+package com.baeldung.calculator.basic;
+
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+public class BasicCalculatorIfElse {
+
+ public static void main(String[] args) {
+
+ System.out.println("---------------------------------- \n" + "Welcome to Basic Calculator \n" + "----------------------------------");
+ System.out.println("Following operations are supported : \n" + "1. Addition (+) \n" + "2. Subtraction (-) \n" + "3. Multiplication (* OR x) \n" + "4. Division (/) \n");
+
+ Scanner scanner = new Scanner(System.in);
+ try {
+ System.out.println("Enter an operator: (+ OR - OR * OR /) ");
+ char operation = scanner.next()
+ .charAt(0);
+
+ if (!(operation == '+' || operation == '-' || operation == '*' || operation == 'x' || operation == '/')) {
+ System.err.println("Invalid Operator. Please use only + or - or * or /");
+ }
+
+ System.out.println("Enter First Number: ");
+ double num1 = scanner.nextDouble();
+
+ System.out.println("Enter Second Number: ");
+ double num2 = scanner.nextDouble();
+
+ if (operation == '/' && num2 == 0.0) {
+ System.err.println("Second Number cannot be zero for Division operation.");
+ }
+
+ if (operation == '+') {
+ System.out.println(num1 + " + " + num2 + " = " + (num1 + num2));
+ } else if (operation == '-') {
+ System.out.println(num1 + " - " + num2 + " = " + (num1 - num2));
+ } else if (operation == '*' || operation == 'x') {
+ System.out.println(num1 + " x " + num2 + " = " + (num1 * num2));
+ } else if (operation == '/') {
+ System.out.println(num1 + " / " + num2 + " = " + (num1 / num2));
+ } else {
+ System.err.println("Invalid Operator Specified.");
+ }
+ } catch (InputMismatchException exc) {
+ System.err.println(exc.getMessage());
+ } finally {
+ scanner.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorSwitchCase.java b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorSwitchCase.java
new file mode 100644
index 0000000000..82c181a0fe
--- /dev/null
+++ b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/calculator/basic/BasicCalculatorSwitchCase.java
@@ -0,0 +1,58 @@
+package com.baeldung.calculator.basic;
+
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+public class BasicCalculatorSwitchCase {
+ public static void main(String[] args) {
+
+ System.out.println("---------------------------------- \n" + "Welcome to Basic Calculator \n" + "----------------------------------");
+ System.out.println("Following operations are supported : \n" + "1. Addition (+) \n" + "2. Subtraction (-) \n" + "3. Multiplication (* OR x) \n" + "4. Division (/) \n");
+
+ Scanner scanner = new Scanner(System.in);
+ try {
+ System.out.println("Enter an operator: (+ OR - OR * OR /) ");
+ char operation = scanner.next()
+ .charAt(0);
+
+ if (!(operation == '+' || operation == '-' || operation == '*' || operation == 'x' || operation == '/')) {
+ System.err.println("Invalid Operator. Please use only + or - or * or /");
+ }
+
+ System.out.println("Enter First Number: ");
+ double num1 = scanner.nextDouble();
+
+ System.out.println("Enter Second Number: ");
+ double num2 = scanner.nextDouble();
+
+ if (operation == '/' && num2 == 0.0) {
+ System.err.println("Second Number cannot be zero for Division operation.");
+ }
+
+ switch (operation) {
+ case '+':
+ System.out.println(num1 + " + " + num2 + " = " + (num1 + num2));
+ break;
+ case '-':
+ System.out.println(num1 + " - " + num2 + " = " + (num1 - num2));
+ break;
+ case '*':
+ System.out.println(num1 + " x " + num2 + " = " + (num1 * num2));
+ break;
+ case 'x':
+ System.out.println(num1 + " x " + num2 + " = " + (num1 * num2));
+ break;
+ case '/':
+ System.out.println(num1 + " / " + num2 + " = " + (num1 / num2));
+ break;
+ default:
+ System.err.println("Invalid Operator Specified.");
+ break;
+ }
+ } catch (InputMismatchException exc) {
+ System.err.println(exc.getMessage());
+ } finally {
+ scanner.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/overflow/Overflow.java b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/overflow/Overflow.java
new file mode 100644
index 0000000000..e08d6f60b7
--- /dev/null
+++ b/core-java-modules/core-java-lang-math/src/main/java/com/baeldung/overflow/Overflow.java
@@ -0,0 +1,70 @@
+package com.baeldung.overflow;
+
+import java.math.BigInteger;
+
+public class Overflow {
+
+ public static void showIntegerOverflow() {
+
+ int value = Integer.MAX_VALUE-1;
+
+ for(int i = 0; i < 4; i++, value++) {
+ System.out.println(value);
+ }
+ }
+
+ public static void noOverflowWithBigInteger() {
+
+ BigInteger largeValue = new BigInteger(Integer.MAX_VALUE + "");
+ for(int i = 0; i < 4; i++) {
+ System.out.println(largeValue);
+ largeValue = largeValue.add(BigInteger.ONE);
+ }
+ }
+
+ public static void exceptionWithAddExact() {
+
+ int value = Integer.MAX_VALUE-1;
+ for(int i = 0; i < 4; i++) {
+ System.out.println(value);
+ value = Math.addExact(value, 1);
+ }
+ }
+
+ public static int addExact(int x, int y) {
+
+ int r = x + y;
+ if (((x ^ r) & (y ^ r)) < 0) {
+ throw new ArithmeticException("int overflow");
+ }
+ return r;
+ }
+
+ public static void demonstrateUnderflow() {
+
+ for(int i = 1073; i <= 1076; i++) {
+ System.out.println("2^" + i + " = " + Math.pow(2, -i));
+ }
+ }
+
+ public static double powExact(double base, double exponent)
+ {
+ if(base == 0.0) {
+ return 0.0;
+ }
+
+ double result = Math.pow(base, exponent);
+
+ if(result == Double.POSITIVE_INFINITY ) {
+ throw new ArithmeticException("Double overflow resulting in POSITIVE_INFINITY");
+ } else if(result == Double.NEGATIVE_INFINITY) {
+ throw new ArithmeticException("Double overflow resulting in NEGATIVE_INFINITY");
+ } else if(Double.compare(-0.0f, result) == 0) {
+ throw new ArithmeticException("Double overflow resulting in negative zero");
+ } else if(Double.compare(+0.0f, result) == 0) {
+ throw new ArithmeticException("Double overflow resulting in positive zero");
+ }
+
+ return result;
+ }
+}
diff --git a/core-java-modules/core-java-lang-math/src/test/java/com/baeldung/math/OverflowUnitTest.java b/core-java-modules/core-java-lang-math/src/test/java/com/baeldung/math/OverflowUnitTest.java
new file mode 100644
index 0000000000..4b213eba13
--- /dev/null
+++ b/core-java-modules/core-java-lang-math/src/test/java/com/baeldung/math/OverflowUnitTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.math;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class OverflowUnitTest {
+
+ @Test
+ public void positive_and_negative_zero_are_not_always_equal() {
+
+ double a = +0f;
+ double b = -0f;
+
+ assertTrue(a == b);
+
+ assertTrue(1/a == Double.POSITIVE_INFINITY);
+ assertTrue(1/b == Double.NEGATIVE_INFINITY);
+
+ assertTrue(1/a != 1/b);
+ }
+}
diff --git a/core-java-modules/core-java-streams-3/README.md b/core-java-modules/core-java-streams-3/README.md
index 4b2c9ed94c..a739245399 100644
--- a/core-java-modules/core-java-streams-3/README.md
+++ b/core-java-modules/core-java-streams-3/README.md
@@ -8,4 +8,5 @@ This module contains articles about the Stream API in Java.
- [The Difference Between Collection.stream().forEach() and Collection.forEach()](https://www.baeldung.com/java-collection-stream-foreach)
- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors)
- [Primitive Type Streams in Java 8](https://www.baeldung.com/java-8-primitive-streams)
-- More articles: [[<-- prev>]](/../core-java-streams-2)
\ No newline at end of file
+- [Debugging Java 8 Streams with IntelliJ](https://www.baeldung.com/intellij-debugging-java-streams)
+- More articles: [[<-- prev>]](/../core-java-streams-2)
diff --git a/core-java-modules/core-java-string-operations/pom.xml b/core-java-modules/core-java-string-operations/pom.xml
index fdddd99433..ebbbade7a4 100644
--- a/core-java-modules/core-java-string-operations/pom.xml
+++ b/core-java-modules/core-java-string-operations/pom.xml
@@ -58,7 +58,7 @@
- 3.8.1
+ 3.9
3.6.1
1.10
diff --git a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/Benchmarking.java b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/Benchmarking.java
index 97e7a46757..847b587cdc 100644
--- a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/Benchmarking.java
+++ b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/Benchmarking.java
@@ -1,6 +1,9 @@
package com.baeldung.isnumeric;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
@@ -14,6 +17,8 @@ import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
public class Benchmarking {
+ private static final TestMode MODE = TestMode.DIVERS;
+
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(Benchmarking.class.getSimpleName())
.forks(1)
@@ -22,52 +27,89 @@ public class Benchmarking {
new Runner(opt).run();
}
+ private static final IsNumeric subject = new IsNumeric();
+
@State(Scope.Thread)
public static class ExecutionPlan {
- public String number = Integer.toString(Integer.MAX_VALUE);
- public boolean isNumber = false;
- public IsNumeric isNumeric = new IsNumeric();
+ private final Map testPlan = testPlan();
+
+ void validate(Function functionUnderTest) {
+ testPlan.forEach((key, value) -> {
+ Boolean result = functionUnderTest.apply(key);
+
+ assertEquals(value, result, key);
+ });
+ }
+
+ private void assertEquals(Boolean expectedResult, Boolean result, String input) {
+ if (result != expectedResult) {
+ throw new IllegalStateException("The output does not match the expected output, for input: " + input);
+ }
+ }
+
+ private Map testPlan() {
+ HashMap plan = new HashMap<>();
+ plan.put(Integer.toString(Integer.MAX_VALUE), true);
+
+ if (MODE == TestMode.SIMPLE) {
+ return plan;
+ }
+
+ plan.put("x0", false);
+ plan.put("0..005", false);
+ plan.put("--11", false);
+ plan.put("test", false);
+ plan.put(null, false);
+ for (int i = 0; i < 94; i++) {
+ plan.put(Integer.toString(i), true);
+ }
+ return plan;
+ }
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingCoreJava(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingCoreJava(plan.number);
+ plan.validate(subject::usingCoreJava);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingRegularExpressions(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingRegularExpressions(plan.number);
+ plan.validate(subject::usingPreCompiledRegularExpressions);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingNumberUtils_isCreatable(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingNumberUtils_isCreatable(plan.number);
+ plan.validate(subject::usingNumberUtils_isCreatable);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingNumberUtils_isParsable(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingNumberUtils_isParsable(plan.number);
+ plan.validate(subject::usingNumberUtils_isParsable);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingStringUtils_isNumeric(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingStringUtils_isNumeric(plan.number);
+ plan.validate(subject::usingStringUtils_isNumeric);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void usingStringUtils_isNumericSpace(ExecutionPlan plan) {
- plan.isNumber = plan.isNumeric.usingStringUtils_isNumericSpace(plan.number);
+ plan.validate(subject::usingStringUtils_isNumericSpace);
+ }
+
+ private enum TestMode {
+ SIMPLE, DIVERS
}
}
\ No newline at end of file
diff --git a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/CheckIntegerInput.java b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/CheckIntegerInput.java
deleted file mode 100644
index 6c08615c74..0000000000
--- a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/CheckIntegerInput.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.baeldung.isnumeric;
-
-import java.util.Scanner;
-
-public class CheckIntegerInput {
-
- public static void main(String[] args) {
- try (Scanner scanner = new Scanner(System.in)) {
- System.out.println("Enter an integer : ");
-
- if (scanner.hasNextInt()) {
- System.out.println("You entered : " + scanner.nextInt());
- } else {
- System.out.println("The input is not an integer");
- }
- }
- }
-}
\ No newline at end of file
diff --git a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumeric.java b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumeric.java
index 6eed0d777d..4cfaf384c2 100644
--- a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumeric.java
+++ b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumeric.java
@@ -1,20 +1,33 @@
package com.baeldung.isnumeric;
+import java.util.regex.Pattern;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
public class IsNumeric {
+ private final Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?");
+
public boolean usingCoreJava(String strNum) {
+ if (strNum == null) {
+ return false;
+ }
+
try {
Double.parseDouble(strNum);
- } catch (NumberFormatException | NullPointerException nfe) {
+ } catch (NumberFormatException nfe) {
return false;
}
return true;
}
- public boolean usingRegularExpressions(String strNum) {
- return strNum.matches("-?\\d+(\\.\\d+)?");
+ public boolean usingPreCompiledRegularExpressions(String strNum) {
+ if (strNum == null) {
+ return false;
+ }
+
+ return pattern.matcher(strNum)
+ .matches();
}
public boolean usingNumberUtils_isCreatable(String strNum) {
diff --git a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumericDriver.java b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumericDriver.java
index a6c5449696..f174497323 100644
--- a/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumericDriver.java
+++ b/core-java-modules/core-java-string-operations/src/main/java/com/baeldung/isnumeric/IsNumericDriver.java
@@ -13,8 +13,8 @@ public class IsNumericDriver {
boolean res = isNumeric.usingCoreJava("1001");
LOG.info("Using Core Java : " + res);
- res = isNumeric.usingRegularExpressions("1001");
- LOG.info("Using Regular Expressions : " + res);
+ res = isNumeric.usingPreCompiledRegularExpressions("1001");
+ LOG.info("Using Pre-compiled Regular Expressions : " + res);
res = isNumeric.usingNumberUtils_isCreatable("1001");
LOG.info("Using NumberUtils.isCreatable : " + res);
diff --git a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/CoreJavaIsNumericUnitTest.java b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/CoreJavaIsNumericUnitTest.java
index 6c03b00e69..5159012aff 100644
--- a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/CoreJavaIsNumericUnitTest.java
+++ b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/CoreJavaIsNumericUnitTest.java
@@ -6,9 +6,13 @@ import org.junit.Test;
public class CoreJavaIsNumericUnitTest {
public static boolean isNumeric(String strNum) {
+ if (strNum == null) {
+ return false;
+ }
+
try {
- double d = Double.parseDouble(strNum);
- } catch (NumberFormatException | NullPointerException nfe) {
+ Double.parseDouble(strNum);
+ } catch (NumberFormatException nfe) {
return false;
}
return true;
diff --git a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/RegularExpressionsUnitTest.java b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/RegularExpressionsUnitTest.java
index 04f3de8dc5..48c9825baa 100644
--- a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/RegularExpressionsUnitTest.java
+++ b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/isnumeric/RegularExpressionsUnitTest.java
@@ -2,11 +2,19 @@ package com.baeldung.isnumeric;
import static org.assertj.core.api.Assertions.assertThat;
+import java.util.regex.Pattern;
+
import org.junit.Test;
public class RegularExpressionsUnitTest {
- public static boolean isNumeric(String strNum) {
- return strNum.matches("-?\\d+(\\.\\d+)?");
+ private final Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?");
+
+ public boolean isNumeric(String strNum) {
+ if (strNum == null) {
+ return false;
+ }
+ return pattern.matcher(strNum)
+ .matches();
}
@Test
@@ -17,6 +25,7 @@ public class RegularExpressionsUnitTest {
assertThat(isNumeric("-200")).isTrue();
// Invalid Numbers
+ assertThat(isNumeric(null)).isFalse();
assertThat(isNumeric("abc")).isFalse();
}
}
diff --git a/data-structures/README.md b/data-structures/README.md
index b7f15c2eb8..7eeda7c64f 100644
--- a/data-structures/README.md
+++ b/data-structures/README.md
@@ -6,4 +6,3 @@ This module contains articles about data structures in Java
- [The Trie Data Structure in Java](https://www.baeldung.com/trie-java)
- [Implementing a Binary Tree in Java](https://www.baeldung.com/java-binary-tree)
-- [Depth First Search in Java](https://www.baeldung.com/java-depth-first-search)
diff --git a/jackson-2/pom.xml b/jackson-2/pom.xml
index 2fff1f8706..0d612c175d 100644
--- a/jackson-2/pom.xml
+++ b/jackson-2/pom.xml
@@ -14,14 +14,6 @@
-
-
-
- com.fasterxml.jackson.core
- jackson-databind
- ${jackson.version}
-
-
com.fasterxml.jackson.dataformat
diff --git a/jackson-annotations/README.md b/jackson-annotations/README.md
new file mode 100644
index 0000000000..d979ec0e0e
--- /dev/null
+++ b/jackson-annotations/README.md
@@ -0,0 +1,11 @@
+## Jackson Annotations
+
+This module contains articles about Jackson annotations.
+
+### Relevant Articles:
+- [Guide to @JsonFormat in Jackson](https://www.baeldung.com/jackson-jsonformat)
+- [More Jackson Annotations](https://www.baeldung.com/jackson-advanced-annotations)
+- [Jackson Annotation Examples](https://www.baeldung.com/jackson-annotations)
+- [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion)
+- [Jackson – Change Name of Field](https://www.baeldung.com/jackson-name-of-property)
+- [Jackson Ignore Properties on Marshalling](https://www.baeldung.com/jackson-ignore-properties-on-serialization)
diff --git a/jackson-annotations/pom.xml b/jackson-annotations/pom.xml
new file mode 100644
index 0000000000..b3efc51e62
--- /dev/null
+++ b/jackson-annotations/pom.xml
@@ -0,0 +1,60 @@
+
+ 4.0.0
+ jackson-annotations
+ 0.0.1-SNAPSHOT
+ jackson-annotations
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+ ${jackson.version}
+
+
+ io.rest-assured
+ json-path
+ ${rest-assured.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+
+
+ jackson-annotations
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ 3.11.0
+ 3.1.1
+
+
+
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/AliasBean.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/AliasBean.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/AliasBean.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/AliasBean.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithCreator.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithCreator.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithFilter.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithFilter.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithGetter.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithGetter.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithIgnore.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithIgnore.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithInject.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/BeanWithInject.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/ExtendableBean.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/ExtendableBean.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/MyBean.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/MyBean.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/MyBean.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/MyBean.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/PrivateBean.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/PrivateBean.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/RawBean.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/RawBean.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/RawBean.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/RawBean.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/UnwrappedUser.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/UnwrappedUser.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/Zoo.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/Zoo.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/annotation/Zoo.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/Zoo.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIdentity.java
similarity index 91%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIdentity.java
index 25de4a8f7a..acd68e9e4a 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIdentity.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIgnore.java
similarity index 86%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIgnore.java
index 910ccec174..a71bdd57f8 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithIgnore.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
public class ItemWithIgnore {
public int id;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithRef.java
similarity index 88%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithRef.java
index 0ca8d721e8..3b9bb44c37 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/ItemWithRef.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
import com.fasterxml.jackson.annotation.JsonManagedReference;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIdentity.java
similarity index 93%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIdentity.java
index db83a09389..9703b27f3e 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIdentity.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
import java.util.ArrayList;
import java.util.List;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIgnore.java
similarity index 91%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIgnore.java
index 857a373cc5..19598a4c17 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithIgnore.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
import java.util.ArrayList;
import java.util.List;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithRef.java
similarity index 91%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithRef.java
index 3de03fc651..3d844ea6c0 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/bidirection/UserWithRef.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.bidirection;
+package com.baeldung.jackson.annotation.bidirection;
import java.util.ArrayList;
import java.util.List;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateDeserializer.java
similarity index 95%
rename from jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateDeserializer.java
index 90c7d9fbac..f17c4dc0dd 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateDeserializer.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.date;
+package com.baeldung.jackson.annotation.date;
import java.io.IOException;
import java.text.ParseException;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateSerializer.java
similarity index 95%
rename from jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateSerializer.java
index d840e1940f..1e869d876a 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/CustomDateSerializer.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.date;
+package com.baeldung.jackson.annotation.date;
import java.io.IOException;
import java.text.SimpleDateFormat;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithFormat.java
similarity index 92%
rename from jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithFormat.java
index 607e694cef..423b927976 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithFormat.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.date;
+package com.baeldung.jackson.annotation.date;
import java.util.Date;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithSerializer.java
similarity index 93%
rename from jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithSerializer.java
index c359b5c846..292cb9129d 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/date/EventWithSerializer.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.date;
+package com.baeldung.jackson.annotation.date;
import java.util.Date;
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/deserialization/ItemDeserializerOnClass.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/deserialization/ItemDeserializerOnClass.java
new file mode 100644
index 0000000000..fe86d48f6a
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/deserialization/ItemDeserializerOnClass.java
@@ -0,0 +1,41 @@
+package com.baeldung.jackson.annotation.deserialization;
+
+import java.io.IOException;
+
+import com.baeldung.jackson.annotation.dtos.ItemWithSerializer;
+import com.baeldung.jackson.annotation.dtos.User;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.node.IntNode;
+
+public class ItemDeserializerOnClass extends StdDeserializer {
+
+ private static final long serialVersionUID = 5579141241817332594L;
+
+ public ItemDeserializerOnClass() {
+ this(null);
+ }
+
+ public ItemDeserializerOnClass(final Class> vc) {
+ super(vc);
+ }
+
+ /**
+ * {"id":1,"itemNr":"theItem","owner":2}
+ */
+ @Override
+ public ItemWithSerializer deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ final JsonNode node = jp.getCodec()
+ .readTree(jp);
+ final int id = (Integer) ((IntNode) node.get("id")).numberValue();
+ final String itemName = node.get("itemName")
+ .asText();
+ final int userId = (Integer) ((IntNode) node.get("owner")).numberValue();
+
+ return new ItemWithSerializer(id, itemName, new User(userId, null));
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/Item.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/Item.java
new file mode 100644
index 0000000000..009789bbf6
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/Item.java
@@ -0,0 +1,32 @@
+package com.baeldung.jackson.annotation.dtos;
+
+public class Item {
+ public int id;
+ public String itemName;
+ public User owner;
+
+ public Item() {
+ super();
+ }
+
+ public Item(final int id, final String itemName, final User owner) {
+ this.id = id;
+ this.itemName = itemName;
+ this.owner = owner;
+ }
+
+ // API
+
+ public int getId() {
+ return id;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public User getOwner() {
+ return owner;
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/ItemWithSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/ItemWithSerializer.java
new file mode 100644
index 0000000000..a4cd7d78ad
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/ItemWithSerializer.java
@@ -0,0 +1,36 @@
+package com.baeldung.jackson.annotation.dtos;
+
+import com.baeldung.jackson.annotation.deserialization.ItemDeserializerOnClass;
+import com.baeldung.jackson.annotation.serialization.ItemSerializerOnClass;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonSerialize(using = ItemSerializerOnClass.class)
+@JsonDeserialize(using = ItemDeserializerOnClass.class)
+public class ItemWithSerializer {
+ public final int id;
+ public final String itemName;
+ public final User owner;
+
+ public ItemWithSerializer(final int id, final String itemName, final User owner) {
+ this.id = id;
+ this.itemName = itemName;
+ this.owner = owner;
+ }
+
+ // API
+
+ public int getId() {
+ return id;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public User getOwner() {
+ return owner;
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/User.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/User.java
new file mode 100644
index 0000000000..9a4ec08ec3
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/User.java
@@ -0,0 +1,26 @@
+package com.baeldung.jackson.annotation.dtos;
+
+public class User {
+ public int id;
+ public String name;
+
+ public User() {
+ super();
+ }
+
+ public User(final int id, final String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ // API
+
+ public int getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/withEnum/DistanceEnumWithValue.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/withEnum/DistanceEnumWithValue.java
new file mode 100644
index 0000000000..574908523a
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/dtos/withEnum/DistanceEnumWithValue.java
@@ -0,0 +1,29 @@
+package com.baeldung.jackson.annotation.dtos.withEnum;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum DistanceEnumWithValue {
+ KILOMETER("km", 1000), MILE("miles", 1609.34), METER("meters", 1), INCH("inches", 0.0254), CENTIMETER("cm", 0.01), MILLIMETER("mm", 0.001);
+
+ private String unit;
+ private final double meters;
+
+ private DistanceEnumWithValue(String unit, double meters) {
+ this.unit = unit;
+ this.meters = meters;
+ }
+
+ @JsonValue
+ public double getMeters() {
+ return meters;
+ }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRoot.java
similarity index 86%
rename from jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRoot.java
index d879c16e6a..629f444356 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRoot.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.exception;
+package com.baeldung.jackson.annotation.exception;
import com.fasterxml.jackson.annotation.JsonRootName;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRootNamespace.java
similarity index 87%
rename from jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRootNamespace.java
index bf8c85efba..8f863168af 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/exception/UserWithRootNamespace.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.exception;
+package com.baeldung.jackson.annotation.exception;
import com.fasterxml.jackson.annotation.JsonRootName;
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Item.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Item.java
new file mode 100644
index 0000000000..3a2681e0f0
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Item.java
@@ -0,0 +1,36 @@
+package com.baeldung.jackson.annotation.jsonview;
+
+import com.fasterxml.jackson.annotation.JsonView;
+
+public class Item {
+ @JsonView(Views.Public.class)
+ public int id;
+
+ @JsonView(Views.Public.class)
+ public String itemName;
+
+ @JsonView(Views.Internal.class)
+ public String ownerName;
+
+ public Item() {
+ super();
+ }
+
+ public Item(final int id, final String itemName, final String ownerName) {
+ this.id = id;
+ this.itemName = itemName;
+ this.ownerName = ownerName;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public String getOwnerName() {
+ return ownerName;
+ }
+}
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Views.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Views.java
new file mode 100644
index 0000000000..567592608a
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/jsonview/Views.java
@@ -0,0 +1,9 @@
+package com.baeldung.jackson.annotation.jsonview;
+
+public class Views {
+ public static class Public {
+ }
+
+ public static class Internal extends Public {
+ }
+}
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializer.java
new file mode 100644
index 0000000000..cc17228de2
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializer.java
@@ -0,0 +1,32 @@
+package com.baeldung.jackson.annotation.serialization;
+
+import java.io.IOException;
+
+import com.baeldung.jackson.annotation.dtos.Item;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+public class ItemSerializer extends StdSerializer- {
+
+ private static final long serialVersionUID = 6739170890621978901L;
+
+ public ItemSerializer() {
+ this(null);
+ }
+
+ public ItemSerializer(final Class
- t) {
+ super(t);
+ }
+
+ @Override
+ public final void serialize(final Item value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException {
+ jgen.writeStartObject();
+ jgen.writeNumberField("id", value.id);
+ jgen.writeStringField("itemName", value.itemName);
+ jgen.writeNumberField("owner", value.owner.id);
+ jgen.writeEndObject();
+ }
+
+}
\ No newline at end of file
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializerOnClass.java b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializerOnClass.java
new file mode 100644
index 0000000000..bad44c01e7
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/annotation/serialization/ItemSerializerOnClass.java
@@ -0,0 +1,32 @@
+package com.baeldung.jackson.annotation.serialization;
+
+import java.io.IOException;
+
+import com.baeldung.jackson.annotation.dtos.ItemWithSerializer;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+public class ItemSerializerOnClass extends StdSerializer {
+
+ private static final long serialVersionUID = -1760959597313610409L;
+
+ public ItemSerializerOnClass() {
+ this(null);
+ }
+
+ public ItemSerializerOnClass(final Class t) {
+ super(t);
+ }
+
+ @Override
+ public final void serialize(final ItemWithSerializer value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException {
+ jgen.writeStartObject();
+ jgen.writeNumberField("id", value.id);
+ jgen.writeStringField("itemName", value.itemName);
+ jgen.writeNumberField("owner", value.owner.id);
+ jgen.writeEndObject();
+ }
+
+}
\ No newline at end of file
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/CustomListDeserializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/CustomListDeserializer.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/CustomListDeserializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/CustomListDeserializer.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/CustomListSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/CustomListSerializer.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/CustomListSerializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/CustomListSerializer.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/Item.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/Item.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/Item.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/Item.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithRef.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithRef.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithSerializer.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithSerializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithSerializer.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithView.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithView.java
similarity index 90%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithView.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithView.java
index ffa19fbad2..5cf9cd9981 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/ItemWithView.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/ItemWithView.java
@@ -1,6 +1,6 @@
package com.baeldung.jackson.bidirection;
-import com.baeldung.jackson.jsonview.Views;
+import com.baeldung.jackson.bidirection.jsonview.Views;
import com.fasterxml.jackson.annotation.JsonView;
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/User.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/User.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/User.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/User.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithIdentity.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithIdentity.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithIgnore.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithIgnore.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithRef.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithRef.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithSerializer.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithSerializer.java
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithSerializer.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithSerializer.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithView.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithView.java
similarity index 92%
rename from jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithView.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithView.java
index d92d67b3a1..ad73eb8f92 100644
--- a/jackson/src/test/java/com/baeldung/jackson/bidirection/UserWithView.java
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/UserWithView.java
@@ -3,7 +3,7 @@ package com.baeldung.jackson.bidirection;
import java.util.ArrayList;
import java.util.List;
-import com.baeldung.jackson.jsonview.Views;
+import com.baeldung.jackson.bidirection.jsonview.Views;
import com.fasterxml.jackson.annotation.JsonView;
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/jsonview/Views.java b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/jsonview/Views.java
new file mode 100644
index 0000000000..0a13d55a5b
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/bidirection/jsonview/Views.java
@@ -0,0 +1,9 @@
+package com.baeldung.jackson.bidirection.jsonview;
+
+public class Views {
+ public static class Public {
+ }
+
+ public static class Internal extends Public {
+ }
+}
diff --git a/jackson-annotations/src/main/java/com/baeldung/jackson/domain/Person.java b/jackson-annotations/src/main/java/com/baeldung/jackson/domain/Person.java
new file mode 100644
index 0000000000..f11ba41113
--- /dev/null
+++ b/jackson-annotations/src/main/java/com/baeldung/jackson/domain/Person.java
@@ -0,0 +1,30 @@
+package com.baeldung.jackson.domain;
+
+public class Person {
+
+ private String firstName;
+ private String lastName;
+
+ public Person(String firstName, String lastName) {
+ super();
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
+
diff --git a/jackson/src/main/java/com/baeldung/jackson/format/User.java b/jackson-annotations/src/main/java/com/baeldung/jackson/format/User.java
old mode 100755
new mode 100644
similarity index 100%
rename from jackson/src/main/java/com/baeldung/jackson/format/User.java
rename to jackson-annotations/src/main/java/com/baeldung/jackson/format/User.java
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/ExtraAnnotationUnitTest.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AdvancedAnnotationsUnitTest.java
similarity index 92%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/ExtraAnnotationUnitTest.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AdvancedAnnotationsUnitTest.java
index 647c451659..c0eb917292 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/ExtraAnnotationUnitTest.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AdvancedAnnotationsUnitTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -12,10 +12,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import com.baeldung.jackson.annotation.extra.AppendBeans.BeanWithAppend;
-import com.baeldung.jackson.annotation.extra.AppendBeans.BeanWithoutAppend;
-import com.baeldung.jackson.annotation.extra.IdentityReferenceBeans.BeanWithIdentityReference;
-import com.baeldung.jackson.annotation.extra.IdentityReferenceBeans.BeanWithoutIdentityReference;
+import com.baeldung.jackson.advancedannotations.AppendBeans.BeanWithAppend;
+import com.baeldung.jackson.advancedannotations.AppendBeans.BeanWithoutAppend;
+import com.baeldung.jackson.advancedannotations.IdentityReferenceBeans.BeanWithIdentityReference;
+import com.baeldung.jackson.advancedannotations.IdentityReferenceBeans.BeanWithoutIdentityReference;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
-public class ExtraAnnotationUnitTest {
+public class AdvancedAnnotationsUnitTest {
@Test
public void whenNotUsingJsonIdentityReferenceAnnotation_thenCorrect() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/AppendBeans.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AppendBeans.java
similarity index 95%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/AppendBeans.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AppendBeans.java
index 7b75c205c9..ab045dd0c6 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/AppendBeans.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/AppendBeans.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/IdentityReferenceBeans.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/IdentityReferenceBeans.java
similarity index 96%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/IdentityReferenceBeans.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/IdentityReferenceBeans.java
index 0a8736d9a5..6e723c317a 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/IdentityReferenceBeans.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/IdentityReferenceBeans.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/NamingBean.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/NamingBean.java
similarity index 92%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/NamingBean.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/NamingBean.java
index efd26ab9ae..323df49c14 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/NamingBean.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/NamingBean.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/POJOBuilderBean.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/POJOBuilderBean.java
similarity index 96%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/POJOBuilderBean.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/POJOBuilderBean.java
index e0a89c6903..97b747fe40 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/POJOBuilderBean.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/POJOBuilderBean.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/PropertyDescriptionBean.java
similarity index 90%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/PropertyDescriptionBean.java
index 1563cddb83..dcc0c67054 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/PropertyDescriptionBean.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdBean.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdBean.java
similarity index 90%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdBean.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdBean.java
index 32a6d5a1d5..1b25529743 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdBean.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdBean.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import com.fasterxml.jackson.annotation.JsonTypeId;
diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdResolverStructure.java
similarity index 98%
rename from jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdResolverStructure.java
index 9056023c69..f9ddd8eea9 100644
--- a/jackson/src/test/java/com/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/advancedannotations/TypeIdResolverStructure.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.annotation.extra;
+package com.baeldung.jackson.advancedannotations;
import java.util.List;
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java b/jackson-annotations/src/test/java/com/baeldung/jackson/annotation/JacksonAnnotationUnitTest.java
similarity index 90%
rename from jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/annotation/JacksonAnnotationUnitTest.java
index ee11f8f20e..462b65787a 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/annotation/JacksonAnnotationUnitTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.test;
+package com.baeldung.jackson.annotation;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
@@ -14,32 +14,18 @@ import java.util.TimeZone;
import org.junit.Test;
-import com.baeldung.jackson.annotation.AliasBean;
-import com.baeldung.jackson.annotation.BeanWithCreator;
-import com.baeldung.jackson.annotation.BeanWithCustomAnnotation;
-import com.baeldung.jackson.annotation.BeanWithFilter;
-import com.baeldung.jackson.annotation.BeanWithGetter;
-import com.baeldung.jackson.annotation.BeanWithIgnore;
-import com.baeldung.jackson.annotation.BeanWithInject;
-import com.baeldung.jackson.annotation.ExtendableBean;
-import com.baeldung.jackson.annotation.MyBean;
-import com.baeldung.jackson.annotation.PrivateBean;
-import com.baeldung.jackson.annotation.RawBean;
-import com.baeldung.jackson.annotation.UnwrappedUser;
-import com.baeldung.jackson.annotation.UserWithIgnoreType;
-import com.baeldung.jackson.annotation.Zoo;
-import com.baeldung.jackson.bidirection.ItemWithIdentity;
-import com.baeldung.jackson.bidirection.ItemWithRef;
-import com.baeldung.jackson.bidirection.UserWithIdentity;
-import com.baeldung.jackson.bidirection.UserWithRef;
-import com.baeldung.jackson.date.EventWithFormat;
-import com.baeldung.jackson.date.EventWithSerializer;
-import com.baeldung.jackson.dtos.MyMixInForIgnoreType;
-import com.baeldung.jackson.dtos.withEnum.DistanceEnumWithValue;
-import com.baeldung.jackson.exception.UserWithRoot;
-import com.baeldung.jackson.exception.UserWithRootNamespace;
-import com.baeldung.jackson.jsonview.Item;
-import com.baeldung.jackson.jsonview.Views;
+import com.baeldung.jackson.annotation.bidirection.ItemWithIdentity;
+import com.baeldung.jackson.annotation.bidirection.ItemWithRef;
+import com.baeldung.jackson.annotation.bidirection.UserWithIdentity;
+import com.baeldung.jackson.annotation.bidirection.UserWithRef;
+import com.baeldung.jackson.annotation.date.EventWithFormat;
+import com.baeldung.jackson.annotation.date.EventWithSerializer;
+import com.baeldung.jackson.ignore.dtos.MyMixInForIgnoreType;
+import com.baeldung.jackson.annotation.dtos.withEnum.DistanceEnumWithValue;
+import com.baeldung.jackson.annotation.exception.UserWithRoot;
+import com.baeldung.jackson.annotation.exception.UserWithRootNamespace;
+import com.baeldung.jackson.annotation.jsonview.Item;
+import com.baeldung.jackson.annotation.jsonview.Views;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.MapperFeature;
@@ -352,13 +338,13 @@ public class JacksonAnnotationUnitTest {
// @Ignore("Jackson 2.7.1-1 seems to have changed the API regarding mixins")
@Test
public void whenSerializingUsingMixInAnnotation_thenCorrect() throws JsonProcessingException {
- final com.baeldung.jackson.dtos.Item item = new com.baeldung.jackson.dtos.Item(1, "book", null);
+ final com.baeldung.jackson.annotation.dtos.Item item = new com.baeldung.jackson.annotation.dtos.Item(1, "book", null);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("owner"));
final ObjectMapper mapper = new ObjectMapper();
- mapper.addMixIn(com.baeldung.jackson.dtos.User.class, MyMixInForIgnoreType.class);
+ mapper.addMixIn(com.baeldung.jackson.annotation.dtos.User.class, MyMixInForIgnoreType.class);
result = mapper.writeValueAsString(item);
assertThat(result, not(containsString("owner")));
diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonBidirectionRelationUnitTest.java b/jackson-annotations/src/test/java/com/baeldung/jackson/bidirection/JacksonBidirectionRelationUnitTest.java
similarity index 87%
rename from jackson/src/test/java/com/baeldung/jackson/test/JacksonBidirectionRelationUnitTest.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/bidirection/JacksonBidirectionRelationUnitTest.java
index e55ca55ac9..d0c5209891 100644
--- a/jackson/src/test/java/com/baeldung/jackson/test/JacksonBidirectionRelationUnitTest.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/bidirection/JacksonBidirectionRelationUnitTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.test;
+package com.baeldung.jackson.bidirection;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
@@ -9,19 +9,7 @@ import java.io.IOException;
import org.junit.Test;
-import com.baeldung.jackson.bidirection.Item;
-import com.baeldung.jackson.bidirection.ItemWithIdentity;
-import com.baeldung.jackson.bidirection.ItemWithIgnore;
-import com.baeldung.jackson.bidirection.ItemWithRef;
-import com.baeldung.jackson.bidirection.ItemWithSerializer;
-import com.baeldung.jackson.bidirection.ItemWithView;
-import com.baeldung.jackson.bidirection.User;
-import com.baeldung.jackson.bidirection.UserWithIdentity;
-import com.baeldung.jackson.bidirection.UserWithIgnore;
-import com.baeldung.jackson.bidirection.UserWithRef;
-import com.baeldung.jackson.bidirection.UserWithSerializer;
-import com.baeldung.jackson.bidirection.UserWithView;
-import com.baeldung.jackson.jsonview.Views;
+import com.baeldung.jackson.bidirection.jsonview.Views;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/jackson/src/test/java/com/baeldung/jackson/format/JsonFormatUnitTest.java b/jackson-annotations/src/test/java/com/baeldung/jackson/format/JsonFormatUnitTest.java
old mode 100755
new mode 100644
similarity index 100%
rename from jackson/src/test/java/com/baeldung/jackson/format/JsonFormatUnitTest.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/format/JsonFormatUnitTest.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java
similarity index 96%
rename from jackson-simple/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java
index da8b464d03..ab51fc11e7 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/JacksonSerializationIgnoreUnitTest.java
@@ -10,15 +10,15 @@ import java.util.Map;
import org.junit.Test;
-import com.baeldung.jackson.dtos.MyDto;
-import com.baeldung.jackson.dtos.MyDtoIncludeNonDefault;
-import com.baeldung.jackson.dtos.MyDtoWithFilter;
-import com.baeldung.jackson.dtos.MyDtoWithSpecialField;
-import com.baeldung.jackson.dtos.MyMixInForIgnoreType;
+import com.baeldung.jackson.ignore.dtos.MyDto;
+import com.baeldung.jackson.ignore.dtos.MyDtoIncludeNonDefault;
+import com.baeldung.jackson.ignore.dtos.MyDtoWithFilter;
+import com.baeldung.jackson.ignore.dtos.MyDtoWithSpecialField;
+import com.baeldung.jackson.ignore.dtos.MyMixInForIgnoreType;
import com.baeldung.jackson.ignore.dtos.MyDtoIgnoreField;
import com.baeldung.jackson.ignore.dtos.MyDtoIgnoreFieldByName;
import com.baeldung.jackson.ignore.dtos.MyDtoIgnoreNull;
-import com.baeldung.jackson.serialization.MyDtoNullKeySerializer;
+import com.baeldung.jackson.ignore.dtos.MyDtoNullKeySerializer;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
diff --git a/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDto.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDto.java
new file mode 100644
index 0000000000..3357c041c0
--- /dev/null
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDto.java
@@ -0,0 +1,54 @@
+package com.baeldung.jackson.ignore.dtos;
+
+public class MyDto {
+
+ private String stringValue;
+ private int intValue;
+ private boolean booleanValue;
+
+ public MyDto() {
+ super();
+ }
+
+ public MyDto(final String stringValue, final int intValue, final boolean booleanValue) {
+ super();
+
+ this.stringValue = stringValue;
+ this.intValue = intValue;
+ this.booleanValue = booleanValue;
+ }
+
+ // API
+
+ public String getStringValue() {
+ return stringValue;
+ }
+
+ public void setStringValue(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public void setIntValue(final int intValue) {
+ this.intValue = intValue;
+ }
+
+ public boolean isBooleanValue() {
+ return booleanValue;
+ }
+
+ public void setBooleanValue(final boolean booleanValue) {
+ this.booleanValue = booleanValue;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ return "MyDto [stringValue=" + stringValue + ", intValue=" + intValue + ", booleanValue=" + booleanValue + "]";
+ }
+
+}
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreField.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreField.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreField.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreField.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreFieldByName.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreFieldByName.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreFieldByName.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreFieldByName.java
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreNull.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreNull.java
similarity index 100%
rename from jackson-simple/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreNull.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIgnoreNull.java
diff --git a/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIncludeNonDefault.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIncludeNonDefault.java
new file mode 100644
index 0000000000..cf5d1682db
--- /dev/null
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoIncludeNonDefault.java
@@ -0,0 +1,43 @@
+package com.baeldung.jackson.ignore.dtos;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_DEFAULT)
+public class MyDtoIncludeNonDefault {
+
+ private String stringValue;
+ private int intValue;
+ private boolean booleanValue;
+
+ public MyDtoIncludeNonDefault() {
+ super();
+ }
+
+ // API
+
+ public String getStringValue() {
+ return stringValue;
+ }
+
+ public void setStringValue(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public void setIntValue(final int intValue) {
+ this.intValue = intValue;
+ }
+
+ public boolean isBooleanValue() {
+ return booleanValue;
+ }
+
+ public void setBooleanValue(final boolean booleanValue) {
+ this.booleanValue = booleanValue;
+ }
+
+}
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoNullKeySerializer.java
similarity index 91%
rename from jackson-simple/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java
rename to jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoNullKeySerializer.java
index d0b2d7f5e9..dcd4070dba 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java
+++ b/jackson-annotations/src/test/java/com/baeldung/jackson/ignore/dtos/MyDtoNullKeySerializer.java
@@ -1,27 +1,27 @@
-package com.baeldung.jackson.serialization;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-
-public class MyDtoNullKeySerializer extends StdSerializer
-
-
- javax.servlet
- jstl
- ${jstl.version}
-
-
- org.springframework
- spring-webmvc
- ${org.springframework.version}
-
-
- org.springframework
- spring-websocket
- ${org.springframework.version}
-
-
- org.springframework
- spring-messaging
- ${org.springframework.version}
-
org.springframework
spring-web
@@ -69,13 +48,6 @@
provided
${javax.servlet-api.version}
-
-
-
- org.primefaces
- primefaces
- ${primefaces.version}
-
@@ -98,8 +70,6 @@
2.2.14
3.0.0
-
- 6.2
\ No newline at end of file
diff --git a/json/pom.xml b/json/pom.xml
index c76625a6fa..eddbdee81e 100644
--- a/json/pom.xml
+++ b/json/pom.xml
@@ -29,11 +29,6 @@
fastjson
${fastjson.version}
-
- org.json
- json
- ${json.version}
-
com.google.code.gson
gson
@@ -49,13 +44,6 @@
javax.json.bind-api
${jsonb-api.version}
-
- junit
- junit
- ${junit.version}
- test
-
-
org.glassfish
javax.json
diff --git a/jta/pom.xml b/jta/pom.xml
index 1e86a0144c..b6f1371629 100644
--- a/jta/pom.xml
+++ b/jta/pom.xml
@@ -2,7 +2,6 @@
4.0.0
- com.baeldung
jta
1.0-SNAPSHOT
jta
@@ -33,51 +32,7 @@
org.hsqldb
hsqldb
- ${hsqldb.version}
-
-
- autoconfiguration
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- integration-test
-
- test
-
-
-
- **/*LiveTest.java
- **/*IntegrationTest.java
- **/*IntTest.java
-
-
- **/AutoconfigurationTest.java
-
-
-
-
-
-
- json
-
-
-
-
-
-
-
-
-
- UTF-8
- UTF-8
- 2.4.1
- 2.0.4.RELEASE
-
diff --git a/libraries-3/README.md b/libraries-3/README.md
index a6c6b190ab..a9d48bb389 100644
--- a/libraries-3/README.md
+++ b/libraries-3/README.md
@@ -7,3 +7,5 @@ The code examples related to different libraries are each in their own module.
Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-modules) we already have separate modules. Please make sure to have a look at the existing modules in such cases.
+### Relevant Articles:
+- [Parsing Command-Line Parameters with JCommander](https://www.baeldung.com/jcommander-parsing-command-line-parameters)
diff --git a/linux-bash/json/README.md b/linux-bash/json/README.md
new file mode 100644
index 0000000000..c0ed9d14d7
--- /dev/null
+++ b/linux-bash/json/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Guide to Linux jq Command for JSON processing](https://www.baeldung.com/linux/jq-command-json)
diff --git a/linux-bash/text/src/main/bash/append_multiple_lines.sh b/linux-bash/text/src/main/bash/append_multiple_lines.sh
new file mode 100755
index 0000000000..580a689716
--- /dev/null
+++ b/linux-bash/text/src/main/bash/append_multiple_lines.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# echo per line
+echo Lorem ipsum dolor sit amet, consectetur adipiscing elit, >> echo-per-line.txt
+echo sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. >> echo-per-line.txt
+
+# echo with escaped newline
+echo -e Lorem ipsum dolor sit amet, consectetur adipiscing elit,\\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua. >> echo-escaped-newline.txt
+
+# echo with double quoted string
+echo -e "Lorem ipsum dolor sit amet, consectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua." >> echo-double-quoted.txt
+
+# printf instead of echo
+printf "Lorem ipsum dolor sit amet, consectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua." >> printf.txt
+
+# printf using format string
+printf "%s\n%s" "Lorem ipsum dolor sit amet, consectetur adipiscing elit," "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." >> printf-format.txt
+
+# cat
+cat << EOF >> cat.txt
+Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+EOF
+
+# tee
+tee -a tee.txt << EOF
+Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+EOF
+
diff --git a/lombok/README.md b/lombok/README.md
index 39d3cd6b05..bda960a28a 100644
--- a/lombok/README.md
+++ b/lombok/README.md
@@ -11,4 +11,4 @@ This module contains articles about Project Lombok.
- [Lombok Builder with Custom Setter](https://www.baeldung.com/lombok-builder-custom-setter)
- [Setting up Lombok with Eclipse and Intellij](https://www.baeldung.com/lombok-ide)
- [Using the @Singular Annotation with Lombok Builders](https://www.baeldung.com/lombok-builder-singular)
-
+- [Using Lombok’s @Accessors Annotation](https://www.baeldung.com/lombok-accessors)
diff --git a/patterns/design-patterns-structural/README.md b/patterns/design-patterns-structural/README.md
index 91620a522e..3478b89c42 100644
--- a/patterns/design-patterns-structural/README.md
+++ b/patterns/design-patterns-structural/README.md
@@ -5,3 +5,4 @@
- [The Decorator Pattern in Java](https://www.baeldung.com/java-decorator-pattern)
- [The Adapter Pattern in Java](https://www.baeldung.com/java-adapter-pattern)
- [The Proxy Pattern in Java](https://www.baeldung.com/java-proxy-pattern)
+- [The Bridge Pattern in Java](https://www.baeldung.com/java-bridge-pattern)
diff --git a/persistence-modules/hibernate5-2/README.md b/persistence-modules/hibernate5-2/README.md
index c61552f305..75d50cd0b4 100644
--- a/persistence-modules/hibernate5-2/README.md
+++ b/persistence-modules/hibernate5-2/README.md
@@ -1,3 +1,3 @@
### Relevant Articles:
- [Hibernate Error “Not all named parameters have been set”](https://www.baeldung.com/hibernate-error-named-parameters-not-set)
-
+- [FetchMode in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-fetchmode)
diff --git a/persistence-modules/spring-boot-persistence-h2/pom.xml b/persistence-modules/spring-boot-persistence-h2/pom.xml
index 30c727bfc8..d1fd5b0170 100644
--- a/persistence-modules/spring-boot-persistence-h2/pom.xml
+++ b/persistence-modules/spring-boot-persistence-h2/pom.xml
@@ -22,6 +22,10 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
com.h2database
h2
diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/ItemRepository.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/ItemRepository.java
new file mode 100644
index 0000000000..3007f56208
--- /dev/null
+++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/ItemRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.h2db.springboot.daos;
+
+import com.baeldung.h2db.springboot.models.Item;
+import org.springframework.data.repository.CrudRepository;
+
+import java.math.BigDecimal;
+
+public interface ItemRepository extends CrudRepository- {
+}
diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Item.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Item.java
new file mode 100644
index 0000000000..a5c5b0d3cb
--- /dev/null
+++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Item.java
@@ -0,0 +1,18 @@
+package com.baeldung.h2db.springboot.models;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+@Entity
+public class Item {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @NotNull
+ private BigDecimal price;
+}
diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties
index 109b389b58..ed1ffc63c3 100644
--- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties
+++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties
@@ -3,6 +3,10 @@ spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.show-sql=true
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.validator.apply_to_ddl=false
+#spring.jpa.properties.hibernate.check_nullability=true
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
debug=true
\ No newline at end of file
diff --git a/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/ItemIntegrationTest.java b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/ItemIntegrationTest.java
new file mode 100644
index 0000000000..839dd87b7e
--- /dev/null
+++ b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/ItemIntegrationTest.java
@@ -0,0 +1,29 @@
+package com.baeldung;
+
+import com.baeldung.h2db.springboot.SpringBootH2Application;
+import com.baeldung.h2db.springboot.daos.ItemRepository;
+import com.baeldung.h2db.springboot.models.Item;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.validation.ConstraintViolationException;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = SpringBootH2Application.class)
+public class ItemIntegrationTest {
+
+ @Autowired
+ private ItemRepository itemRepository;
+
+ @Test
+ public void shouldNotAllowToPersistNullItemsPrice() {
+ assertThatThrownBy(() -> itemRepository.save(new Item()))
+ .hasRootCauseInstanceOf(ConstraintViolationException.class)
+ .hasStackTraceContaining("must not be null");
+ }
+}
diff --git a/persistence-modules/spring-data-geode/README.md b/persistence-modules/spring-data-geode/README.md
new file mode 100644
index 0000000000..98bde6ea5a
--- /dev/null
+++ b/persistence-modules/spring-data-geode/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Intro to Spring Data Geode](https://www.baeldung.com/spring-data-geode)
diff --git a/persistence-modules/spring-data-jpa-2/README.md b/persistence-modules/spring-data-jpa-2/README.md
index d1875d91d4..e59aca7c69 100644
--- a/persistence-modules/spring-data-jpa-2/README.md
+++ b/persistence-modules/spring-data-jpa-2/README.md
@@ -9,3 +9,4 @@
- [JPA @Embedded And @Embeddable](https://www.baeldung.com/jpa-embedded-embeddable)
- [Spring Data JPA Delete and Relationships](https://www.baeldung.com/spring-data-jpa-delete)
- [Spring Data JPA and Named Entity Graphs](https://www.baeldung.com/spring-data-jpa-named-entity-graphs)
+- [Customizing the Result of JPA Queries with Aggregation Functions](https://www.baeldung.com/jpa-queries-custom-result-with-aggregation-functions)
diff --git a/persistence-modules/spring-data-jpa-3/README.md b/persistence-modules/spring-data-jpa-3/README.md
index a86c1e5ec2..d3908c3a01 100644
--- a/persistence-modules/spring-data-jpa-3/README.md
+++ b/persistence-modules/spring-data-jpa-3/README.md
@@ -10,6 +10,7 @@
- [Batch Insert/Update with Hibernate/JPA](https://www.baeldung.com/jpa-hibernate-batch-insert-update)
- [Difference Between save() and saveAndFlush() in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-save-saveandflush)
- [Programmatic Transaction Management in Spring](https://www.baeldung.com/spring-programmatic-transaction-management)
+- [A Guide to Spring’s Open Session In View](https://www.baeldung.com/spring-open-session-in-view)
### Eclipse Config
After importing the project into Eclipse, you may see the following error:
diff --git a/play-framework/websockets/app/actors/Messenger.java b/play-framework/websockets/app/actors/Messenger.java
new file mode 100644
index 0000000000..1c9335b82e
--- /dev/null
+++ b/play-framework/websockets/app/actors/Messenger.java
@@ -0,0 +1,111 @@
+package actors;
+
+import akka.actor.AbstractActor;
+import akka.actor.ActorRef;
+import akka.actor.PoisonPill;
+import akka.actor.Props;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.http.javadsl.Http;
+import akka.http.javadsl.marshallers.jackson.Jackson;
+import akka.http.javadsl.model.HttpMessage;
+import akka.http.javadsl.model.HttpRequest;
+import akka.http.javadsl.model.HttpResponse;
+import akka.stream.Materializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import dto.MessageDTO;
+import dto.RequestDTO;
+import utils.MessageConverter;
+
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.UUID;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Messenger extends AbstractActor {
+ private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
+
+ private ActorRef out;
+
+ public Messenger(ActorRef out) {
+ this.out = out;
+ }
+
+ public static Props props(ActorRef out) {
+ return Props.create(Messenger.class, () -> new Messenger(out));
+ }
+
+ @Override
+ public void preStart() throws Exception {
+ log.info("Messenger actor started at {}",
+ OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+ }
+
+ @Override
+ public void postStop() throws Exception {
+ log.info("Messenger actor stopped at {}",
+ OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+ }
+
+ private void onSendMessage(JsonNode jsonNode) {
+ RequestDTO requestDTO = MessageConverter.jsonNodeToRequest(jsonNode);
+ String message = requestDTO.getMessage().toLowerCase();
+ if("stop".equals(message)) {
+ MessageDTO messageDTO = createMessageDTO("1", "1", "Stop", "Stopping actor");
+ out.tell(MessageConverter.messageToJsonNode(messageDTO), getSelf());
+ self().tell(PoisonPill.getInstance(), getSelf());
+ } else {
+ log.info("Actor received. {}", requestDTO);
+ processMessage(requestDTO);
+ }
+ }
+
+ private MessageDTO createMessageDTO(String userId, String id, String title, String message) {
+ MessageDTO messageDTO = new MessageDTO();
+ messageDTO.setUserId(UUID.randomUUID().toString());
+ messageDTO.setId(UUID.randomUUID().toString());
+ messageDTO.setTitle("Self Kill");
+ messageDTO.setBody("Stopping actor");
+ return messageDTO;
+ }
+
+ private void processMessage(RequestDTO requestDTO) {
+ CompletionStage responseFuture = getRandomMessage();
+ responseFuture.thenCompose(this::consumeHttpResponse)
+ .thenAccept(messageDTO ->
+ out.tell(MessageConverter.messageToJsonNode(messageDTO), getSelf()));
+ }
+
+ private CompletionStage getRandomMessage() {
+ int postId = ThreadLocalRandom.current().nextInt(0, 100);
+ return Http.get(getContext().getSystem()).singleRequest(
+ HttpRequest.create("https://jsonplaceholder.typicode.com/posts/" + postId)
+ );
+ }
+
+ private void discardEntity(HttpResponse httpResponse, Materializer materializer) {
+ httpResponse.discardEntityBytes(materializer)
+ .completionStage()
+ .whenComplete((done, ex) -> log.info("Entity discarded completely!"));
+ }
+
+ private CompletionStage consumeHttpResponse(HttpResponse httpResponse) {
+ Materializer materializer = Materializer.matFromSystem(getContext().getSystem());
+ return Jackson.unmarshaller(MessageDTO.class)
+ .unmarshal(httpResponse.entity(), materializer)
+ .thenApply(messageDTO -> {
+ log.info("Received message: {}", messageDTO);
+ discardEntity(httpResponse, materializer);
+ return messageDTO;
+ });
+ }
+
+ @Override
+ public Receive createReceive() {
+ return receiveBuilder()
+ .match(JsonNode.class, this::onSendMessage)
+ .matchAny(o -> log.error("Received unknown message: {}", o.getClass()))
+ .build();
+ }
+}
diff --git a/play-framework/websockets/app/controllers/HomeController.java b/play-framework/websockets/app/controllers/HomeController.java
new file mode 100644
index 0000000000..39c670fe59
--- /dev/null
+++ b/play-framework/websockets/app/controllers/HomeController.java
@@ -0,0 +1,79 @@
+package controllers;
+
+import actors.Messenger;
+import akka.actor.ActorSystem;
+import akka.stream.Materializer;
+import akka.stream.javadsl.Flow;
+import akka.stream.javadsl.Sink;
+import akka.stream.javadsl.Source;
+import com.fasterxml.jackson.databind.JsonNode;
+import dto.MessageDTO;
+import lombok.extern.slf4j.Slf4j;
+import play.libs.F;
+import play.libs.streams.ActorFlow;
+import play.mvc.*;
+import utils.MessageConverter;
+
+import javax.inject.Inject;
+
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+@Slf4j
+public class HomeController extends Controller {
+ private ActorSystem actorSystem;
+ private Materializer materializer;
+
+ @Inject
+ public HomeController(ActorSystem actorSystem, Materializer materializer) {
+ this.actorSystem = actorSystem;
+ this.materializer = materializer;
+ }
+
+ public Result index(Http.Request request) {
+ String url = routes.HomeController.socket().webSocketURL(request);
+ //To test WebSockets with akka streams, uncomment the next line and comment out the previous
+ //String url = routes.HomeController.akkaStreamsSocket().webSocketURL(request);
+ return ok(views.html.index.render(url));
+ }
+
+
+ public WebSocket socket() {
+ return WebSocket.Json.acceptOrResult(this::createActorFlow);
+ }
+
+ private CompletionStage>> createActorFlow(
+ Http.RequestHeader request) {
+ return CompletableFuture.completedFuture(F.Either.Right(createFlowForActor()));
+ }
+
+ private CompletionStage>>
+ createActorFlow2(Http.RequestHeader request) {
+ return CompletableFuture.completedFuture(
+ request.session()
+ .getOptional("username")
+ .map(username ->
+ F.Either.>Right(
+ createFlowForActor()))
+ .orElseGet(() -> F.Either.Left(forbidden())));
+ }
+
+ private Flow createFlowForActor() {
+ return ActorFlow.actorRef(out -> Messenger.props(out), actorSystem, materializer);
+ }
+
+ public WebSocket akkaStreamsSocket() {
+ return WebSocket.Json.accept(
+ request -> {
+ Sink in = Sink.foreach(System.out::println);
+ MessageDTO messageDTO = new MessageDTO("1", "1", "Title", "Test Body");
+ Source out = Source.tick(
+ Duration.ofSeconds(2),
+ Duration.ofSeconds(2),
+ MessageConverter.messageToJsonNode(messageDTO)
+ );
+ return Flow.fromSinkAndSource(in, out);
+ });
+ }
+}
diff --git a/play-framework/websockets/app/dto/MessageDTO.java b/play-framework/websockets/app/dto/MessageDTO.java
new file mode 100644
index 0000000000..e6b2bac1af
--- /dev/null
+++ b/play-framework/websockets/app/dto/MessageDTO.java
@@ -0,0 +1,60 @@
+package dto;
+
+public class MessageDTO {
+ private String userId;
+ private String id;
+ private String title;
+ private String body;
+
+ public MessageDTO() {
+ }
+
+ public MessageDTO(String userId, String id, String title, String body) {
+ this.userId = userId;
+ this.id = id;
+ this.title = title;
+ this.body = body;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ @Override
+ public String toString() {
+ return "MessageDTO{" +
+ "userId='" + userId + '\'' +
+ ", id='" + id + '\'' +
+ ", title='" + title + '\'' +
+ ", body='" + body + '\'' +
+ '}';
+ }
+}
diff --git a/play-framework/websockets/app/dto/RequestDTO.java b/play-framework/websockets/app/dto/RequestDTO.java
new file mode 100644
index 0000000000..a85d3770a4
--- /dev/null
+++ b/play-framework/websockets/app/dto/RequestDTO.java
@@ -0,0 +1,27 @@
+package dto;
+
+public class RequestDTO {
+ private String message;
+
+ public RequestDTO() {
+ }
+
+ public RequestDTO(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ return "RequestDTO{" +
+ "message='" + message + '\'' +
+ '}';
+ }
+}
diff --git a/play-framework/websockets/app/utils/MessageConverter.java b/play-framework/websockets/app/utils/MessageConverter.java
new file mode 100644
index 0000000000..85729cd1da
--- /dev/null
+++ b/play-framework/websockets/app/utils/MessageConverter.java
@@ -0,0 +1,24 @@
+package utils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import dto.MessageDTO;
+import dto.RequestDTO;
+
+public class MessageConverter {
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ public static MessageDTO jsonNodeToMessage(JsonNode jsonNode) {
+ return OBJECT_MAPPER.convertValue(jsonNode, MessageDTO.class);
+ }
+
+ public static JsonNode messageToJsonNode(MessageDTO messageDTO) {
+ return OBJECT_MAPPER.convertValue(messageDTO, JsonNode.class);
+ }
+ public static RequestDTO jsonNodeToRequest(JsonNode jsonNode) {
+ return OBJECT_MAPPER.convertValue(jsonNode, RequestDTO.class);
+ }
+
+ public static JsonNode requestToJsonNode(RequestDTO requestDTO) {
+ return OBJECT_MAPPER.convertValue(requestDTO, JsonNode.class);
+ }
+}
diff --git a/play-framework/websockets/app/views/index.scala.html b/play-framework/websockets/app/views/index.scala.html
new file mode 100644
index 0000000000..b837fc6f74
--- /dev/null
+++ b/play-framework/websockets/app/views/index.scala.html
@@ -0,0 +1,97 @@
+@(url: String)
+@main("Welcome to Play") {
+
Welcome to Play WebSockets!
+
+
+
+
+
+
+}
diff --git a/play-framework/websockets/app/views/main.scala.html b/play-framework/websockets/app/views/main.scala.html
new file mode 100644
index 0000000000..be5dd8f09d
--- /dev/null
+++ b/play-framework/websockets/app/views/main.scala.html
@@ -0,0 +1,14 @@
+@(title: String)(content: Html)
+
+
+
+
+ @title
+
+
+
+
+ @content
+
+
+
diff --git a/play-framework/websockets/build.sbt b/play-framework/websockets/build.sbt
new file mode 100644
index 0000000000..a076daa4f0
--- /dev/null
+++ b/play-framework/websockets/build.sbt
@@ -0,0 +1,22 @@
+name := """websockets"""
+organization := "com.baeldung"
+
+version := "1.0-SNAPSHOT"
+
+lazy val root = (project in file(".")).enablePlugins(PlayJava)
+
+scalaVersion := "2.13.0"
+
+lazy val akkaVersion = "2.6.0-M8"
+lazy val akkaHttpVersion = "10.1.10"
+
+libraryDependencies += guice
+libraryDependencies += "com.typesafe.akka" %% "akka-actor" % akkaVersion
+libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % akkaVersion
+libraryDependencies += "com.typesafe.akka" %% "akka-stream" % akkaVersion
+libraryDependencies += "com.typesafe.akka" %% "akka-http-jackson" % akkaHttpVersion
+libraryDependencies += "com.typesafe.akka" %% "akka-http" % akkaHttpVersion
+libraryDependencies += "org.projectlombok" % "lombok" % "1.18.8" % "provided"
+libraryDependencies += "junit" % "junit" % "4.12"
+
+PlayKeys.devSettings += "play.server.http.idleTimeout" -> "infinite"
diff --git a/play-framework/websockets/conf/application.conf b/play-framework/websockets/conf/application.conf
new file mode 100644
index 0000000000..87cb978051
--- /dev/null
+++ b/play-framework/websockets/conf/application.conf
@@ -0,0 +1,7 @@
+# This is the main configuration file for the application.
+# https://www.playframework.com/documentation/latest/ConfigFile
+########################################
+# akka-http-core Reference Config File #
+########################################
+
+play.server.http.idleTimeout = "infinite"
\ No newline at end of file
diff --git a/play-framework/websockets/conf/logback.xml b/play-framework/websockets/conf/logback.xml
new file mode 100644
index 0000000000..8efb66cda3
--- /dev/null
+++ b/play-framework/websockets/conf/logback.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ ${application.home:-.}/logs/application.log
+
+ %date [%level] from %logger in %thread - %message%n%xException
+
+
+
+
+
+ %coloredLevel %logger{15} - %message%n%xException{10}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/play-framework/websockets/conf/routes b/play-framework/websockets/conf/routes
new file mode 100644
index 0000000000..674aba00bd
--- /dev/null
+++ b/play-framework/websockets/conf/routes
@@ -0,0 +1,11 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# An example controller showing a sample home page
+GET / controllers.HomeController.index(request: Request)
+GET /chat controllers.HomeController.socket
+GET /chat/with/streams controllers.HomeController.akkaStreamsSocket
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
diff --git a/play-framework/websockets/project/build.properties b/play-framework/websockets/project/build.properties
new file mode 100644
index 0000000000..c0bab04941
--- /dev/null
+++ b/play-framework/websockets/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.2.8
diff --git a/play-framework/websockets/project/plugins.sbt b/play-framework/websockets/project/plugins.sbt
new file mode 100644
index 0000000000..1c8c62a0d5
--- /dev/null
+++ b/play-framework/websockets/project/plugins.sbt
@@ -0,0 +1,7 @@
+// The Play plugin
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
+
+// Defines scaffolding (found under .g8 folder)
+// http://www.foundweekends.org/giter8/scaffolding.html
+// sbt "g8Scaffold form"
+addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
diff --git a/play-framework/websockets/public/images/favicon.png b/play-framework/websockets/public/images/favicon.png
new file mode 100644
index 0000000000..c7d92d2ae4
Binary files /dev/null and b/play-framework/websockets/public/images/favicon.png differ
diff --git a/play-framework/websockets/public/javascripts/main.js b/play-framework/websockets/public/javascripts/main.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/play-framework/websockets/public/stylesheets/main.css b/play-framework/websockets/public/stylesheets/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/play-framework/websockets/test/controllers/HomeControllerTest.java b/play-framework/websockets/test/controllers/HomeControllerTest.java
new file mode 100644
index 0000000000..b006feab8c
--- /dev/null
+++ b/play-framework/websockets/test/controllers/HomeControllerTest.java
@@ -0,0 +1,32 @@
+package controllers;
+
+import org.junit.Test;
+import play.Application;
+import play.inject.guice.GuiceApplicationBuilder;
+import play.mvc.Http;
+import play.mvc.Result;
+import play.test.WithApplication;
+
+import static org.junit.Assert.assertEquals;
+import static play.mvc.Http.Status.OK;
+import static play.test.Helpers.GET;
+import static play.test.Helpers.route;
+
+public class HomeControllerTest extends WithApplication {
+
+ @Override
+ protected Application provideApplication() {
+ return new GuiceApplicationBuilder().build();
+ }
+
+ @Test
+ public void giveRequest_whenRootPath_ThenStatusOkay() {
+ Http.RequestBuilder request = new Http.RequestBuilder()
+ .method(GET)
+ .uri("/");
+
+ Result result = route(app, request);
+ assertEquals(OK, result.status());
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index cefb09325d..a77936bacf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -341,6 +341,7 @@
algorithms-miscellaneous-4
algorithms-miscellaneous-5
algorithms-sorting
+ algorithms-searching
animal-sniffer-mvn-plugin
annotations
antlr
@@ -499,6 +500,8 @@
jackson
jackson-2
jackson-simple
+ jackson-annotations
+ jackson-exceptions
java-collections-conversions
java-collections-conversions-2
java-collections-maps
@@ -508,6 +511,7 @@
java-lite
java-math
+ java-math-2
java-numbers
java-numbers-2
java-rmi
@@ -975,6 +979,7 @@
algorithms-miscellaneous-4
algorithms-miscellaneous-5
algorithms-sorting
+ algorithms-searching
animal-sniffer-mvn-plugin
annotations
antlr
@@ -1125,6 +1130,8 @@
jackson
jackson-2
jackson-simple
+ jackson-annotations
+ jackson-exceptions
java-collections-conversions
java-collections-conversions-2
java-collections-maps
@@ -1134,6 +1141,7 @@
java-ee-8-security-api
java-lite
java-math
+ java-math-2
java-numbers
java-numbers-2
java-rmi
@@ -1447,7 +1455,7 @@
twilio
twitter4j
- undertow
+
vertx
vertx-and-rxjava
diff --git a/spring-batch/README.md b/spring-batch/README.md
index 9e09612490..99ac9826bc 100644
--- a/spring-batch/README.md
+++ b/spring-batch/README.md
@@ -8,3 +8,4 @@ This module contains articles about Spring Batch
- [Spring Batch – Tasklets vs Chunks](https://www.baeldung.com/spring-batch-tasklet-chunk)
- [How to Trigger and Stop a Scheduled Spring Batch Job](https://www.baeldung.com/spring-batch-start-stop-job)
- [Configuring Skip Logic in Spring Batch](https://www.baeldung.com/spring-batch-skip-logic)
+- [Testing a Spring Batch Job](https://www.baeldung.com/spring-batch-testing-job)
diff --git a/spring-boot-data/README.md b/spring-boot-data/README.md
index eb3cd5bbaa..f023bb772f 100644
--- a/spring-boot-data/README.md
+++ b/spring-boot-data/README.md
@@ -8,3 +8,4 @@ This module contains articles about Spring Boot with Spring Data
- [Rendering Exceptions in JSON with Spring](https://www.baeldung.com/spring-exceptions-json)
- [Disable Spring Data Auto Configuration](https://www.baeldung.com/spring-data-disable-auto-config)
- [Repositories with Multiple Spring Data Modules](https://www.baeldung.com/spring-multiple-data-modules)
+- [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor)
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/PropertyEditorApplication.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/PropertyEditorApplication.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/PropertyEditorApplication.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/PropertyEditorApplication.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/PropertyEditorRestController.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/PropertyEditorRestController.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/PropertyEditorRestController.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/PropertyEditorRestController.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCard.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCard.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCard.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCard.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCardEditor.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCardEditor.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCardEditor.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/creditcard/CreditCardEditor.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/exotictype/editor/CustomExoticTypeEditor.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/exotictype/editor/CustomExoticTypeEditor.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/exotictype/editor/CustomExoticTypeEditor.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/exotictype/editor/CustomExoticTypeEditor.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/propertyeditor/exotictype/model/ExoticType.java b/spring-boot-data/src/main/java/com/baeldung/propertyeditor/exotictype/model/ExoticType.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/propertyeditor/exotictype/model/ExoticType.java
rename to spring-boot-data/src/main/java/com/baeldung/propertyeditor/exotictype/model/ExoticType.java
diff --git a/spring-resttemplate/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java b/spring-boot-data/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
similarity index 100%
rename from spring-resttemplate/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
rename to spring-boot-data/src/test/java/com/baeldung/propertyeditor/creditcard/CreditCardEditorUnitTest.java
diff --git a/spring-boot-di/src/test/java/com/baeldung/componentscan/filter/assignable/ComponentScanAssignableTypeFilterAppIntegrationTest.java b/spring-boot-di/src/test/java/com/baeldung/componentscan/filter/assignable/ComponentScanAssignableTypeFilterAppIntegrationTest.java
index 3e5c7ee4f7..edd82f435c 100644
--- a/spring-boot-di/src/test/java/com/baeldung/componentscan/filter/assignable/ComponentScanAssignableTypeFilterAppIntegrationTest.java
+++ b/spring-boot-di/src/test/java/com/baeldung/componentscan/filter/assignable/ComponentScanAssignableTypeFilterAppIntegrationTest.java
@@ -19,7 +19,7 @@ import static org.hamcrest.CoreMatchers.*;
public class ComponentScanAssignableTypeFilterAppIntegrationTest {
@Test
- public void whenAssignableTypeFilterIsUsed_thenComponentScanShouldRegisterBeanOfAssignableTypeAndItsSubClass() {
+ public void whenAssignableTypeFilterIsUsed_thenComponentScanShouldRegisterBean() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanAssignableTypeFilterApp.class);
List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
.filter(bean -> !bean.contains("org.springframework") && !bean.contains("componentScanAssignableTypeFilterApp"))
diff --git a/spring-boot-runtime/README.md b/spring-boot-runtime/README.md
index d3dc19493d..a544faf830 100644
--- a/spring-boot-runtime/README.md
+++ b/spring-boot-runtime/README.md
@@ -7,4 +7,8 @@ This module contains articles about administering a Spring Boot runtime
- [Programmatically Restarting a Spring Boot Application](https://www.baeldung.com/java-restart-spring-boot-app)
- [Logging HTTP Requests with Spring Boot Actuator HTTP Tracing](https://www.baeldung.com/spring-boot-actuator-http)
- [How to Disable Console Logging in Spring Boot](https://www.baeldung.com/spring-boot-disable-console-logging)
- - [Spring Boot Embedded Tomcat Logs](https://www.baeldung.com/spring-boot-embedded-tomcat-logs)
\ No newline at end of file
+ - [Spring Boot Embedded Tomcat Logs](https://www.baeldung.com/spring-boot-embedded-tomcat-logs)
+ - [How to Change the Default Port in Spring Boot](https://www.baeldung.com/spring-boot-change-port)
+ - [Project Configuration with Spring](https://www.baeldung.com/project-configuration-with-spring)
+ - [CORS with Spring](https://www.baeldung.com/spring-cors)
+ - [Spring – Log Incoming Requests](https://www.baeldung.com/spring-http-logging)
\ No newline at end of file
diff --git a/spring-boot-runtime/pom.xml b/spring-boot-runtime/pom.xml
index dca9b47410..772fd20d9e 100644
--- a/spring-boot-runtime/pom.xml
+++ b/spring-boot-runtime/pom.xml
@@ -32,6 +32,12 @@
spring-boot-starter-test
test
+
+
+ commons-io
+ commons-io
+ 2.6
+
org.springframework.boot
@@ -57,6 +63,10 @@
spring-boot-admin-starter-client
${spring-boot-admin-starter-client.version}
+
+ org.springframework.security
+ spring-security-test
+
com.h2database
diff --git a/spring-resttemplate/src/main/java/com/baeldung/changeport/CustomApplication.java b/spring-boot-runtime/src/main/java/com/baeldung/changeport/CustomApplication.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/changeport/CustomApplication.java
rename to spring-boot-runtime/src/main/java/com/baeldung/changeport/CustomApplication.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/changeport/ServerPortCustomizer.java b/spring-boot-runtime/src/main/java/com/baeldung/changeport/ServerPortCustomizer.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/changeport/ServerPortCustomizer.java
rename to spring-boot-runtime/src/main/java/com/baeldung/changeport/ServerPortCustomizer.java
diff --git a/spring-rest-simple/src/main/java/com/baeldung/cors/Account.java b/spring-boot-runtime/src/main/java/com/baeldung/cors/Account.java
similarity index 100%
rename from spring-rest-simple/src/main/java/com/baeldung/cors/Account.java
rename to spring-boot-runtime/src/main/java/com/baeldung/cors/Account.java
diff --git a/spring-rest-simple/src/main/java/com/baeldung/cors/AccountController.java b/spring-boot-runtime/src/main/java/com/baeldung/cors/AccountController.java
similarity index 100%
rename from spring-rest-simple/src/main/java/com/baeldung/cors/AccountController.java
rename to spring-boot-runtime/src/main/java/com/baeldung/cors/AccountController.java
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/MainApplication.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/MainApplication.java
new file mode 100644
index 0000000000..507f340e9d
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/MainApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.sampleapp.config;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@EnableAutoConfiguration
+@ComponentScan("com.baeldung.sampleapp")
+public class MainApplication implements WebMvcConfigurer {
+
+ public static void main(final String[] args) {
+ SpringApplication.run(MainApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/RestClientConfig.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/RestClientConfig.java
new file mode 100644
index 0000000000..cbaa21f4ca
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/RestClientConfig.java
@@ -0,0 +1,29 @@
+package com.baeldung.sampleapp.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.RestTemplate;
+
+import com.baeldung.sampleapp.interceptors.RestTemplateHeaderModifierInterceptor;
+
+@Configuration
+public class RestClientConfig {
+
+ @Bean
+ public RestTemplate restTemplate() {
+ RestTemplate restTemplate = new RestTemplate();
+
+ List interceptors = restTemplate.getInterceptors();
+ if (CollectionUtils.isEmpty(interceptors)) {
+ interceptors = new ArrayList();
+ }
+ interceptors.add(new RestTemplateHeaderModifierInterceptor());
+ restTemplate.setInterceptors(interceptors);
+ return restTemplate;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/WebConfig.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/WebConfig.java
new file mode 100644
index 0000000000..dc4fb9c695
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/config/WebConfig.java
@@ -0,0 +1,42 @@
+package com.baeldung.sampleapp.config;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/*
+ * Please note that main web configuration is in src/main/webapp/WEB-INF/api-servlet.xml
+ */
+@Configuration
+@EnableWebMvc
+@ComponentScan({ "com.baeldung.sampleapp.web" })
+public class WebConfig implements WebMvcConfigurer {
+
+ public WebConfig() {
+ super();
+ }
+
+ /*
+ @Override
+ public void configureMessageConverters(final List> messageConverters) {
+ final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
+ builder.indentOutput(true)
+ .dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm"));
+ messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
+ // messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
+
+ // messageConverters.add(new MappingJackson2HttpMessageConverter());
+
+ // messageConverters.add(new ProtobufHttpMessageConverter());
+
+ }
+
+ */
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/interceptors/RestTemplateHeaderModifierInterceptor.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/interceptors/RestTemplateHeaderModifierInterceptor.java
new file mode 100644
index 0000000000..9ebe1553a5
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/interceptors/RestTemplateHeaderModifierInterceptor.java
@@ -0,0 +1,18 @@
+package com.baeldung.sampleapp.interceptors;
+
+import java.io.IOException;
+
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+public class RestTemplateHeaderModifierInterceptor implements ClientHttpRequestInterceptor {
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+ ClientHttpResponse response = execution.execute(request, body);
+ response.getHeaders().add("Foo", "bar");
+ return response;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/repository/HeavyResourceRepository.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/repository/HeavyResourceRepository.java
new file mode 100644
index 0000000000..ea9541c31a
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/repository/HeavyResourceRepository.java
@@ -0,0 +1,28 @@
+package com.baeldung.sampleapp.repository;
+
+import java.util.Map;
+
+import com.baeldung.sampleapp.web.dto.HeavyResource;
+import com.baeldung.sampleapp.web.dto.HeavyResourceAddressOnly;
+
+public class HeavyResourceRepository {
+
+ public void save(HeavyResource heavyResource) {
+ }
+
+ public void save(HeavyResourceAddressOnly partialUpdate) {
+
+ }
+
+ public void save(Map updates, String id) {
+
+ }
+
+ public void save(HeavyResource heavyResource, String id) {
+
+ }
+
+ public void save(HeavyResourceAddressOnly partialUpdate, String id) {
+
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/BarMappingExamplesController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/BarMappingExamplesController.java
new file mode 100644
index 0000000000..c6b8d23944
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/BarMappingExamplesController.java
@@ -0,0 +1,47 @@
+package com.baeldung.sampleapp.web.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping(value = "/ex")
+public class BarMappingExamplesController {
+
+ public BarMappingExamplesController() {
+ super();
+ }
+
+ // API
+
+ // with @RequestParam
+
+ @RequestMapping(value = "/bars")
+ @ResponseBody
+ public String getBarBySimplePathWithRequestParam(@RequestParam("id") final long id) {
+ return "Get a specific Bar with id=" + id;
+ }
+
+ @RequestMapping(value = "/bars", params = "id")
+ @ResponseBody
+ public String getBarBySimplePathWithExplicitRequestParam(@RequestParam("id") final long id) {
+ return "Get a specific Bar with id=" + id;
+ }
+
+ @RequestMapping(value = "/bars", params = { "id", "second" })
+ @ResponseBody
+ public String getBarBySimplePathWithExplicitRequestParams(@RequestParam("id") final long id) {
+ return "Get a specific Bar with id=" + id;
+ }
+
+ // with @PathVariable
+
+ @RequestMapping(value = "/bars/{numericId:[\\d]+}")
+ @ResponseBody
+ public String getBarsBySimplePathWithPathVariable(@PathVariable final long numericId) {
+ return "Get a specific Bar with id=" + numericId;
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/CompanyController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/CompanyController.java
new file mode 100644
index 0000000000..bfda2fe0d6
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/CompanyController.java
@@ -0,0 +1,17 @@
+package com.baeldung.sampleapp.web.controller;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.sampleapp.web.dto.Company;
+
+@RestController
+public class CompanyController {
+
+ @RequestMapping(value = "/companyRest", produces = MediaType.APPLICATION_JSON_VALUE)
+ public Company getCompanyRest() {
+ final Company company = new Company(1, "Xpto");
+ return company;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/DeferredResultController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/DeferredResultController.java
new file mode 100644
index 0000000000..8f4eb3218a
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/DeferredResultController.java
@@ -0,0 +1,85 @@
+package com.baeldung.sampleapp.web.controller;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.context.request.async.DeferredResult;
+
+@RestController
+public class DeferredResultController {
+
+ private final static Logger LOG = LoggerFactory.getLogger(DeferredResultController.class);
+
+ @GetMapping("/async-deferredresult")
+ public DeferredResult> handleReqDefResult(Model model) {
+ LOG.info("Received request");
+ DeferredResult> deferredResult = new DeferredResult<>();
+
+ deferredResult.onCompletion(() -> LOG.info("Processing complete"));
+
+ CompletableFuture.supplyAsync(() -> {
+ LOG.info("Processing in separate thread");
+ try {
+ Thread.sleep(6000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return "OK";
+ })
+ .whenCompleteAsync((result, exc) -> deferredResult.setResult(ResponseEntity.ok(result)));
+
+ LOG.info("Servlet thread freed");
+ return deferredResult;
+ }
+
+ @GetMapping("/process-blocking")
+ public ResponseEntity> handleReqSync(Model model) {
+ // ...
+ return ResponseEntity.ok("ok");
+ }
+
+ @GetMapping("/async-deferredresult-timeout")
+ public DeferredResult> handleReqWithTimeouts(Model model) {
+ LOG.info("Received async request with a configured timeout");
+ DeferredResult> deferredResult = new DeferredResult<>(500l);
+ deferredResult.onTimeout(() -> deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT)
+ .body("Request timeout occurred.")));
+
+ CompletableFuture.supplyAsync(() -> {
+ LOG.info("Processing in separate thread");
+ try {
+ Thread.sleep(6000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return "error";
+ })
+ .whenCompleteAsync((result, exc) -> deferredResult.setResult(ResponseEntity.ok(result)));
+ LOG.info("servlet thread freed");
+ return deferredResult;
+ }
+
+ @GetMapping("/async-deferredresult-error")
+ public DeferredResult> handleAsyncFailedRequest(Model model) {
+ LOG.info("Received async request with a configured error handler");
+ DeferredResult> deferredResult = new DeferredResult<>();
+ deferredResult.onError(new Consumer() {
+ @Override
+ public void accept(Throwable t) {
+ deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body("An error occurred."));
+ }
+
+ });
+ LOG.info("servlet thread freed");
+ return deferredResult;
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/HeavyResourceController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/HeavyResourceController.java
new file mode 100644
index 0000000000..8156fc14a9
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/HeavyResourceController.java
@@ -0,0 +1,42 @@
+package com.baeldung.sampleapp.web.controller;
+
+
+import java.util.Map;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.sampleapp.repository.HeavyResourceRepository;
+import com.baeldung.sampleapp.web.dto.HeavyResource;
+import com.baeldung.sampleapp.web.dto.HeavyResourceAddressOnly;
+
+@RestController
+public class HeavyResourceController {
+
+ private HeavyResourceRepository heavyResourceRepository = new HeavyResourceRepository();
+
+ @RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> saveResource(@RequestBody HeavyResource heavyResource, @PathVariable("id") String id) {
+ heavyResourceRepository.save(heavyResource, id);
+ return ResponseEntity.ok("resource saved");
+ }
+
+ @RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> partialUpdateName(@RequestBody HeavyResourceAddressOnly partialUpdate, @PathVariable("id") String id) {
+ heavyResourceRepository.save(partialUpdate, id);
+ return ResponseEntity.ok("resource address updated");
+ }
+
+ @RequestMapping(value = "/heavyresource2/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> partialUpdateGeneric(@RequestBody Map updates,
+ @PathVariable("id") String id) {
+ heavyResourceRepository.save(updates, id);
+ return ResponseEntity.ok("resource updated");
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/ItemController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/ItemController.java
new file mode 100644
index 0000000000..69bd458968
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/ItemController.java
@@ -0,0 +1,39 @@
+package com.baeldung.sampleapp.web.controller;
+
+import java.util.Date;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.sampleapp.web.dto.Item;
+import com.baeldung.sampleapp.web.dto.ItemManager;
+import com.baeldung.sampleapp.web.dto.Views;
+import com.fasterxml.jackson.annotation.JsonView;
+
+@RestController
+public class ItemController {
+
+ @JsonView(Views.Public.class)
+ @RequestMapping("/items/{id}")
+ public Item getItemPublic(@PathVariable final int id) {
+ return ItemManager.getById(id);
+ }
+
+ @JsonView(Views.Internal.class)
+ @RequestMapping("/items/internal/{id}")
+ public Item getItemInternal(@PathVariable final int id) {
+ return ItemManager.getById(id);
+ }
+
+ @RequestMapping("/date")
+ public Date getCurrentDate() throws Exception {
+ return new Date();
+ }
+
+ @RequestMapping("/delay/{seconds}")
+ public void getCurrentTime(@PathVariable final int seconds) throws Exception {
+
+ Thread.sleep(seconds * 1000);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/MyFooController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/MyFooController.java
new file mode 100644
index 0000000000..11ea5b70c9
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/MyFooController.java
@@ -0,0 +1,85 @@
+package com.baeldung.sampleapp.web.controller;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+import com.baeldung.sampleapp.web.dto.Foo;
+import com.baeldung.sampleapp.web.exception.ResourceNotFoundException;
+
+@Controller
+@RequestMapping(value = "/foos")
+public class MyFooController {
+
+ private final Map myfoos;
+
+ public MyFooController() {
+ super();
+ myfoos = new HashMap();
+ myfoos.put(1L, new Foo(1L, "sample foo"));
+ }
+
+ // API - read
+
+ @RequestMapping(method = RequestMethod.GET, produces = { "application/json" })
+ @ResponseBody
+ public Collection findAll() {
+ return myfoos.values();
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = { "application/json" })
+ @ResponseBody
+ public Foo findById(@PathVariable final long id) {
+ final Foo foo = myfoos.get(id);
+ if (foo == null) {
+ throw new ResourceNotFoundException();
+ }
+ return foo;
+ }
+
+ // API - write
+
+ @RequestMapping(method = RequestMethod.PUT, value = "/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ @ResponseBody
+ public Foo updateFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) {
+ myfoos.put(id, foo);
+ return foo;
+ }
+
+ @RequestMapping(method = RequestMethod.PATCH, value = "/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ public void updateFoo2(@PathVariable("id") final long id, @RequestBody final Foo foo) {
+ myfoos.put(id, foo);
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ @ResponseStatus(HttpStatus.CREATED)
+ @ResponseBody
+ public Foo createFoo(@RequestBody final Foo foo, HttpServletResponse response) {
+ myfoos.put(foo.getId(), foo);
+ response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentRequest()
+ .path("/" + foo.getId())
+ .toUriString());
+ return foo;
+ }
+
+ @RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ public void deleteById(@PathVariable final long id) {
+ myfoos.remove(id);
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/PactController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/PactController.java
new file mode 100644
index 0000000000..0f5d7f1acb
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/PactController.java
@@ -0,0 +1,33 @@
+package com.baeldung.sampleapp.web.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.sampleapp.web.dto.PactDto;
+
+@RestController
+public class PactController {
+
+ List pacts = new ArrayList<>();
+
+ @GetMapping(value = "/pact", produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public PactDto getPact() {
+ return new PactDto(true, "tom");
+ }
+
+ @PostMapping("/pact")
+ @ResponseStatus(HttpStatus.CREATED)
+ public void createPact(PactDto pact) {
+ pacts.add(pact);
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/SimplePostController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/SimplePostController.java
new file mode 100644
index 0000000000..7b57d35088
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/SimplePostController.java
@@ -0,0 +1,74 @@
+package com.baeldung.sampleapp.web.controller;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.baeldung.sampleapp.web.dto.Foo;
+
+// used to test HttpClientPostingTest
+@RestController
+public class SimplePostController {
+
+ @RequestMapping(value = "/users", method = RequestMethod.POST)
+ public String postUser(@RequestParam final String username, @RequestParam final String password) {
+ return "Success" + username;
+ }
+
+ @RequestMapping(value = "/users/detail", method = RequestMethod.POST)
+ public String postUserDetail(@RequestBody final Foo entity) {
+ return "Success" + entity.getId();
+ }
+
+ @RequestMapping(value = "/users/multipart", method = RequestMethod.POST)
+ public String uploadFile(@RequestParam final String username, @RequestParam final String password, @RequestParam("file") final MultipartFile file) {
+ if (!file.isEmpty()) {
+ try {
+ final DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH.mm.ss");
+ final String fileName = dateFormat.format(new Date());
+ final File fileServer = new File(fileName);
+ fileServer.createNewFile();
+ final byte[] bytes = file.getBytes();
+ final BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(fileServer));
+ stream.write(bytes);
+ stream.close();
+ return "You successfully uploaded " + username;
+ } catch (final Exception e) {
+ return "You failed to upload " + e.getMessage();
+ }
+ } else {
+ return "You failed to upload because the file was empty.";
+ }
+ }
+
+ @RequestMapping(value = "/users/upload", method = RequestMethod.POST)
+ public String postMultipart(@RequestParam("file") final MultipartFile file) {
+ if (!file.isEmpty()) {
+ try {
+ final DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH.mm.ss");
+ final String fileName = dateFormat.format(new Date());
+ final File fileServer = new File(fileName);
+ fileServer.createNewFile();
+ final byte[] bytes = file.getBytes();
+ final BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(fileServer));
+ stream.write(bytes);
+ stream.close();
+ return "You successfully uploaded ";
+ } catch (final Exception e) {
+ return "You failed to upload " + e.getMessage();
+ }
+ } else {
+ return "You failed to upload because the file was empty.";
+ }
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/mediatypes/CustomMediaTypeController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/mediatypes/CustomMediaTypeController.java
new file mode 100644
index 0000000000..fc73bade87
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/mediatypes/CustomMediaTypeController.java
@@ -0,0 +1,25 @@
+package com.baeldung.sampleapp.web.controller.mediatypes;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.sampleapp.web.dto.BaeldungItem;
+import com.baeldung.sampleapp.web.dto.BaeldungItemV2;
+
+@RestController
+@RequestMapping(value = "/", produces = "application/vnd.baeldung.api.v1+json")
+public class CustomMediaTypeController {
+
+ @RequestMapping(method = RequestMethod.GET, value = "/public/api/items/{id}", produces = "application/vnd.baeldung.api.v1+json")
+ public @ResponseBody BaeldungItem getItem(@PathVariable("id") String id) {
+ return new BaeldungItem("itemId1");
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/public/api/items/{id}", produces = "application/vnd.baeldung.api.v2+json")
+ public @ResponseBody BaeldungItemV2 getItemSecondAPIVersion(@PathVariable("id") String id) {
+ return new BaeldungItemV2("itemName");
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java
new file mode 100644
index 0000000000..321f3be3ef
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java
@@ -0,0 +1,68 @@
+package com.baeldung.sampleapp.web.controller.redirect;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import org.springframework.web.servlet.view.RedirectView;
+
+@Controller
+@RequestMapping("/")
+public class RedirectController {
+
+ @RequestMapping(value = "/redirectWithXMLConfig", method = RequestMethod.GET)
+ public ModelAndView redirectWithUsingXMLConfig(final ModelMap model) {
+ model.addAttribute("attribute", "redirectWithXMLConfig");
+ return new ModelAndView("RedirectedUrl", model);
+ }
+
+ @RequestMapping(value = "/redirectWithRedirectPrefix", method = RequestMethod.GET)
+ public ModelAndView redirectWithUsingRedirectPrefix(final ModelMap model) {
+ model.addAttribute("attribute", "redirectWithRedirectPrefix");
+ return new ModelAndView("redirect:/redirectedUrl", model);
+ }
+
+ @RequestMapping(value = "/redirectWithRedirectAttributes", method = RequestMethod.GET)
+ public RedirectView redirectWithRedirectAttributes(final RedirectAttributes redirectAttributes) {
+ redirectAttributes.addFlashAttribute("flashAttribute", "redirectWithRedirectAttributes");
+ redirectAttributes.addAttribute("attribute", "redirectWithRedirectAttributes");
+ return new RedirectView("redirectedUrl");
+ }
+
+ @RequestMapping(value = "/redirectWithRedirectView", method = RequestMethod.GET)
+ public RedirectView redirectWithUsingRedirectView(final ModelMap model) {
+ model.addAttribute("attribute", "redirectWithRedirectView");
+ return new RedirectView("redirectedUrl");
+ }
+
+ @RequestMapping(value = "/forwardWithForwardPrefix", method = RequestMethod.GET)
+ public ModelAndView forwardWithUsingForwardPrefix(final ModelMap model) {
+ model.addAttribute("attribute", "redirectWithForwardPrefix");
+ return new ModelAndView("forward:/redirectedUrl", model);
+ }
+
+ @RequestMapping(value = "/redirectedUrl", method = RequestMethod.GET)
+ public ModelAndView redirection(final ModelMap model, @ModelAttribute("flashAttribute") final Object flashAttribute) {
+ model.addAttribute("redirectionAttribute", flashAttribute);
+ return new ModelAndView("redirection", model);
+ }
+
+ @RequestMapping(value = "/redirectPostToPost", method = RequestMethod.POST)
+ public ModelAndView redirectPostToPost(HttpServletRequest request) {
+ request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
+ return new ModelAndView("redirect:/redirectedPostToPost");
+ }
+
+ @RequestMapping(value = "/redirectedPostToPost", method = RequestMethod.POST)
+ public ModelAndView redirectedPostToPost() {
+ return new ModelAndView("redirection");
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItem.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItem.java
new file mode 100644
index 0000000000..807a254cfc
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItem.java
@@ -0,0 +1,13 @@
+package com.baeldung.sampleapp.web.dto;
+
+public class BaeldungItem {
+ private final String itemId;
+
+ public BaeldungItem(String itemId) {
+ this.itemId = itemId;
+ }
+
+ public String getItemId() {
+ return itemId;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItemV2.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItemV2.java
new file mode 100644
index 0000000000..f84591ea43
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/BaeldungItemV2.java
@@ -0,0 +1,14 @@
+package com.baeldung.sampleapp.web.dto;
+
+
+public class BaeldungItemV2 {
+ private final String itemName;
+
+ public BaeldungItemV2(String itemName) {
+ this.itemName = itemName;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Company.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Company.java
new file mode 100644
index 0000000000..6cfcc079d9
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Company.java
@@ -0,0 +1,38 @@
+package com.baeldung.sampleapp.web.dto;
+
+public class Company {
+
+ private long id;
+ private String name;
+
+ public Company() {
+ super();
+ }
+
+ public Company(final long id, final String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "Company [id=" + id + ", name=" + name + "]";
+ }
+
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java
new file mode 100644
index 0000000000..de1d76ed92
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java
@@ -0,0 +1,42 @@
+package com.baeldung.sampleapp.web.dto;
+
+public class Foo {
+ private long id;
+ private String name;
+
+ public Foo() {
+ super();
+ }
+
+ public Foo(final String name) {
+ super();
+
+ this.name = name;
+ }
+
+ public Foo(final long id, final String name) {
+ super();
+
+ this.id = id;
+ this.name = name;
+ }
+
+ // API
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResource.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResource.java
new file mode 100644
index 0000000000..2821341888
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResource.java
@@ -0,0 +1,62 @@
+package com.baeldung.sampleapp.web.dto;
+
+
+public class HeavyResource {
+ private Integer id;
+ private String name;
+ private String surname;
+ private Integer age;
+ private String address;
+
+
+ public HeavyResource() {
+ }
+
+ public HeavyResource(Integer id, String name, String surname, Integer age, String address) {
+ this.id = id;
+ this.name = name;
+ this.surname = surname;
+ this.age = age;
+ this.address = address;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressOnly.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressOnly.java
new file mode 100644
index 0000000000..01ee6e7dd4
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressOnly.java
@@ -0,0 +1,31 @@
+package com.baeldung.sampleapp.web.dto;
+
+
+public class HeavyResourceAddressOnly {
+ private Integer id;
+ private String address;
+
+ public HeavyResourceAddressOnly() {
+ }
+
+ public HeavyResourceAddressOnly(Integer id, String address) {
+ this.id = id;
+ this.address = address;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressPartialUpdate.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressPartialUpdate.java
new file mode 100644
index 0000000000..1832a1a58b
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/HeavyResourceAddressPartialUpdate.java
@@ -0,0 +1,31 @@
+package com.baeldung.sampleapp.web.dto;
+
+
+public class HeavyResourceAddressPartialUpdate {
+ private Integer id;
+ private String address;
+
+ public HeavyResourceAddressPartialUpdate() {
+ }
+
+ public HeavyResourceAddressPartialUpdate(Integer id, String address) {
+ this.id = id;
+ this.address = address;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Item.java
similarity index 94%
rename from jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java
rename to spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Item.java
index 26d20d4847..a4fcef5dce 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Item.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.jsonview;
+package com.baeldung.sampleapp.web.dto;
import com.fasterxml.jackson.annotation.JsonView;
@@ -33,4 +33,4 @@ public class Item {
public String getOwnerName() {
return ownerName;
}
-}
+}
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/ItemManager.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/ItemManager.java
new file mode 100644
index 0000000000..0009c0180b
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/ItemManager.java
@@ -0,0 +1,9 @@
+package com.baeldung.sampleapp.web.dto;
+
+public class ItemManager {
+
+ public static Item getById(final int id) {
+ final Item item = new Item(2, "book", "John");
+ return item;
+ }
+}
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/PactDto.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/PactDto.java
new file mode 100644
index 0000000000..e184119611
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/PactDto.java
@@ -0,0 +1,33 @@
+package com.baeldung.sampleapp.web.dto;
+
+public class PactDto {
+
+ private boolean condition;
+ private String name;
+
+ public PactDto() {
+ }
+
+ public PactDto(boolean condition, String name) {
+ super();
+ this.condition = condition;
+ this.name = name;
+ }
+
+ public boolean isCondition() {
+ return condition;
+ }
+
+ public void setCondition(boolean condition) {
+ this.condition = condition;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Views.java
similarity index 75%
rename from jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java
rename to spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Views.java
index 65950b7f9f..e2d83fda22 100644
--- a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/dto/Views.java
@@ -1,4 +1,4 @@
-package com.baeldung.jackson.jsonview;
+package com.baeldung.sampleapp.web.dto;
public class Views {
public static class Public {
diff --git a/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/exception/ResourceNotFoundException.java b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/exception/ResourceNotFoundException.java
new file mode 100644
index 0000000000..69532f196d
--- /dev/null
+++ b/spring-boot-runtime/src/main/java/com/baeldung/sampleapp/web/exception/ResourceNotFoundException.java
@@ -0,0 +1,8 @@
+package com.baeldung.sampleapp.web.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(value = HttpStatus.NOT_FOUND)
+public class ResourceNotFoundException extends RuntimeException {
+}
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/app/Application.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java
similarity index 94%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/app/Application.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java
index 6e2607339c..f20fba737a 100644
--- a/spring-resttemplate/src/main/java/com/baeldung/web/log/app/Application.java
+++ b/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java
@@ -11,6 +11,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.context.annotation.PropertySource;
import com.baeldung.web.log.config.CustomeRequestLoggingFilter;
@@ -18,6 +19,7 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
@EnableAutoConfiguration
@ComponentScan("com.baeldung.web.log")
+@PropertySource("application-log.properties")
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/controller/TaxiFareController.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/controller/TaxiFareController.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/controller/TaxiFareController.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/controller/TaxiFareController.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/data/RateCard.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/data/RateCard.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/data/RateCard.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/data/RateCard.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/data/TaxiRide.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/data/TaxiRide.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/data/TaxiRide.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/data/TaxiRide.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/service/TaxiFareCalculatorService.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/service/TaxiFareCalculatorService.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/service/TaxiFareCalculatorService.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/service/TaxiFareCalculatorService.java
diff --git a/spring-resttemplate/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java b/spring-boot-runtime/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java
similarity index 100%
rename from spring-resttemplate/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java
rename to spring-boot-runtime/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java
diff --git a/spring-boot-runtime/src/main/resources/application-log.properties b/spring-boot-runtime/src/main/resources/application-log.properties
new file mode 100644
index 0000000000..1a26e3ad99
--- /dev/null
+++ b/spring-boot-runtime/src/main/resources/application-log.properties
@@ -0,0 +1,2 @@
+server.port=8082
+server.servlet.context-path=/spring-rest
\ No newline at end of file
diff --git a/spring-boot-runtime/src/main/resources/application-logging.properties b/spring-boot-runtime/src/main/resources/application-logging.properties
index 338251cf9b..d3bdaa00b7 100644
--- a/spring-boot-runtime/src/main/resources/application-logging.properties
+++ b/spring-boot-runtime/src/main/resources/application-logging.properties
@@ -20,3 +20,4 @@ spring.application.name=spring-boot-management
server.port=8081
+
diff --git a/spring-rest/src/main/webapp/WEB-INF/api-servlet.xml b/spring-boot-runtime/src/main/webapp/WEB-INF/api-servlet.xml
similarity index 100%
rename from spring-rest/src/main/webapp/WEB-INF/api-servlet.xml
rename to spring-boot-runtime/src/main/webapp/WEB-INF/api-servlet.xml
diff --git a/spring-rest/src/main/webapp/WEB-INF/company.html b/spring-boot-runtime/src/main/webapp/WEB-INF/company.html
similarity index 100%
rename from spring-rest/src/main/webapp/WEB-INF/company.html
rename to spring-boot-runtime/src/main/webapp/WEB-INF/company.html
diff --git a/spring-rest/src/main/webapp/WEB-INF/spring-views.xml b/spring-boot-runtime/src/main/webapp/WEB-INF/spring-views.xml
similarity index 100%
rename from spring-rest/src/main/webapp/WEB-INF/spring-views.xml
rename to spring-boot-runtime/src/main/webapp/WEB-INF/spring-views.xml
diff --git a/spring-rest/src/main/webapp/WEB-INF/web.xml b/spring-boot-runtime/src/main/webapp/WEB-INF/web.xml
similarity index 100%
rename from spring-rest/src/main/webapp/WEB-INF/web.xml
rename to spring-boot-runtime/src/main/webapp/WEB-INF/web.xml
diff --git a/spring-resttemplate/src/test/java/com/baeldung/web/controller/HeavyResourceControllerIntegrationTest.java b/spring-boot-runtime/src/test/java/com/baeldung/web/controller/HeavyResourceControllerIntegrationTest.java
similarity index 100%
rename from spring-resttemplate/src/test/java/com/baeldung/web/controller/HeavyResourceControllerIntegrationTest.java
rename to spring-boot-runtime/src/test/java/com/baeldung/web/controller/HeavyResourceControllerIntegrationTest.java
diff --git a/spring-resttemplate/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java b/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java
similarity index 56%
rename from spring-resttemplate/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java
rename to spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java
index 1cc098abf1..97d669d3fa 100644
--- a/spring-resttemplate/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java
+++ b/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java
@@ -7,14 +7,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.context.annotation.Configuration;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import com.baeldung.web.log.app.Application;
import com.baeldung.web.log.data.TaxiRide;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = { Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@SpringBootTest(classes = { Application.class, TaxiFareControllerIntegrationTest.SecurityConfig.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TaxiFareControllerIntegrationTest {
@LocalServerPort
@@ -22,7 +25,8 @@ public class TaxiFareControllerIntegrationTest {
@Test
public void givenRequest_whenFetchTaxiFareRateCard_thanOK() {
-
+
+ System.out.println(port);
String URL = "http://localhost:" + port + "/spring-rest";
TestRestTemplate testRestTemplate = new TestRestTemplate();
TaxiRide taxiRide = new TaxiRide(true, 10l);
@@ -32,4 +36,17 @@ public class TaxiFareControllerIntegrationTest {
assertThat(fare, equalTo("200"));
}
+
+ @Configuration
+ static class SecurityConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ System.out.println("security being set");
+ http
+ .authorizeRequests()
+ .anyRequest().permitAll()
+ .and()
+ .csrf().disable();
+ }
+ }
}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-aws/src/main/resources/application.properties b/spring-cloud/spring-cloud-aws/src/main/resources/application.properties
index a769b70ddd..690eda13a2 100644
--- a/spring-cloud/spring-cloud-aws/src/main/resources/application.properties
+++ b/spring-cloud/spring-cloud-aws/src/main/resources/application.properties
@@ -10,5 +10,5 @@ cloud.aws.rds.spring-cloud-test-db.username=testuser
cloud.aws.rds.spring-cloud-test-db.readReplicaSupport=true
cloud.aws.rds.spring-cloud-test-db.databaseName=test
-# Disable auto cloudfromation
+# Disable auto cloudformation
cloud.aws.stack.auto=false
diff --git a/spring-cloud/spring-cloud-eureka-self-preservation/README.md b/spring-cloud/spring-cloud-eureka-self-preservation/README.md
new file mode 100644
index 0000000000..52e321b1cb
--- /dev/null
+++ b/spring-cloud/spring-cloud-eureka-self-preservation/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Guide to Eureka Self Preservation and Renewal](https://www.baeldung.com/eureka-self-preservation-renewal)
diff --git a/spring-cloud/spring-cloud-gateway/pom.xml b/spring-cloud/spring-cloud-gateway/pom.xml
index c297d90896..61f0267ba0 100644
--- a/spring-cloud/spring-cloud-gateway/pom.xml
+++ b/spring-cloud/spring-cloud-gateway/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
spring-cloud-gateway
@@ -17,8 +18,25 @@
org.springframework.cloud
- spring-cloud-gateway
- ${cloud.version}
+ spring-cloud-dependencies
+ ${spring-cloud-dependencies.version}
+ pom
+ import
+
+
+
+
+ org.junit
+ junit-bom
+ 5.5.2
+ pom
+ import
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
pom
import
@@ -28,20 +46,7 @@
org.springframework.cloud
- spring-cloud-starter
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.boot
- spring-boot-starter-webflux
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
+ spring-cloud-starter-gateway
@@ -54,13 +59,31 @@
validation-api
- io.projectreactor.ipc
- reactor-netty
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
- 2.0.1.RELEASE
+ Greenwich.SR3
+
+
+ 2.1.9.RELEASE
6.0.2.Final
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/SecondServiceApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/SecondServiceApplication.java
new file mode 100644
index 0000000000..69be1be9ca
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/SecondServiceApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.secondservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.PropertySource;
+
+@SpringBootApplication
+@PropertySource("classpath:secondservice-application.properties")
+public class SecondServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SecondServiceApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/web/SecondServiceRestController.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/web/SecondServiceRestController.java
new file mode 100644
index 0000000000..f047b123ef
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/secondservice/web/SecondServiceRestController.java
@@ -0,0 +1,18 @@
+package com.baeldung.secondservice.web;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import reactor.core.publisher.Mono;
+
+@RestController
+public class SecondServiceRestController {
+
+ @GetMapping("/resource/language")
+ public Mono> getResource() {
+ return Mono.just(ResponseEntity.ok()
+ .body("es"));
+
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/ServiceApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/ServiceApplication.java
new file mode 100644
index 0000000000..9853b78088
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/ServiceApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.service;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.PropertySource;
+
+@SpringBootApplication
+@PropertySource("classpath:service-application.properties")
+public class ServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/web/ServiceRestController.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/web/ServiceRestController.java
new file mode 100644
index 0000000000..12f7151e59
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/service/web/ServiceRestController.java
@@ -0,0 +1,22 @@
+package com.baeldung.service.web;
+
+import java.util.Locale;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import reactor.core.publisher.Mono;
+
+@RestController
+public class ServiceRestController {
+
+ @GetMapping("/resource")
+ public Mono> getResource() {
+ return Mono.just(ResponseEntity.ok()
+ .header(HttpHeaders.CONTENT_LANGUAGE, Locale.ENGLISH.getLanguage())
+ .body("Service Resource"));
+
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java
deleted file mode 100644
index ba384749df..0000000000
--- a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.baeldung.spring.cloud;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class GatewayApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(GatewayApplication.class, args);
- }
-
-}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersGatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersGatewayApplication.java
new file mode 100644
index 0000000000..a9f18e71fd
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersGatewayApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.springcloudgateway.customfilters;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.PropertySource;
+
+@SpringBootApplication
+@PropertySource("classpath:customfilters-global-application.properties")
+public class CustomFiltersGatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CustomFiltersGatewayApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/config/WebClientConfig.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/config/WebClientConfig.java
new file mode 100644
index 0000000000..8a7771f0e3
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/config/WebClientConfig.java
@@ -0,0 +1,16 @@
+package com.baeldung.springcloudgateway.customfilters.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Configuration
+public class WebClientConfig {
+
+ @Bean
+ WebClient client() {
+ return WebClient.builder()
+ .build();
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ChainRequestGatewayFilterFactory.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ChainRequestGatewayFilterFactory.java
new file mode 100644
index 0000000000..f7e754fd70
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ChainRequestGatewayFilterFactory.java
@@ -0,0 +1,90 @@
+package com.baeldung.springcloudgateway.customfilters.filters.factories;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale.LanguageRange;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFactory {
+
+ final Logger logger = LoggerFactory.getLogger(ChainRequestGatewayFilterFactory.class);
+
+ private final WebClient client;
+
+ public ChainRequestGatewayFilterFactory(WebClient client) {
+ super(Config.class);
+ this.client = client;
+ }
+
+ @Override
+ public List shortcutFieldOrder() {
+ return Arrays.asList("endpoint", "defaultLanguage");
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ return (exchange, chain) -> {
+ return client.get()
+ .uri(config.getEndpoint())
+ .exchange()
+ .flatMap(response -> {
+ return (response.statusCode()
+ .is2xxSuccessful()) ? response.bodyToMono(String.class) : Mono.just(config.getDefaultLanguage());
+ })
+ .map(LanguageRange::parse)
+ .map(range -> {
+ exchange.getRequest()
+ .mutate()
+ .headers(h -> h.setAcceptLanguage(range))
+ .build();
+
+ String allOutgoingRequestLanguages = exchange.getRequest()
+ .getHeaders()
+ .getAcceptLanguage()
+ .stream()
+ .map(r -> r.getRange())
+ .collect(Collectors.joining(","));
+
+ logger.info("Chain Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages);
+
+ return exchange;
+ })
+ .flatMap(chain::filter);
+
+ };
+ }
+
+ public static class Config {
+ private String endpoint;
+ private String defaultLanguage;
+
+ public Config() {
+ }
+
+ public String getEndpoint() {
+ return endpoint;
+ }
+
+ public void setEndpoint(String endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ public String getDefaultLanguage() {
+ return defaultLanguage;
+ }
+
+ public void setDefaultLanguage(String defaultLanguage) {
+ this.defaultLanguage = defaultLanguage;
+ }
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/LoggingGatewayFilterFactory.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/LoggingGatewayFilterFactory.java
new file mode 100644
index 0000000000..db73ba99c0
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/LoggingGatewayFilterFactory.java
@@ -0,0 +1,85 @@
+package com.baeldung.springcloudgateway.customfilters.filters.factories;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.stereotype.Component;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory {
+
+ final Logger logger = LoggerFactory.getLogger(LoggingGatewayFilterFactory.class);
+
+ public static final String BASE_MSG = "baseMessage";
+ public static final String PRE_LOGGER = "preLogger";
+ public static final String POST_LOGGER = "postLogger";
+
+ public LoggingGatewayFilterFactory() {
+ super(Config.class);
+ }
+
+ @Override
+ public List shortcutFieldOrder() {
+ return Arrays.asList(BASE_MSG, PRE_LOGGER, POST_LOGGER);
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ return new OrderedGatewayFilter((exchange, chain) -> {
+ if (config.isPreLogger())
+ logger.info("Pre GatewayFilter logging: " + config.getBaseMessage());
+ return chain.filter(exchange)
+ .then(Mono.fromRunnable(() -> {
+ if (config.isPostLogger())
+ logger.info("Post GatewayFilter logging: " + config.getBaseMessage());
+ }));
+ }, -2);
+ }
+
+ public static class Config {
+ private String baseMessage;
+ private boolean preLogger;
+ private boolean postLogger;
+
+ public Config() {
+ };
+
+ public Config(String baseMessage, boolean preLogger, boolean postLogger) {
+ super();
+ this.baseMessage = baseMessage;
+ this.preLogger = preLogger;
+ this.postLogger = postLogger;
+ }
+
+ public String getBaseMessage() {
+ return this.baseMessage;
+ }
+
+ public boolean isPreLogger() {
+ return preLogger;
+ }
+
+ public boolean isPostLogger() {
+ return postLogger;
+ }
+
+ public void setBaseMessage(String baseMessage) {
+ this.baseMessage = baseMessage;
+ }
+
+ public void setPreLogger(boolean preLogger) {
+ this.preLogger = preLogger;
+ }
+
+ public void setPostLogger(boolean postLogger) {
+ this.postLogger = postLogger;
+ }
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyRequestGatewayFilterFactory.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyRequestGatewayFilterFactory.java
new file mode 100644
index 0000000000..0f039bb41d
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyRequestGatewayFilterFactory.java
@@ -0,0 +1,78 @@
+package com.baeldung.springcloudgateway.customfilters.filters.factories;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory {
+
+ final Logger logger = LoggerFactory.getLogger(ModifyRequestGatewayFilterFactory.class);
+
+ public ModifyRequestGatewayFilterFactory() {
+ super(Config.class);
+ }
+
+ @Override
+ public List shortcutFieldOrder() {
+ return Arrays.asList("defaultLocale");
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ return (exchange, chain) -> {
+ if (exchange.getRequest()
+ .getHeaders()
+ .getAcceptLanguage()
+ .isEmpty()) {
+
+ String queryParamLocale = exchange.getRequest()
+ .getQueryParams()
+ .getFirst("locale");
+
+ Locale requestLocale = Optional.ofNullable(queryParamLocale)
+ .map(l -> Locale.forLanguageTag(l))
+ .orElse(config.getDefaultLocale());
+
+ exchange.getRequest()
+ .mutate()
+ .headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale)))
+ .build();
+ }
+
+ String allOutgoingRequestLanguages = exchange.getRequest()
+ .getHeaders()
+ .getAcceptLanguage()
+ .stream()
+ .map(range -> range.getRange())
+ .collect(Collectors.joining(","));
+
+ logger.info("Modify Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages);
+ return chain.filter(exchange);
+ };
+ }
+
+ public static class Config {
+ private Locale defaultLocale;
+
+ public Config() {
+ }
+
+ public Locale getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public void setDefaultLocale(String defaultLocale) {
+ this.defaultLocale = Locale.forLanguageTag(defaultLocale);
+ };
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyResponseGatewayFilterFactory.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyResponseGatewayFilterFactory.java
new file mode 100644
index 0000000000..55b39fce29
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/factories/ModifyResponseGatewayFilterFactory.java
@@ -0,0 +1,48 @@
+package com.baeldung.springcloudgateway.customfilters.filters.factories;
+
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class ModifyResponseGatewayFilterFactory extends AbstractGatewayFilterFactory {
+
+ final Logger logger = LoggerFactory.getLogger(ModifyResponseGatewayFilterFactory.class);
+
+ public ModifyResponseGatewayFilterFactory() {
+ super(Config.class);
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ return (exchange, chain) -> {
+ return chain.filter(exchange)
+ .then(Mono.fromRunnable(() -> {
+ ServerHttpResponse response = exchange.getResponse();
+
+ Optional.ofNullable(exchange.getRequest()
+ .getQueryParams()
+ .getFirst("locale"))
+ .ifPresent(qp -> {
+ String responseContentLanguage = response.getHeaders()
+ .getContentLanguage()
+ .getLanguage();
+
+ response.getHeaders()
+ .add("Bael-Custom-Language-Header", responseContentLanguage);
+ logger.info("Added custom header to Response");
+ });
+ }));
+ };
+ }
+
+ public static class Config {
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalFiltersConfigurations.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalFiltersConfigurations.java
new file mode 100644
index 0000000000..cf2ff3af16
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalFiltersConfigurations.java
@@ -0,0 +1,39 @@
+package com.baeldung.springcloudgateway.customfilters.filters.global;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+
+import reactor.core.publisher.Mono;
+
+@Configuration
+public class LoggingGlobalFiltersConfigurations {
+
+ final Logger logger = LoggerFactory.getLogger(LoggingGlobalFiltersConfigurations.class);
+
+ @Bean
+ public GlobalFilter postGlobalFilter() {
+ return (exchange, chain) -> {
+ return chain.filter(exchange)
+ .then(Mono.fromRunnable(() -> {
+ logger.info("Global Post Filter executed");
+ }));
+ };
+ }
+
+ @Bean
+ @Order(-1)
+ public GlobalFilter FirstPreLastPostGlobalFilter() {
+ return (exchange, chain) -> {
+ logger.info("First Pre Global Filter");
+ return chain.filter(exchange)
+ .then(Mono.fromRunnable(() -> {
+ logger.info("Last Post Global Filter");
+ }));
+ };
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalPreFilter.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalPreFilter.java
new file mode 100644
index 0000000000..d91075e4b6
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/filters/global/LoggingGlobalPreFilter.java
@@ -0,0 +1,28 @@
+package com.baeldung.springcloudgateway.customfilters.filters.global;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+
+import reactor.core.publisher.Mono;
+
+@Component
+public class LoggingGlobalPreFilter implements GlobalFilter, Ordered {
+
+ final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class);
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ logger.info("Global Pre Filter executed");
+ return chain.filter(exchange);
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/routes/ServiceRouteConfiguration.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/routes/ServiceRouteConfiguration.java
new file mode 100644
index 0000000000..b4f6eda374
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/customfilters/routes/ServiceRouteConfiguration.java
@@ -0,0 +1,28 @@
+package com.baeldung.springcloudgateway.customfilters.routes;
+
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
+import org.springframework.context.annotation.Bean;
+
+import com.baeldung.springcloudgateway.customfilters.filters.factories.LoggingGatewayFilterFactory;
+import com.baeldung.springcloudgateway.customfilters.filters.factories.LoggingGatewayFilterFactory.Config;
+
+/**
+ * Note: We want to keep this as an example of configuring a Route with a custom filter
+ *
+ * This corresponds with the properties configuration we have
+ */
+// @Configuration
+public class ServiceRouteConfiguration {
+
+ @Bean
+ public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) {
+
+ return builder.routes()
+ .route("service_route_java_config", r -> r.path("/service/**")
+ .filters(f -> f.rewritePath("/service(?/?.*)", "$\\{segment}")
+ .filter(loggingFactory.apply(new Config("My Custom Message", true, true))))
+ .uri("http://localhost:8081"))
+ .build();
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java
new file mode 100644
index 0000000000..d276597a6b
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.springcloudgateway.introduction;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.PropertySource;
+
+@SpringBootApplication
+@PropertySource("classpath:introduction-application.properties")
+public class IntroductionGatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(IntroductionGatewayApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/application.yml b/spring-cloud/spring-cloud-gateway/src/main/resources/application.yml
index 2450638e46..a33bca2055 100644
--- a/spring-cloud/spring-cloud-gateway/src/main/resources/application.yml
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/application.yml
@@ -1,16 +1,4 @@
-server:
- port: 80
-spring:
- cloud:
- gateway:
- routes:
- - id: baeldung_route
- uri: http://www.baeldung.com
- predicates:
- - Path=/baeldung
-
-management:
- endpoints:
- web:
- exposure:
- include: "*"
+logging:
+ level:
+ org.springframework.cloud.gateway: DEBUG
+ reactor.netty.http.client: DEBUG
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/customfilters-global-application.properties b/spring-cloud/spring-cloud-gateway/src/main/resources/customfilters-global-application.properties
new file mode 100644
index 0000000000..116bc706cb
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/customfilters-global-application.properties
@@ -0,0 +1,19 @@
+spring.cloud.gateway.routes[0].id=service_route
+spring.cloud.gateway.routes[0].uri=http://localhost:8081
+spring.cloud.gateway.routes[0].predicates[0]=Path=/service/**
+spring.cloud.gateway.routes[0].filters[0]=RewritePath=/service(?/?.*), $\{segment}
+spring.cloud.gateway.routes[0].filters[1]=Logging=My Custom Message, true, true
+# Or, as an alternative:
+#spring.cloud.gateway.routes[0].filters[1].name=Logging
+#spring.cloud.gateway.routes[0].filters[1].args[baseMessage]=My Custom Message
+#spring.cloud.gateway.routes[0].filters[1].args[preLogger]=true
+#spring.cloud.gateway.routes[0].filters[1].args[postLogger]=true
+
+spring.cloud.gateway.routes[0].filters[2]=ModifyRequest=en
+spring.cloud.gateway.routes[0].filters[3]=ModifyResponse
+spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr
+
+management.endpoints.web.exposure.include=*
+
+server.port=80
+
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/introduction-application.properties b/spring-cloud/spring-cloud-gateway/src/main/resources/introduction-application.properties
new file mode 100644
index 0000000000..d7a6c4e072
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/introduction-application.properties
@@ -0,0 +1,7 @@
+spring.cloud.gateway.routes[0].id=baeldung_route
+spring.cloud.gateway.routes[0].uri=http://www.baeldung.com
+spring.cloud.gateway.routes[0].predicates[0]=Path=/baeldung
+
+management.endpoints.web.exposure.include=*
+
+server.port=80
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/secondservice-application.properties b/spring-cloud/spring-cloud-gateway/src/main/resources/secondservice-application.properties
new file mode 100644
index 0000000000..3cf12afeb9
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/secondservice-application.properties
@@ -0,0 +1 @@
+server.port=8082
diff --git a/spring-cloud/spring-cloud-gateway/src/main/resources/service-application.properties b/spring-cloud/spring-cloud-gateway/src/main/resources/service-application.properties
new file mode 100644
index 0000000000..4d360de145
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/main/resources/service-application.properties
@@ -0,0 +1 @@
+server.port=8081
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SecondServiceIntegrationTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SecondServiceIntegrationTest.java
new file mode 100644
index 0000000000..9a1e0b0712
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SecondServiceIntegrationTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.secondservice;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import com.baeldung.secondservice.web.SecondServiceRestController;
+
+@WebFluxTest(SecondServiceRestController.class)
+public class SecondServiceIntegrationTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @Test
+ public void whenResourceLanguageEndpointCalled_thenRetrievesSpanishLanguageString() throws Exception {
+ this.webClient.get()
+ .uri("/resource/language")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody(String.class)
+ .isEqualTo("es");
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SpringContextTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SpringContextTest.java
new file mode 100644
index 0000000000..127ef7fe32
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/secondservice/SpringContextTest.java
@@ -0,0 +1,12 @@
+package com.baeldung.secondservice;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = SecondServiceApplication.class)
+public class SpringContextTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/ServiceIntegrationTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/ServiceIntegrationTest.java
new file mode 100644
index 0000000000..cb65ac3a50
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/ServiceIntegrationTest.java
@@ -0,0 +1,29 @@
+package com.baeldung.service;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
+import org.springframework.http.HttpHeaders;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import com.baeldung.service.web.ServiceRestController;
+
+@WebFluxTest(ServiceRestController.class)
+public class ServiceIntegrationTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @Test
+ public void whenResourceEndpointCalled_thenRetrievesResourceStringWithContentLanguageHeader() throws Exception {
+ this.webClient.get()
+ .uri("/resource")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectHeader()
+ .valueEquals(HttpHeaders.CONTENT_LANGUAGE, "en")
+ .expectBody(String.class)
+ .isEqualTo("Service Resource");
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/SpringContextTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/SpringContextTest.java
new file mode 100644
index 0000000000..28216dca86
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/service/SpringContextTest.java
@@ -0,0 +1,12 @@
+package com.baeldung.service;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = ServiceApplication.class)
+public class SpringContextTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersLiveTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersLiveTest.java
new file mode 100644
index 0000000000..40275bd206
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/CustomFiltersLiveTest.java
@@ -0,0 +1,90 @@
+package com.baeldung.springcloudgateway.customfilters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.assertj.core.api.Condition;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
+
+import com.baeldung.springcloudgateway.customfilters.utils.LoggerListAppender;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+/**
+ * This test requires:
+ * * the service in com.baeldung.service running
+ * * the 'second service' in com.baeldung.secondservice running
+ *
+ */
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+public class CustomFiltersLiveTest {
+
+ @LocalServerPort
+ String port;
+
+ private WebTestClient client;
+
+ @BeforeEach
+ public void clearLogList() {
+ LoggerListAppender.clearEventList();
+ client = WebTestClient.bindToServer()
+ .baseUrl("http://localhost:" + port)
+ .build();
+ }
+
+ @Test
+ public void whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() {
+ ResponseSpec response = client.get()
+ .uri("/service/resource")
+ .exchange();
+
+ response.expectStatus()
+ .isOk()
+ .expectBody(String.class)
+ .isEqualTo("Service Resource");
+
+ assertThat(LoggerListAppender.getEvents())
+ // Global Pre Filter
+ .haveAtLeastOne(eventContains("Global Pre Filter executed"))
+ // Global Post Filter
+ .haveAtLeastOne(eventContains("Global Post Filter executed"))
+ // Global Pre and Post Filter
+ .haveAtLeastOne(eventContains("First Pre Global Filter"))
+ .haveAtLeastOne(eventContains("Last Post Global Filter"))
+ // Logging Filter Factory
+ .haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message"))
+ .haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message"))
+ // Modify Request
+ .haveAtLeastOne(eventContains("Modify Request output - Request contains Accept-Language header:"))
+ // Modify Response
+ .areNot(eventContains("Added custom header to Response"))
+ // Chain Request
+ .haveAtLeastOne(eventContains("Chain Request output - Request contains Accept-Language header:"));
+ }
+
+ @Test
+ public void givenRequestWithLocaleQueryParam_whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() {
+ ResponseSpec response = client.get()
+ .uri("/service/resource?locale=en")
+ .exchange();
+
+ response.expectStatus()
+ .isOk()
+ .expectBody(String.class)
+ .isEqualTo("Service Resource");
+
+ assertThat(LoggerListAppender.getEvents())
+ // Modify Response
+ .haveAtLeastOne(eventContains("Added custom header to Response"));
+ }
+
+ private Condition eventContains(String substring) {
+ return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage()
+ .contains(substring))), String.format("entry with message '%s'", substring));
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/utils/LoggerListAppender.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/utils/LoggerListAppender.java
new file mode 100644
index 0000000000..b6337dabb6
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/utils/LoggerListAppender.java
@@ -0,0 +1,25 @@
+package com.baeldung.springcloudgateway.customfilters.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+
+public class LoggerListAppender extends AppenderBase {
+
+ static private List events = new ArrayList<>();
+
+ @Override
+ protected void append(ILoggingEvent eventObject) {
+ events.add(eventObject);
+ }
+
+ public static List getEvents() {
+ return events;
+ }
+
+ public static void clearEventList() {
+ events.clear();
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java
new file mode 100644
index 0000000000..1550265f22
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java
@@ -0,0 +1,15 @@
+package com.baeldung.springcloudgateway.introduction;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.baeldung.springcloudgateway.introduction.IntroductionGatewayApplication;
+
+
+@SpringBootTest(classes = IntroductionGatewayApplication.class)
+public class SpringContextTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/org/baeldung/SpringContextTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/org/baeldung/SpringContextTest.java
deleted file mode 100644
index b7e2acf7a8..0000000000
--- a/spring-cloud/spring-cloud-gateway/src/test/java/org/baeldung/SpringContextTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.baeldung;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import com.baeldung.spring.cloud.GatewayApplication;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = GatewayApplication.class)
-public class SpringContextTest {
-
- @Test
- public void whenSpringContextIsBootstrapped_thenNoExceptions() {
- }
-}
diff --git a/spring-cloud/spring-cloud-gateway/src/test/resources/logback-test.xml b/spring-cloud/spring-cloud-gateway/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..8febdc8b1a
--- /dev/null
+++ b/spring-cloud/spring-cloud-gateway/src/test/resources/logback-test.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java
index 77d6a816e3..046a310cc0 100644
--- a/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java
+++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java
@@ -1,43 +1,61 @@
package org.baeldung.cachedrequest;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.io.IOException;
+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import java.io.IOException;
-
-import javax.print.attribute.PrintRequestAttribute;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.ResultActions;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { HttpRequestDemoConfig.class, ContentCachingFilter.class, PrintRequestAttribute.class })
-@AutoConfigureMockMvc
+@ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = { HttpRequestDemoConfig.class, ContentCachingFilter.class, PrintRequestContentFilter.class, PersonController.class })
+@WebAppConfiguration
public class PersonControllerIntegrationTest {
@Autowired
+ private WebApplicationContext wac;
+
private MockMvc mockMvc;
ObjectMapper objectMapper = new ObjectMapper();
+ @Autowired
+ private ContentCachingFilter contentCachingFilter;
+
+ @Autowired
+ private PrintRequestContentFilter printRequestContentFilter;
+
+ @Before
+ public void setup() throws Exception {
+
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
+ .addFilter(contentCachingFilter, "/**")
+ .addFilter(printRequestContentFilter, "/**")
+ .build();
+ }
+
@Test
public void whenValidInput_thenCreateBook() throws IOException, Exception {
// assign - given
- Person book = new Person("sumit", "abc", 100);
+ Person person = new Person("sumit", "abc", 100);
// act - when
ResultActions result = mockMvc.perform(post("/person").accept(MediaType.APPLICATION_JSON)
- .contentType(MediaType.APPLICATION_JSON)
- .content(objectMapper.writeValueAsString(book)));
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(person)));
// assert - then
result.andExpect(status().isNoContent());
diff --git a/spring-rest-full/README.md b/spring-rest-full/README.md
index df7856725f..70ab6b2c80 100644
--- a/spring-rest-full/README.md
+++ b/spring-rest-full/README.md
@@ -10,7 +10,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
- [Integration Testing with the Maven Cargo plugin](https://www.baeldung.com/integration-testing-with-the-maven-cargo-plugin)
-- [Project Configuration with Spring](https://www.baeldung.com/project-configuration-with-spring)
- [Metrics for your Spring REST API](https://www.baeldung.com/spring-rest-api-metrics)
### Build the Project
diff --git a/spring-rest-simple/README.md b/spring-rest-simple/README.md
index 1ad32bf120..cb52e9118c 100644
--- a/spring-rest-simple/README.md
+++ b/spring-rest-simple/README.md
@@ -9,4 +9,4 @@ This module contains articles about REST APIs in Spring
- [Spring RequestMapping](https://www.baeldung.com/spring-requestmapping)
- [Spring and Apache FileUpload](https://www.baeldung.com/spring-apache-file-upload)
- [Test a REST API with curl](https://www.baeldung.com/curl-rest)
-- [CORS with Spring](https://www.baeldung.com/spring-cors)
+- [Best Practices for REST API Error Handling](https://www.baeldung.com/rest-api-error-handling-best-practices)
\ No newline at end of file
diff --git a/spring-rest/.gitignore b/spring-rest/.gitignore
index 83c05e60c8..2661c0de1e 100644
--- a/spring-rest/.gitignore
+++ b/spring-rest/.gitignore
@@ -4,7 +4,7 @@
/target
/neoDb*
/data
-/src/main/webapp/WEB-INF/classes
+/spring-boot-runtime/src/main/webapp/WEB-INF/classes
*/META-INF/*
# Packaged files #
diff --git a/spring-rest/README.md b/spring-rest/README.md
index af054b2dcf..3ea9361169 100644
--- a/spring-rest/README.md
+++ b/spring-rest/README.md
@@ -12,9 +12,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Guide to UriComponentsBuilder in Spring](https://www.baeldung.com/spring-uricomponentsbuilder)
- [A Custom Media Type for a Spring REST API](https://www.baeldung.com/spring-rest-custom-media-type)
- [HTTP PUT vs HTTP PATCH in a REST API](https://www.baeldung.com/http-put-patch-difference-spring)
-- [Spring – Log Incoming Requests](https://www.baeldung.com/spring-http-logging)
-- [How to Change the Default Port in Spring Boot](https://www.baeldung.com/spring-boot-change-port)
- [Guide to DeferredResult in Spring](https://www.baeldung.com/spring-deferred-result)
-- [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor)
- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header)
- [Download an Image or a File with Spring MVC](https://www.baeldung.com/spring-controller-return-image-file)
diff --git a/spring-resttemplate/src/main/java/com/baeldung/SpringContextTest.java b/spring-resttemplate/src/main/java/com/baeldung/SpringContextTest.java
index 0f39fc3983..19d5eabd2b 100644
--- a/spring-resttemplate/src/main/java/com/baeldung/SpringContextTest.java
+++ b/spring-resttemplate/src/main/java/com/baeldung/SpringContextTest.java
@@ -5,17 +5,14 @@ import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
-import com.baeldung.changeport.CustomApplication;
import com.baeldung.produceimage.ImageApplication;
-import com.baeldung.propertyeditor.PropertyEditorApplication;
import com.baeldung.responseheaders.ResponseHeadersApplication;
-import com.baeldung.sampleapp.config.MainApplication;
-import com.baeldung.web.log.app.Application;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = { CustomApplication.class, ImageApplication.class, PropertyEditorApplication.class,
- ResponseHeadersApplication.class, Application.class, com.baeldung.web.upload.app.UploadApplication.class,
- MainApplication.class})
+@SpringBootTest(classes = { ImageApplication.class,
+ ResponseHeadersApplication.class,
+ com.baeldung.web.upload.app.UploadApplication.class,
+ })
public class SpringContextTest {
@Test
diff --git a/testing-modules/junit-5/README.md b/testing-modules/junit-5/README.md
index ede60c45a9..e62f2dd345 100644
--- a/testing-modules/junit-5/README.md
+++ b/testing-modules/junit-5/README.md
@@ -6,3 +6,4 @@
- [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java)
- [Testing an Abstract Class With JUnit](https://www.baeldung.com/junit-test-abstract-class)
- [Guide to Dynamic Tests in JUnit 5](https://www.baeldung.com/junit5-dynamic-tests)
+- [Determine the Execution Time of JUnit Tests](https://www.baeldung.com/junit-test-execution-time)
diff --git a/testing-modules/testing-libraries/pom.xml b/testing-modules/testing-libraries/pom.xml
index 0838e81d14..844fcb3e53 100644
--- a/testing-modules/testing-libraries/pom.xml
+++ b/testing-modules/testing-libraries/pom.xml
@@ -18,19 +18,20 @@
${lambda-behave.version}
- info.cukes
+ io.cucumber
cucumber-junit
${cucumber.version}
test
- info.cukes
+ io.cucumber
cucumber-java
${cucumber.version}
test
+
- info.cukes
+ io.cucumber
cucumber-java8
${cucumber.version}
test
@@ -87,7 +88,7 @@
0.4
- 1.2.5
+ 4.8.0
3.0.0
diff --git a/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/Book.java b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/Book.java
new file mode 100644
index 0000000000..f83623445b
--- /dev/null
+++ b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/Book.java
@@ -0,0 +1,35 @@
+package com.baeldung.cucumber.books;
+
+public class Book {
+
+ private String title;
+ private String author;
+
+ public Book(String title, String author) {
+ this.title = title;
+ this.author = author;
+ }
+
+ public Book() {}
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ @Override
+ public String toString() {
+ return "Book [title=" + title + ", author=" + author + "]";
+ }
+}
diff --git a/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookCatalog.java b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookCatalog.java
new file mode 100644
index 0000000000..69fa8e3160
--- /dev/null
+++ b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookCatalog.java
@@ -0,0 +1,22 @@
+package com.baeldung.cucumber.books;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BookCatalog {
+
+ private List books = new ArrayList<>();
+
+ public void addBook(Book book) {
+ books.add(book);
+ }
+
+ public List getBooks() {
+ return books;
+ }
+
+ @Override
+ public String toString() {
+ return "BookCatalog [books=" + books + "]";
+ }
+}
diff --git a/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookStore.java b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookStore.java
new file mode 100644
index 0000000000..e5a3ceab3e
--- /dev/null
+++ b/testing-modules/testing-libraries/src/main/java/com/baeldung/cucumber/books/BookStore.java
@@ -0,0 +1,26 @@
+package com.baeldung.cucumber.books;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class BookStore {
+
+ private List books = new ArrayList<>();
+
+ public void addBook(Book book) {
+ books.add(book);
+ }
+
+ public void addAllBooks(Collection books) {
+ this.books.addAll(books);
+ }
+
+ public List booksByAuthor(String author) {
+ return books.stream()
+ .filter(book -> Objects.equals(author, book.getAuthor()))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorIntegrationTest.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorIntegrationTest.java
index 00f666db2d..e4580900a2 100644
--- a/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorIntegrationTest.java
+++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorIntegrationTest.java
@@ -1,9 +1,10 @@
package com.baeldung.calculator;
-import cucumber.api.CucumberOptions;
-import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
+import io.cucumber.junit.Cucumber;
+import io.cucumber.junit.CucumberOptions;
+
@RunWith(Cucumber.class)
@CucumberOptions(
features = {"classpath:features/calculator.feature", "classpath:features/calculator-scenario-outline.feature"}
diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorRunSteps.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorRunSteps.java
index 7eda618566..1bf0c0eccd 100644
--- a/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorRunSteps.java
+++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/calculator/CalculatorRunSteps.java
@@ -1,13 +1,15 @@
package com.baeldung.calculator;
-import com.baeldung.cucumber.Calculator;
-import cucumber.api.java.Before;
-import cucumber.api.java.en.Given;
-import cucumber.api.java.en.Then;
-import cucumber.api.java.en.When;
import org.hamcrest.Matchers;
import org.junit.Assert;
+import com.baeldung.cucumber.Calculator;
+
+import io.cucumber.java.Before;
+import io.cucumber.java.en.Given;
+import io.cucumber.java.en.Then;
+import io.cucumber.java.en.When;
+
public class CalculatorRunSteps {
private int total;
diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreIntegrationTest.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreIntegrationTest.java
new file mode 100644
index 0000000000..5ed2700af8
--- /dev/null
+++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreIntegrationTest.java
@@ -0,0 +1,13 @@
+package com.baeldung.cucumber.books;
+
+import org.junit.runner.RunWith;
+
+import io.cucumber.junit.Cucumber;
+import io.cucumber.junit.CucumberOptions;
+
+@RunWith(Cucumber.class)
+@CucumberOptions(features = "classpath:features/book-store.feature")
+public class BookStoreIntegrationTest {
+
+}
+
diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRegistryConfigurer.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRegistryConfigurer.java
new file mode 100644
index 0000000000..12de1ae71e
--- /dev/null
+++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRegistryConfigurer.java
@@ -0,0 +1,42 @@
+package com.baeldung.cucumber.books;
+
+import java.util.Locale;
+
+import io.cucumber.core.api.TypeRegistry;
+import io.cucumber.core.api.TypeRegistryConfigurer;
+import io.cucumber.datatable.DataTable;
+import io.cucumber.datatable.DataTableType;
+import io.cucumber.datatable.TableTransformer;
+
+public class BookStoreRegistryConfigurer implements TypeRegistryConfigurer {
+
+ @Override
+ public Locale locale() {
+ return Locale.ENGLISH;
+ }
+
+ @Override
+ public void configureTypeRegistry(TypeRegistry typeRegistry) {
+ typeRegistry.defineDataTableType(
+ new DataTableType(BookCatalog.class, new BookTableTransformer())
+ );
+ }
+
+ private static class BookTableTransformer implements TableTransformer {
+
+ @Override
+ public BookCatalog transform(DataTable table) throws Throwable {
+
+ BookCatalog catalog = new BookCatalog();
+
+ table.cells()
+ .stream()
+ .skip(1) // Skip header row
+ .map(fields -> new Book(fields.get(0), fields.get(1)))
+ .forEach(catalog::addBook);
+
+ return catalog;
+ }
+
+ }
+}
diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRunSteps.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRunSteps.java
new file mode 100644
index 0000000000..e0944d3dd4
--- /dev/null
+++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/cucumber/books/BookStoreRunSteps.java
@@ -0,0 +1,60 @@
+package com.baeldung.cucumber.books;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import io.cucumber.java.Before;
+import io.cucumber.java.en.Given;
+import io.cucumber.java.en.Then;
+import io.cucumber.java.en.When;
+import io.cucumber.datatable.DataTable;
+
+public class BookStoreRunSteps {
+
+ private BookStore store;
+ private List foundBooks;
+
+ @Before
+ public void setUp() {
+ store = new BookStore();
+ foundBooks = new ArrayList<>();
+ }
+
+ @Given("^I have the following books in the store by list$")
+ public void haveBooksInTheStoreByList(DataTable table) {
+
+ List> rows = table.asLists(String.class);
+
+ for (List columns: rows) {
+ store.addBook(new Book(columns.get(0), columns.get(1)));
+ }
+ }
+
+ @Given("^I have the following books in the store by map$")
+ public void haveBooksInTheStoreByMap(DataTable table) {
+
+ List