diff --git a/.github/ISSUE_TEMPLATE/issue_report.md b/.github/ISSUE_TEMPLATE/issue_report.md new file mode 100644 index 0000000000..4bc8c8121c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_report.md @@ -0,0 +1,32 @@ +--- +name: Issue Report +about: Report an issue to help us improve +title: '[ISSUE] ' +--- + +**Article and Module Links** +A link to the affected article and the affected module. You can find the link to the module in the Conclusion section in the "on Github" standard phase. + +**Describe the Issue** +A clear and concise description of what the issue is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected Behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment (please complete the following information):** +- OS: [e.g. Windows] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] + +**Additional Context** +Add any other context about the issue here. diff --git a/.gitignore b/.gitignore index d22c792f43..0b6bd24070 100644 --- a/.gitignore +++ b/.gitignore @@ -124,4 +124,7 @@ devDb*.db *.xjb #neo4j -persistence-modules/neo4j/data/** \ No newline at end of file +persistence-modules/neo4j/data/** +/deep-shallow-copy/.mvn/wrapper +/deep-shallow-copy/mvnw +/deep-shallow-copy/mvnw.cmd diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..642f4c6707 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing to Baeldung Tutorials +First off, thank you for considering contributing to Baeldung Tutorials. + +## Reporting Issues +Before you submit an issue, please review the guidelines below: + +1. **No Custom Modifications:** If your issue arises from any custom modifications you've made to the code in the repository, we won't be able to assist. We can only help if the issue is reproducible with the untouched codebase from this repo. If you're working with a modified version, consider asking for help on StackOverflow or other relevant forums. +2. **Use a clear and descriptive title** for the issue to identify the problem. +3. **Include a link to the article** you're having issues with. +4. **Describe the exact steps which reproduce the problem** in as many details as possible. +5. **Additional Details:** Offer any other context or descriptions that could be useful. Screenshots, error messages, copy/pasteable snippets, or logs can be immensely helpful. \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java index 202912a1af..15e813f680 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java @@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory; public class KadaneAlgorithm { - private Logger logger = LoggerFactory.getLogger(BruteForceAlgorithm.class.getName()); + private Logger logger = LoggerFactory.getLogger(KadaneAlgorithm.class.getName()); public int maxSubArraySum(int[] arr) { @@ -14,15 +14,15 @@ public class KadaneAlgorithm { int end = 0; int maxSoFar = arr[0], maxEndingHere = arr[0]; + for (int i = 1; i < size; i++) { - - if (arr[i] > maxEndingHere + arr[i]) { - start = i; + maxEndingHere = maxEndingHere + arr[i]; + if (arr[i] > maxEndingHere) { maxEndingHere = arr[i]; - } else { - maxEndingHere = maxEndingHere + arr[i]; + if (maxSoFar < maxEndingHere) { + start = i; + } } - if (maxSoFar < maxEndingHere) { maxSoFar = maxEndingHere; end = i; diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java index 8dcc81bc5b..b0ce689645 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class KadaneAlgorithmUnitTest { @Test - void givenArrayWithNegativeNumberWhenMaximumSubarrayThenReturns6() { + void givenArrayWithNegativeNumberWhenMaximumSubarrayThenReturnsExpectedResult() { //given int[] arr = new int[] { -3, 1, -8, 4, -1, 2, 1, -5, 5 }; //when @@ -27,7 +27,7 @@ class KadaneAlgorithmUnitTest { //then assertEquals(-1, maxSum); } - + @Test void givenArrayWithAllPosiitveNumbersWhenMaximumSubarrayThenReturnsExpectedResult() { //given @@ -39,4 +39,15 @@ class KadaneAlgorithmUnitTest { assertEquals(10, maxSum); } + @Test + void givenArrayToTestStartIndexWhenMaximumSubarrayThenReturnsExpectedResult() { + //given + int[] arr = new int[] { 1, 2, -1, 3, -6, -2 }; + //when + KadaneAlgorithm algorithm = new KadaneAlgorithm(); + int maxSum = algorithm.maxSubArraySum(arr); + //then + assertEquals(5, maxSum); + } + } \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/README.md b/algorithms-modules/algorithms-miscellaneous-7/README.md index ab07d655f9..87a1ee15ec 100644 --- a/algorithms-modules/algorithms-miscellaneous-7/README.md +++ b/algorithms-modules/algorithms-miscellaneous-7/README.md @@ -3,4 +3,6 @@ - [Algorithm to Identify and Validate a Credit Card Number](https://www.baeldung.com/java-validate-cc-number) - [Find the N Most Frequent Elements in a Java Array](https://www.baeldung.com/java-n-most-frequent-elements-array) - [Getting Pixel Array From Image in Java](https://www.baeldung.com/java-getting-pixel-array-from-image) +- [Calculate Distance Between Two Coordinates in Java](https://www.baeldung.com/java-find-distance-between-points) +- [Rotate Arrays in Java](https://www.baeldung.com/java-rotate-arrays) - More articles: [[<-- prev]](/algorithms-miscellaneous-6) diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java new file mode 100644 index 0000000000..e42475c17e --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java @@ -0,0 +1,19 @@ +package com.baeldung.algorithms.latlondistance; + +public class EquirectangularApproximation { + + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + double lat1Rad = Math.toRadians(lat1); + double lat2Rad = Math.toRadians(lat2); + double lon1Rad = Math.toRadians(lon1); + double lon2Rad = Math.toRadians(lon2); + + double x = (lon2Rad - lon1Rad) * Math.cos((lat1Rad + lat2Rad) / 2); + double y = (lat2Rad - lat1Rad); + double distance = Math.sqrt(x * x + y * y) * EARTH_RADIUS; + + return distance; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java new file mode 100644 index 0000000000..69074ec559 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java @@ -0,0 +1,24 @@ +package com.baeldung.algorithms.latlondistance; + +public class HaversineDistance { + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double startLat, double startLong, + double endLat, double endLong) { + + double dLat = Math.toRadians((endLat - startLat)); + double dLong = Math.toRadians((endLong - startLong)); + + startLat = Math.toRadians(startLat); + endLat = Math.toRadians(endLat); + + double a = haversine(dLat) + Math.cos(startLat) * Math.cos(endLat) * haversine(dLong); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return EARTH_RADIUS * c; + } + + public static double haversine(double val) { + return Math.pow(Math.sin(val / 2), 2); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java new file mode 100644 index 0000000000..7d0b0b907f --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java @@ -0,0 +1,53 @@ +package com.baeldung.algorithms.latlondistance; + +public class VincentyDistance { + + // Constants for WGS84 ellipsoid model of Earth + private static final double SEMI_MAJOR_AXIS_MT = 6378137; + private static final double SEMI_MINOR_AXIS_MT = 6356752.314245; + private static final double FLATTENING = 1 / 298.257223563; + private static final double ERROR_TOLERANCE = 1e-12; + + public static double calculateDistance(double latitude1, double longitude1, double latitude2, double longitude2) { + double U1 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude1))); + double U2 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude2))); + + double sinU1 = Math.sin(U1); + double cosU1 = Math.cos(U1); + double sinU2 = Math.sin(U2); + double cosU2 = Math.cos(U2); + + double longitudeDifference = Math.toRadians(longitude2 - longitude1); + double previousLongitudeDifference; + + double sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM; + + do { + sinSigma = Math.sqrt(Math.pow(cosU2 * Math.sin(longitudeDifference), 2) + + Math.pow(cosU1 * sinU2 - sinU1 * cosU2 * Math.cos(longitudeDifference), 2)); + cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * Math.cos(longitudeDifference); + sigma = Math.atan2(sinSigma, cosSigma); + sinAlpha = cosU1 * cosU2 * Math.sin(longitudeDifference) / sinSigma; + cosSqAlpha = 1 - Math.pow(sinAlpha, 2); + cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; + if (Double.isNaN(cos2SigmaM)) { + cos2SigmaM = 0; + } + previousLongitudeDifference = longitudeDifference; + double C = FLATTENING / 16 * cosSqAlpha * (4 + FLATTENING * (4 - 3 * cosSqAlpha)); + longitudeDifference = Math.toRadians(longitude2 - longitude1) + (1 - C) * FLATTENING * sinAlpha * + (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)))); + } while (Math.abs(longitudeDifference - previousLongitudeDifference) > ERROR_TOLERANCE); + + double uSq = cosSqAlpha * (Math.pow(SEMI_MAJOR_AXIS_MT, 2) - Math.pow(SEMI_MINOR_AXIS_MT, 2)) / Math.pow(SEMI_MINOR_AXIS_MT, 2); + + double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); + double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); + + double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)) - + B / 6 * cos2SigmaM * (-3 + 4 * Math.pow(sinSigma, 2)) * (-3 + 4 * Math.pow(cos2SigmaM, 2)))); + + double distanceMt = SEMI_MINOR_AXIS_MT * A * (sigma - deltaSigma); + return distanceMt / 1000; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java new file mode 100644 index 0000000000..36490d4899 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java @@ -0,0 +1,102 @@ +package com.baeldung.algorithms.rotatearray; + +/** + * To speed up the rotation, we narrow k rotations to the remainder of k divided by the array length, or k module the array length. + * Therefore, a large rotation number will be translated into the relative smallest rotation. + * All solutions replace the original array, although they might use an extra array to compute the rotation. + */ +public class RotateArray { + + private RotateArray() { + throw new IllegalStateException("Rotate array algorithm utility methods class"); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void bruteForce(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + int temp; + int previous; + for (int i = 0; i < k; i++) { + previous = arr[arr.length - 1]; + for (int j = 0; j < arr.length; j++) { + temp = arr[j]; + arr[j] = previous; + previous = temp; + } + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void withExtraArray(int[] arr, int k) { + checkInvalidInput(arr, k); + + int[] extraArray = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + extraArray[(i + k) % arr.length] = arr[i]; + } + System.arraycopy(extraArray, 0, arr, 0, arr.length); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void cyclicReplacement(int[] arr, int k) { + checkInvalidInput(arr, k); + + k = k % arr.length; + int count = 0; + for (int start = 0; count < arr.length; start++) { + int current = start; + int prev = arr[start]; + do { + int next = (current + k) % arr.length; + int temp = arr[next]; + arr[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void reverse(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + reverse(arr, 0, arr.length - 1); + reverse(arr, 0, k - 1); + reverse(arr, k, arr.length - 1); + } + + private static void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } + + private static void checkInvalidInput(int[] arr, int rotation) { + if (rotation < 1 || arr == null) + throw new IllegalArgumentException("Rotation must be greater than zero or array must be not null"); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameBoard.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameBoard.java new file mode 100644 index 0000000000..b10bd95a19 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameBoard.java @@ -0,0 +1,129 @@ +package com.baeldung.algorithms.connect4; + +import java.util.ArrayList; +import java.util.List; + +public class GameBoard { + private final List> columns; + + private final int rows; + + public GameBoard(int columns, int rows) { + this.rows = rows; + this.columns = new ArrayList<>(); + + for (int i = 0; i < columns; ++i) { + this.columns.add(new ArrayList<>()); + } + } + + public int getRows() { + return rows; + } + + public int getColumns() { + return columns.size(); + } + + public Piece getCell(int x, int y) { + assert(x >= 0 && x < getColumns()); + assert(y >= 0 && y < getRows()); + + List column = columns.get(x); + + if (column.size() > y) { + return column.get(y); + } else { + return null; + } + } + + public boolean move(int x, Piece player) { + assert(x >= 0 && x < getColumns()); + + List column = columns.get(x); + + if (column.size() >= this.rows) { + throw new IllegalArgumentException("That column is full"); + } + + column.add(player); + + return checkWin(x, column.size() - 1, player); + } + + private boolean checkWin(int x, int y, Piece player) { + // Vertical line + if (checkLine(x, y, 0, -1, player)) { + return true; + } + + for (int offset = 0; offset < 4; ++offset) { + // Horizontal line + if (checkLine(x - 3 + offset, y, 1, 0, player)) { + return true; + } + + // Leading diagonal + if (checkLine(x - 3 + offset, y + 3 - offset, 1, -1, player)) { + return true; + } + + // Trailing diagonal + if (checkLine(x - 3 + offset, y - 3 + offset, 1, 1, player)) { + return true; + } + } + + return false; + } + + private boolean checkLine(int x1, int y1, int xDiff, int yDiff, Piece player) { + for (int i = 0; i < 4; ++i) { + int x = x1 + (xDiff * i); + int y = y1 + (yDiff * i); + + if (x < 0 || x > columns.size() - 1) { + return false; + } + + if (y < 0 || y > rows - 1) { + return false; + } + + if (player != getCell(x, y)) { + return false; + } + } + + return true; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + + for (int y = getRows() - 1; y >= 0; --y) { + for (int x = 0; x < getColumns(); ++x) { + Piece piece = getCell(x, y); + + result.append("|"); + if (piece == null) { + result.append(" "); + } else if (piece == Piece.PLAYER_1) { + result.append("X"); + } else if (piece == Piece.PLAYER_2) { + result.append("O"); + } + } + + result.append("|\n"); + for (int i = 0; i < getColumns(); ++i) { + result.append("+-"); + } + result.append("+\n"); + } + + return result.toString(); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameUnitTest.java new file mode 100644 index 0000000000..f340644950 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/GameUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.algorithms.connect4; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GameUnitTest { + @Test + public void blankGame() { + GameBoard gameBoard = new GameBoard(8, 6); + + System.out.println(gameBoard); + } + + @Test + public void playedGame() { + GameBoard gameBoard = new GameBoard(8, 6); + + assertFalse(gameBoard.move(3, Piece.PLAYER_1)); + assertFalse(gameBoard.move(2, Piece.PLAYER_2)); + + assertFalse(gameBoard.move(4, Piece.PLAYER_1)); + assertFalse(gameBoard.move(3, Piece.PLAYER_2)); + + assertFalse(gameBoard.move(5, Piece.PLAYER_1)); + assertFalse(gameBoard.move(6, Piece.PLAYER_2)); + + assertFalse(gameBoard.move(5, Piece.PLAYER_1)); + assertFalse(gameBoard.move(4, Piece.PLAYER_2)); + + assertFalse(gameBoard.move(5, Piece.PLAYER_1)); + assertFalse(gameBoard.move(5, Piece.PLAYER_2)); + + assertFalse(gameBoard.move(6, Piece.PLAYER_1)); + assertTrue(gameBoard.move(4, Piece.PLAYER_2)); + + System.out.println(gameBoard); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/Piece.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/Piece.java new file mode 100644 index 0000000000..5a8724c09b --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/connect4/Piece.java @@ -0,0 +1,6 @@ +package com.baeldung.algorithms.connect4; + +public enum Piece { + PLAYER_1, + PLAYER_2 +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java new file mode 100644 index 0000000000..9e72f86287 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.latlondistance; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GeoDistanceUnitTest { + @Test + public void testCalculateDistance() { + double lat1 = 40.714268; // New York + double lon1 = -74.005974; + double lat2 = 34.0522; // Los Angeles + double lon2 = -118.2437; + + double equirectangularDistance = EquirectangularApproximation.calculateDistance(lat1, lon1, lat2, lon2); + double haversineDistance = HaversineDistance.calculateDistance(lat1, lon1, lat2, lon2); + double vincentyDistance = VincentyDistance.calculateDistance(lat1, lon1, lat2, lon2); + + double expectedDistance = 3944; + assertTrue(Math.abs(equirectangularDistance - expectedDistance) < 100); + assertTrue(Math.abs(haversineDistance - expectedDistance) < 10); + assertTrue(Math.abs(vincentyDistance - expectedDistance) < 0.5); + + } + +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java new file mode 100644 index 0000000000..4a98acdb75 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java @@ -0,0 +1,124 @@ +package com.baeldung.algorithms.rotatearray; + +import static com.baeldung.algorithms.rotatearray.RotateArray.bruteForce; +import static com.baeldung.algorithms.rotatearray.RotateArray.cyclicReplacement; +import static com.baeldung.algorithms.rotatearray.RotateArray.reverse; +import static com.baeldung.algorithms.rotatearray.RotateArray.withExtraArray; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class RotateArrayUnitTest { + + private final int[] arr = { 1, 2, 3, 4, 5, 6 }; + private final int rotationLtArrayLength = 1; + private final int rotationGtArrayLength = arr.length + 2; + private final int[] ltArrayLengthRotation = { 6, 1, 2, 3, 4, 5 }; + private final int[] gtArrayLengthRotation = { 5, 6, 1, 2, 3, 4 }; + + @Test + void givenInputArray_whenNoRotationOrEmptyArray_thenThrowIllegalArgumentException() { + final int noRotation = 0; + final int someRotation = arr.length - 1; + + assertThrows(IllegalArgumentException.class, () -> bruteForce(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(arr, noRotation)); + + assertThrows(IllegalArgumentException.class, () -> bruteForce(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(null, someRotation)); + } + + @Test + void givenInputArray_whenUseBruteForceRotationLtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationGtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationEqArrayLength_thenDoNothing() { + int[] expected = arr.clone(); + + bruteForce(arr, arr.length); + assertArrayEquals(expected, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationLtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationGtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayWithRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + withExtraArray(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationLtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationGtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + cyclicReplacement(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationLtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationGtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationEqArrayLength_thenDoNothing() { + + int[] clone = arr.clone(); + + reverse(arr, arr.length); + assertArrayEquals(clone, arr); + } +} diff --git a/annotations/README.md b/annotations/README.md deleted file mode 100644 index ec4005fc5e..0000000000 --- a/annotations/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## Annotations - -This module contains articles about Java annotations - -### Relevant Articles: - -- [Java Annotation Processing and Creating a Builder](https://www.baeldung.com/java-annotation-processing-builder) diff --git a/annotations/pom.xml b/annotations/pom.xml deleted file mode 100644 index b3fabb8637..0000000000 --- a/annotations/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - annotations - annotations - pom - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - annotation-processing - annotation-user - - - \ No newline at end of file diff --git a/apache-cxf-modules/cxf-spring/pom.xml b/apache-cxf-modules/cxf-spring/pom.xml index 1c87ae4bfb..67a61e8200 100644 --- a/apache-cxf-modules/cxf-spring/pom.xml +++ b/apache-cxf-modules/cxf-spring/pom.xml @@ -43,19 +43,19 @@ com.sun.xml.ws jaxws-ri - 2.3.3 + ${jaxws-ri.version} pom javax.servlet javax.servlet-api - 4.0.1 + ${javax.servlet-api.version} provided javax.servlet jstl - 1.2 + ${jstl.version} @@ -117,7 +117,9 @@ 5.3.25 1.6.1 - 3.3.2 + 1.2 + 4.0.1 + 2.3.3 \ No newline at end of file diff --git a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java index c58763b1c0..818d0c3cd9 100644 --- a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java +++ b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -1,36 +1,43 @@ package com.baeldung.tlsversion; -import javax.net.ssl.SSLSocket; - -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContexts; -import org.apache.http.util.EntityUtils; - import java.io.IOException; +import javax.net.ssl.SSLSocket; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; + public class ClientTlsVersionExamples { - public static CloseableHttpClient setViaSocketFactory() { - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( - SSLContexts.createDefault(), - new String[] { "TLSv1.2", "TLSv1.3" }, - null, - SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultTlsConfig(TlsConfig.custom() + .setHandshakeTimeout(Timeout.ofSeconds(30)) + .setSupportedProtocols(TLS.V_1_2, TLS.V_1_3) + .build()) + .build(); - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + return HttpClients.custom() + .setConnectionManager(cm) + .build(); } public static CloseableHttpClient setTlsVersionPerConnection() { SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { - @Override protected void prepareSocket(SSLSocket socket) { - String hostname = socket.getInetAddress().getHostName(); + String hostname = socket.getInetAddress() + .getHostName(); if (hostname.endsWith("internal.system.com")) { socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); } else { @@ -39,7 +46,14 @@ public class ClientTlsVersionExamples { } }; - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + HttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslsf) + .build(); + + return HttpClients.custom() + .setConnectionManager(connManager) + .build(); + } // To configure the TLS versions for the client, set the https.protocols system property during runtime. @@ -47,15 +61,11 @@ public class ClientTlsVersionExamples { public static CloseableHttpClient setViaSystemProperties() { return HttpClients.createSystem(); // Alternatively: - // return HttpClients.custom().useSystemProperties().build(); + //return HttpClients.custom().useSystemProperties().build(); } public static void main(String[] args) throws IOException { - // Alternatively: - // CloseableHttpClient httpClient = setTlsVersionPerConnection(); - // CloseableHttpClient httpClient = setViaSystemProperties(); - try (CloseableHttpClient httpClient = setViaSocketFactory(); - CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + try (CloseableHttpClient httpClient = setViaSocketFactory(); CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/cookies/HttpClientGettingCookieValueUnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/cookies/HttpClientGettingCookieValueUnitTest.java index ef57406705..6a8308483b 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/cookies/HttpClientGettingCookieValueUnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/cookies/HttpClientGettingCookieValueUnitTest.java @@ -14,6 +14,7 @@ import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.http.cookie.ClientCookie; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +52,8 @@ class HttpClientGettingCookieValueUnitTest { private BasicCookieStore createCustomCookieStore() { BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("custom_cookie", "test_value"); - cookie.setDomain("baeldung.com"); - cookie.setAttribute("domain", "true"); + cookie.setDomain("github.com"); + cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie); return cookieStore; diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClient5UnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClient5UnitTest.java index 9a79cbf491..8bf1278c3e 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClient5UnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClient5UnitTest.java @@ -16,7 +16,7 @@ public class ApacheHttpClient5UnitTest { public static final String DUMMY_URL = "https://postman-echo.com/get"; @Test - public void whenUseApacheHttpClient_thenCorrect() throws IOException { + void whenUseApacheHttpClient_thenCorrect() throws IOException { HttpGet request = new HttpGet(DUMMY_URL); try (CloseableHttpClient client = HttpClients.createDefault()) { diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpClientUnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpClientUnitTest.java index 1dca1bf7c6..dcd3e38371 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpClientUnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpClientUnitTest.java @@ -1,6 +1,5 @@ package com.baeldung.httpclient.readresponsebodystring; -import org.junit.Test; import java.io.IOException; import java.net.URI; @@ -8,11 +7,13 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -public class HttpClientUnitTest { +import org.junit.jupiter.api.Test; + +class HttpClientUnitTest { public static final String DUMMY_URL = "https://postman-echo.com/get"; @Test - public void whenUseHttpClient_thenCorrect() throws IOException, InterruptedException { + void whenUseHttpClient_thenCorrect() throws IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder().uri(URI.create(DUMMY_URL)).build(); diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpUrlConnectionUnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpUrlConnectionUnitTest.java index 54ae887eb4..e19fbd6c53 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpUrlConnectionUnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/HttpUrlConnectionUnitTest.java @@ -1,7 +1,7 @@ package com.baeldung.httpclient.readresponsebodystring; -import org.junit.Assert; -import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.BufferedReader; import java.io.IOException; @@ -10,12 +10,14 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; +import org.junit.jupiter.api.Test; + public class HttpUrlConnectionUnitTest { public static final String DUMMY_URL = "https://postman-echo.com/get"; @Test - public void whenUseHttpUrlConnection_thenCorrect() throws IOException { + void whenUseHttpUrlConnection_thenCorrect() throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL(DUMMY_URL).openConnection(); InputStream inputStream = connection.getInputStream(); @@ -28,7 +30,7 @@ public class HttpUrlConnectionUnitTest { response.append(currentLine); in.close(); - Assert.assertNotNull(response.toString()); + assertNotNull(response.toString()); System.out.println("Response -> " + response.toString()); } } diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringRestTemplateUnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringRestTemplateUnitTest.java index c59d7662f1..e06cc165f0 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringRestTemplateUnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringRestTemplateUnitTest.java @@ -1,6 +1,6 @@ package com.baeldung.httpclient.readresponsebodystring; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; public class SpringRestTemplateUnitTest { diff --git a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringWebClientUnitTest.java b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringWebClientUnitTest.java index 9bd2f825ad..df71bab983 100644 --- a/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringWebClientUnitTest.java +++ b/apache-httpclient-2/src/test/java/com/baeldung/httpclient/readresponsebodystring/SpringWebClientUnitTest.java @@ -1,6 +1,6 @@ package com.baeldung.httpclient.readresponsebodystring; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @@ -8,7 +8,7 @@ public class SpringWebClientUnitTest { public static final String DUMMY_URL = "https://postman-echo.com/get"; @Test - public void whenUseWebClientRetrieve_thenCorrect() { + void whenUseWebClientRetrieve_thenCorrect() { WebClient webClient = WebClient.create(DUMMY_URL); Mono body = webClient.get().retrieve().bodyToMono(String.class); String s = body.block(); diff --git a/apache-httpclient-2/src/test/resources/logback.xml b/apache-httpclient-2/src/test/resources/logback.xml index 366a94e86e..dc1bbea439 100644 --- a/apache-httpclient-2/src/test/resources/logback.xml +++ b/apache-httpclient-2/src/test/resources/logback.xml @@ -4,6 +4,7 @@ %date [%level] %logger - %msg %n + diff --git a/apache-httpclient/pom.xml b/apache-httpclient/pom.xml index 5c3ea5b3b3..1b22d64799 100644 --- a/apache-httpclient/pom.xml +++ b/apache-httpclient/pom.xml @@ -15,45 +15,6 @@ - - - org.apache.httpcomponents - httpclient - ${httpclient.version} - - - commons-logging - commons-logging - - - - - org.apache.httpcomponents - fluent-hc - ${httpclient.version} - - - commons-logging - commons-logging - - - - - org.apache.httpcomponents - httpmime - ${httpclient.version} - - - org.apache.httpcomponents - httpasyncclient - ${httpasyncclient.version} - - - commons-logging - commons-logging - - - org.apache.httpcomponents.core5 httpcore5 @@ -115,12 +76,8 @@ - - 4.1.4 - 5.6.1 2.5.1 - 4.5.8 5.2 5.2 diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java index 69eedc8e48..627ac2bd31 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java @@ -4,10 +4,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.apache.hc.core5.http.ParseException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.entity.mime.FileBody; import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; @@ -19,6 +19,7 @@ import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.ParseException; import java.io.BufferedReader; import java.io.File; @@ -30,9 +31,6 @@ import java.net.URL; class HttpClientMultipartLiveTest extends GetRequestMockServer { - // No longer available - // private static final String SERVER = "http://echo.200please.com"; - private static final String SERVER = "http://localhost:8080/spring-mvc-java/stub/multipart"; private static final String TEXTFILENAME = "temp.txt"; private static final String IMAGEFILENAME = "image.jpg"; diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientRedirectLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientRedirectLiveTest.java index 04fad84333..560eb0c8ef 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientRedirectLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientRedirectLiveTest.java @@ -1,15 +1,16 @@ package com.baeldung.httpclient; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import org.junit.jupiter.api.Test; + import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import java.io.IOException; diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java index 2235d0e9d0..3ac3ee88be 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java @@ -1,29 +1,5 @@ package com.baeldung.httpclient.advancedconfig; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.AuthCache; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.DefaultProxyRoutePlanner; -import org.junit.Rule; -import org.junit.Test; - -import java.io.IOException; - import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; @@ -32,18 +8,55 @@ import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class HttpClientAdvancedConfigurationIntegrationTest { +import java.io.IOException; - @Rule - public WireMockRule serviceMock = new WireMockRule(8089); +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.CredentialsProvider; +import org.apache.hc.client5.http.auth.StandardAuthScheme; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.StringEntity; - @Rule - public WireMockRule proxyMock = new WireMockRule(8090); +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.github.tomakehurst.wiremock.WireMockServer; + +class HttpClientAdvancedConfigurationIntegrationTest { + + public WireMockServer serviceMock; + public WireMockServer proxyMock; + + @BeforeEach + public void before () { + serviceMock = new WireMockServer(8089); + serviceMock.start(); + proxyMock = new WireMockServer(8090); + proxyMock.start(); + } + + @AfterEach + public void after () { + serviceMock.stop(); + proxyMock.stop(); + } @Test - public void givenClientWithCustomUserAgentHeader_whenExecuteRequest_shouldReturn200() throws IOException { + void givenClientWithCustomUserAgentHeader_whenExecuteRequest_shouldReturn200() throws IOException { //given String userAgent = "BaeldungAgent/1.0"; serviceMock.stubFor(get(urlEqualTo("/detail")) @@ -59,11 +72,11 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpClient.execute(httpGet); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(200, response.getCode()); } @Test - public void givenClientThatSendDataInBody_whenSendXmlInBody_shouldReturn200() throws IOException { + void givenClientThatSendDataInBody_whenSendXmlInBody_shouldReturn200() throws IOException { //given String xmlBody = "1"; serviceMock.stubFor(post(urlEqualTo("/person")) @@ -82,12 +95,12 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpClient.execute(httpPost); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(200, response.getCode()); } @Test - public void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException { + void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException { //given proxyMock.stubFor(get(urlMatching(".*")) .willReturn(aResponse().proxiedFrom("http://localhost:8089/"))); @@ -107,7 +120,7 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpclient.execute(httpGet); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(200, response.getCode()); proxyMock.verify(getRequestedFor(urlEqualTo("/private"))); serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); } @@ -125,14 +138,12 @@ public class HttpClientAdvancedConfigurationIntegrationTest { DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); // Client credentials - CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(new AuthScope(proxy), - new UsernamePasswordCredentials("username_admin", "secret_password")); - + CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create() + .add(new AuthScope(proxy), "username_admin", "secret_password".toCharArray()) + .build(); // Create AuthCache instance AuthCache authCache = new BasicAuthCache(); - // Generate BASIC scheme object and add it to the local auth cache BasicScheme basicAuth = new BasicScheme(); authCache.put(proxy, basicAuth); @@ -149,10 +160,11 @@ public class HttpClientAdvancedConfigurationIntegrationTest { //when final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + httpGet.setHeader("Authorization", StandardAuthScheme.BASIC); HttpResponse response = httpclient.execute(httpGet, context); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(200, response.getCode()); proxyMock.verify(getRequestedFor(urlEqualTo("/private")).withHeader("Authorization", containing("Basic"))); serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientBasicPostLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientBasicPostLiveTest.java deleted file mode 100644 index 9d4573084b..0000000000 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientBasicPostLiveTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.baeldung.httpclient.base; - -import com.baeldung.httpclient.ResponseUtil; -import org.apache.http.auth.AuthenticationException; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; - -public class HttpClientBasicPostLiveTest { - - private static final String SAMPLE_URL = "http://www.github.com"; - - private CloseableHttpClient instance; - - private CloseableHttpResponse response; - - @Before - public final void before() { - instance = HttpClientBuilder.create().build(); - } - - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - - // tests - non-GET - - @Test - public final void whenExecutingPostRequest_thenNoExceptions() throws IOException { - instance.execute(new HttpPost(SAMPLE_URL)); - } - - @Test - public final void whenExecutingPostRequestWithBody_thenNoExceptions() throws IOException { - final HttpPost request = new HttpPost(SAMPLE_URL); - request.setEntity(new StringEntity("in the body of the POST")); - instance.execute(request); - } - - @Test - public final void givenAuth_whenExecutingPostRequestWithBody_thenNoExceptions() throws IOException, AuthenticationException { - final HttpPost request = new HttpPost(SAMPLE_URL); - request.setEntity(new StringEntity("in the body of the POST")); - final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("username", "password"); - request.addHeader(new BasicScheme().authenticate(creds, request, null)); - instance.execute(request); - } - -} diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java deleted file mode 100644 index b8bc536918..0000000000 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.baeldung.httpclient.base; - -import com.baeldung.httpclient.ResponseUtil; - -import org.apache.http.Header; -import org.apache.http.HttpHeaders; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; - -import static org.hamcrest.Matchers.emptyArray; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; - -public class HttpClientLiveTest { - - private static final String SAMPLE_URL = "http://www.github.com"; - - private CloseableHttpClient instance; - - private CloseableHttpResponse response; - - @Before - public final void before() { - instance = HttpClientBuilder.create().build(); - } - - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - - // tests - - @Test(expected = ConnectTimeoutException.class) - public final void givenLowTimeout_whenExecutingRequestWithTimeout_thenException() throws IOException { - final RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5).setConnectTimeout(5).setSocketTimeout(2).build(); - final HttpGet request = new HttpGet(SAMPLE_URL); - request.setConfig(requestConfig); - response = instance.execute(request); - } - - // tests - configs - - @Test - public final void givenHttpClientIsConfiguredWithCustomConnectionManager_whenExecutingRequest_thenNoExceptions() throws IOException { - instance = HttpClientBuilder.create().setConnectionManager(new BasicHttpClientConnectionManager()).build(); - response = instance.execute(new HttpGet(SAMPLE_URL)); - } - - @Test - public final void givenCustomHeaderIsSet_whenSendingRequest_thenNoExceptions() throws IOException { - final HttpGet request = new HttpGet(SAMPLE_URL); - request.addHeader(HttpHeaders.ACCEPT, "application/xml"); - response = instance.execute(request); - } - - @Test - public final void givenRequestWasSet_whenAnalyzingTheHeadersOfTheResponse_thenCorrect() throws IOException { - response = instance.execute(new HttpGet(SAMPLE_URL)); - - final Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE); - assertThat(headers, not(emptyArray())); - } - -} diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java index 57a8f0a806..b0c60c0ab1 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -1,69 +1,71 @@ package com.baeldung.httpclient.conn; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import org.apache.http.HeaderElement; -import org.apache.http.HeaderElementIterator; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.conn.ConnectionPoolTimeoutException; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicHeaderElementIterator; -import org.apache.http.protocol.HTTP; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpCoreContext; -import org.apache.http.protocol.HttpRequestExecutor; -import org.apache.http.util.EntityUtils; -import org.junit.Ignore; -import org.junit.Test; +import org.apache.hc.client5.http.ConnectionKeepAliveStrategy; +import org.apache.hc.client5.http.HttpRoute; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.io.ConnectionEndpoint; +import org.apache.hc.client5.http.io.LeaseRequest; +import org.apache.hc.core5.http.HeaderElement; +import org.apache.hc.core5.http.HeaderElements; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.MessageSupport; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.pool.PoolStats; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.junit.jupiter.api.Test; -public class HttpClientConnectionManagementLiveTest { +class HttpClientConnectionManagementLiveTest { // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) @Test - public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { - try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - final ConnectionRequest connRequest = connManager.requestConnection(route, null); - assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); - } + final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + assertNotNull(connRequest.get(Timeout.ZERO_MILLISECONDS)); + connMgr.close(); } // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient @Test - public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws IOException { PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(poolingConnManager) .build(); client.execute(new HttpGet("https://www.baeldung.com")); - assertTrue(poolingConnManager.getTotalStats() .getLeased() == 1); + client.close(); + poolingConnManager.close(); } // Example 3.2. Using Two HttpClients to Connect to One Target Host Each @Test - public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); @@ -81,61 +83,71 @@ public class HttpClientConnectionManagementLiveTest { thread1.join(); thread2.join(); - assertTrue(connManager.getTotalStats() - .getLeased() == 0); + assertEquals(0, connManager.getTotalStats().getLeased()); + client1.close(); + client2.close(); + connManager.close(); } // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits @Test - public final void whenIncreasingConnectionPool_thenNoEceptions() { - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setMaxTotal(5); - connManager.setDefaultMaxPerRoute(4); - HttpHost host = new HttpHost("www.baeldung.com", 80); - connManager.setMaxPerRoute(new HttpRoute(host), 5); - } + final void whenIncreasingConnectionPool_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + connManager.close(); } // Example 4.2. Using Threads to Execute Connections @Test - public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + final void whenExecutingSameRequestsInDifferentThreads_thenExecuteRequest() throws InterruptedException, IOException { HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); - MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread4 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread5 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread6 = new MultiHttpClientConnThread(client, get, connManager); thread1.start(); thread2.start(); thread3.start(); + thread4.start(); + thread5.start(); + thread6.start(); thread1.join(); thread2.join(); thread3.join(); + thread4.join(); + thread5.join(); + thread6.join(); + client.close(); + connManager.close(); } // Example 5.1. A Custom Keep Alive Strategy @Test - public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { + final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { @Override - public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { - final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); - while (it.hasNext()) { - final HeaderElement he = it.nextElement(); - final String param = he.getName(); - final String value = he.getValue(); - if ((value != null) && param.equalsIgnoreCase("timeout")) { - return Long.parseLong(value) * 1000; + public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) { + Args.notNull(response, "HTTP response"); + final Iterator it = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE); + final HeaderElement he = it.next(); + final String param = he.getName(); + final String value = he.getValue(); + if (value != null && param.equalsIgnoreCase("timeout")) { + try { + return TimeValue.ofSeconds(Long.parseLong(value)); + } catch (final NumberFormatException ignore) { } } - final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); - if ("localhost".equalsIgnoreCase(target.getHostName())) { - return 10 * 1000; - } else { - return 5 * 1000; - } + return TimeValue.ofSeconds(5); } }; @@ -144,42 +156,38 @@ public class HttpClientConnectionManagementLiveTest { .setKeepAliveStrategy(myStrategy) .setConnectionManager(connManager) .build(); + connManager.close(); } - // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + //Example 6.1. BasicHttpClientConnectionManager Connection Reuse @Test - public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { - BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); - HttpClientContext context = HttpClientContext.create(); - - // low level + final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); - ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); - HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); - basicConnManager.connect(conn, route, 1000, context); - basicConnManager.routeComplete(conn, route, context); + final HttpContext context = new BasicHttpContext(); - HttpRequestExecutor exeRequest = new HttpRequestExecutor(); - context.setTargetHost((new HttpHost("www.baeldung.com", 80))); - HttpGet get = new HttpGet("http://www.baeldung.com"); - exeRequest.execute(get, conn, context); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + final ConnectionEndpoint endpoint = connRequest.get(Timeout.ZERO_MILLISECONDS); + connMgr.connect(endpoint, Timeout.ZERO_MILLISECONDS, context); - basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + connMgr.release(endpoint, null, TimeValue.ZERO_MILLISECONDS); - // high level CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(basicConnManager) + .setConnectionManager(connMgr) .build(); - client.execute(get); + HttpGet httpGet = new HttpGet("https://www.example.com"); + client.execute(httpGet, context, response -> response); + client.close(); + connMgr.close(); } // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads @Test - public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { - HttpGet get = new HttpGet("http://echo.200please.com"); + final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException, IOException { + HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setDefaultMaxPerRoute(5); - connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(6); + connManager.setMaxTotal(6); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); @@ -193,48 +201,71 @@ public class HttpClientConnectionManagementLiveTest { for (MultiHttpClientConnThread thread : threads) { thread.join(1000); } + client.close(); + connManager.close(); } // Example 7.1. Setting Socket Timeout to 5 Seconds @Test - public final void whenConfiguringTimeOut_thenNoExceptions() { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() - .setSoTimeout(5000) - .build()); - assertTrue(connManager.getSocketConfig(route.getTargetHost()) - .getSoTimeout() == 5000); - } + final void whenConfiguringTimeOut_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException, IOException { + final HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final HttpContext context = new BasicHttpContext(); + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + + final ConnectionConfig connConfig = ConnectionConfig.custom() + .setSocketTimeout(5, TimeUnit.SECONDS) + .build(); + + connManager.setDefaultConnectionConfig(connConfig); + + final LeaseRequest leaseRequest = connManager.lease("id1", route, null); + final ConnectionEndpoint endpoint = leaseRequest.get(Timeout.ZERO_MILLISECONDS); + connManager.connect(endpoint, null, context); + connManager.close(); } // Example 8.1. Setting the HttpClient to Check for Stale Connections @Test - public final void whenHttpClientChecksStaleConns_thenNoExceptions() { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setDefaultRequestConfig(RequestConfig.custom() - .setStaleConnectionCheckEnabled(true) - .build()) + final void whenEvictIdealConn_thenNoExceptions() throws InterruptedException, IOException { + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(100); + try (final CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager) - .build(); - } + .evictExpiredConnections() + .evictIdleConnections(TimeValue.ofSeconds(2)) + .build()) { + // create an array of URIs to perform GETs on + final String[] urisToGet = { "http://hc.apache.org/", "http://hc.apache.org/httpcomponents-core-ga/"}; - // Example 8.2. Using a Stale Connection Monitor Thread - @Test - public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setConnectionManager(connManager) - .build(); - IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); - staleMonitor.start(); - staleMonitor.join(1000); + for (final String requestURI : urisToGet) { + final HttpGet request = new HttpGet(requestURI); + + System.out.println("Executing request " + request.getMethod() + " " + request.getRequestUri()); + + httpclient.execute(request, response -> { + System.out.println("----------------------------------------"); + System.out.println(request + "->" + new StatusLine(response)); + EntityUtils.consume(response.getEntity()); + return null; + }); + } + + final PoolStats stats1 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats1.getAvailable()); + + // Sleep 10 sec and let the connection evict or do its job + Thread.sleep(4000); + + final PoolStats stats2 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats2.getAvailable()); + + connManager.close(); + } } // Example 9.1. Closing Connection and Releasing Resources - @Test(expected = IllegalStateException.class) - public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException { + @Test + final void whenClosingConnectionsAndManager_thenCloseWithNoExceptions1() throws IOException { PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) @@ -246,16 +277,11 @@ public class HttpClientConnectionManagementLiveTest { response.close(); client.close(); connManager.close(); - connManager.shutdown(); - - client.execute(get); - - assertTrue(response.getEntity() == null); } @Test // Example 3.2. TESTER VERSION - public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); @@ -273,77 +299,10 @@ public class HttpClientConnectionManagementLiveTest { thread2.start(); thread1.join(); thread2.join(1000); - assertTrue(poolingConnManager.getTotalStats() - .getLeased() == 2); - } + assertEquals(2, poolingConnManager.getTotalStats().getLeased()); - @Test - // Example 4.2 Tester Version - public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - thread1.start(); - thread2.start(); - thread3.start(); - thread1.join(10000); - thread2.join(10000); - thread3.join(10000); - } - - @Test - // 6.2 TESTER VERSION - public final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - poolingConnManager.setDefaultMaxPerRoute(5); - poolingConnManager.setMaxTotal(5); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; - int countConnMade = 0; - for (int i = 0; i < threads.length; i++) { - threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.start(); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.join(10000); - countConnMade++; - if (countConnMade == 0) { - assertTrue(thread.getLeasedConn() == 5); - } - } - } - - @Test - @Ignore("Very Long Running") - // 8.2 TESTER VERSION - public final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); - final HttpGet get = new HttpGet("http://google.com"); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - staleMonitor.start(); - thread1.start(); - thread1.join(); - thread2.start(); - thread2.join(); - thread3.start(); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 1); - thread3.join(32000); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 0); + client1.close(); + client2.close(); + poolingConnManager.close(); } } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java index acadd1f240..9e4b770828 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java @@ -2,12 +2,11 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,22 +44,21 @@ public class MultiHttpClientConnThread extends Thread { try { logger.debug("Thread Running: " + getName()); - logger.debug("Thread Running: " + getName()); if (connManager != null) { logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); } - final HttpResponse response = client.execute(get); + HttpEntity entity = client.execute(get).getEntity(); if (connManager != null) { leasedConn = connManager.getTotalStats().getLeased(); logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); } + EntityUtils.consume(entity); - EntityUtils.consume(response.getEntity()); } catch (final IOException ex) { logger.error("", ex); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java index a50858672e..6703d6880c 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -2,10 +2,9 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/apache-httpclient4/pom.xml b/apache-httpclient4/pom.xml index 21c675db35..f4c213687e 100644 --- a/apache-httpclient4/pom.xml +++ b/apache-httpclient4/pom.xml @@ -241,8 +241,6 @@ 4.4.16 4.5.14 5.11.2 - - 3.3.2 \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java new file mode 100644 index 0000000000..c58763b1c0 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -0,0 +1,64 @@ +package com.baeldung.tlsversion; + +import javax.net.ssl.SSLSocket; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class ClientTlsVersionExamples { + + public static CloseableHttpClient setViaSocketFactory() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + SSLContexts.createDefault(), + new String[] { "TLSv1.2", "TLSv1.3" }, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + public static CloseableHttpClient setTlsVersionPerConnection() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { + + @Override + protected void prepareSocket(SSLSocket socket) { + String hostname = socket.getInetAddress().getHostName(); + if (hostname.endsWith("internal.system.com")) { + socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); + } else { + socket.setEnabledProtocols(new String[] { "TLSv1.3" }); + } + } + }; + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + // To configure the TLS versions for the client, set the https.protocols system property during runtime. + // For example: java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar + public static CloseableHttpClient setViaSystemProperties() { + return HttpClients.createSystem(); + // Alternatively: + // return HttpClients.custom().useSystemProperties().build(); + } + + public static void main(String[] args) throws IOException { + // Alternatively: + // CloseableHttpClient httpClient = setTlsVersionPerConnection(); + // CloseableHttpClient httpClient = setViaSystemProperties(); + try (CloseableHttpClient httpClient = setViaSocketFactory(); + CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + } + } +} \ No newline at end of file diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/HttpClientSandboxLiveTest.java similarity index 82% rename from apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java rename to apache-httpclient4/src/test/java/com/baeldung/client/HttpClientSandboxLiveTest.java index f72aa0c878..c15d8953f2 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/client/HttpClientSandboxLiveTest.java @@ -1,7 +1,7 @@ -package com.baeldung.httpclient.base; +package com.baeldung.client; + +import java.io.IOException; -import com.baeldung.httpclient.GetRequestMockServer; -import com.baeldung.httpclient.ResponseUtil; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; @@ -12,15 +12,16 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.junit.jupiter.api.Test; -import java.io.IOException; +import com.baeldung.GetRequestMockServer; +import com.baeldung.httpclient.ResponseUtil; /* * NOTE : Need module spring-security-rest-basic-auth to be running */ -public class HttpClientSandboxLiveTest extends GetRequestMockServer { +class HttpClientSandboxLiveTest extends GetRequestMockServer { @Test - public final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode() throws IOException { + final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode() throws IOException { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); final AuthScope authscp = new AuthScope("localhost", 8080); credentialsProvider.setCredentials(authscp, new UsernamePasswordCredentials("user1", "user1Pass")); diff --git a/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java index 3c0f5b7c63..98c6a0b4a7 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java @@ -35,7 +35,7 @@ import org.springframework.web.client.RestTemplate; * This test requires a localhost server over HTTPS
* It should only be manually run, not part of the automated build * */ -public class RestClientV4LiveManualTest { +class RestClientV4LiveManualTest { final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; @@ -81,7 +81,7 @@ public class RestClientV4LiveManualTest { } @Test - public void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { + void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); String urlOverHttps = "https://localhost:8082/httpclient-simple"; HttpGet getMethod = new HttpGet(urlOverHttps); diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/ClientUtil.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/ClientUtil.java index ce8a869e97..0b0d7104d7 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/ClientUtil.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/ClientUtil.java @@ -2,8 +2,6 @@ package com.baeldung.httpclient; import java.io.IOException; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.impl.client.CloseableHttpClient; public final class ClientUtil { diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java index 80b16d7f07..90b64092e0 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java @@ -1,4 +1,5 @@ package com.baeldung.httpclient; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java index 446c47c200..6a8a66e87b 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java @@ -9,11 +9,11 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class HttpClientCancelRequestV4LiveTest { +class HttpClientCancelRequestV4LiveTest { private static final String SAMPLE_URL = "http://www.github.com"; @@ -21,18 +21,18 @@ public class HttpClientCancelRequestV4LiveTest { private CloseableHttpResponse response; - @Before + @BeforeEach public final void before() { instance = HttpClientBuilder.create().build(); } - @After + @AfterEach public final void after() throws IllegalStateException, IOException { ResponseUtil.closeResponse(response); } @Test - public final void whenRequestIsCanceled_thenCorrect() throws IOException { + final void whenRequestIsCanceled_thenCorrect() throws IOException { instance = HttpClients.custom().build(); final HttpGet request = new HttpGet(SAMPLE_URL); response = instance.execute(request); diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCookBookV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCookBookV4LiveTest.java index 8b83419ba1..ba77a5c7dd 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCookBookV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCookBookV4LiveTest.java @@ -1,5 +1,9 @@ package com.baeldung.httpclient; +import org.apache.http.auth.AuthenticationException; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -181,4 +185,20 @@ class HttpClientCookBookV4LiveTest { } } + @Test + final void whenExecutingPostRequestWithBody_thenNoExceptions() throws IOException { + final HttpPost request = new HttpPost(SAMPLE_POST_URL); + request.setEntity(new StringEntity("in the body of the POST")); + client.execute(request); + } + + @Test + final void givenAuth_whenExecutingPostRequestWithBody_thenNoExceptions() throws IOException, AuthenticationException { + final HttpPost request = new HttpPost(SAMPLE_POST_URL); + request.setEntity(new StringEntity("in the body of the POST")); + final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("username", "password"); + request.addHeader(new BasicScheme().authenticate(creds, request, null)); + client.execute(request); + } + } diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientRedirectV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientRedirectV4LiveTest.java index f6d65a8d8f..a3f9f3eb47 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientRedirectV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientRedirectV4LiveTest.java @@ -1,12 +1,12 @@ package com.baeldung.httpclient; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - import java.io.IOException; import org.apache.http.client.methods.CloseableHttpResponse; diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java index ed22913ddd..5b3ced8b98 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java @@ -92,6 +92,26 @@ class HttpClientTimeoutV4LiveTest extends GetRequestMockServer { } + @Test + final void givenLowTimeout_whenExecutingRequestWithTimeout_thenException() { + final RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(5) + .setConnectTimeout(5) + .setSocketTimeout(2) + .build(); + + final CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .build(); + + final HttpGet request = new HttpGet("http://www.github.com"); + + assertThrows(ConnectTimeoutException.class, () -> { + response = client.execute(request); + }); + } + + @Test void whenSecuredRestApiIsConsumed_then200OK() throws IOException { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java new file mode 100644 index 0000000000..5ced756644 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java @@ -0,0 +1,173 @@ +package com.baeldung.httpclient.advancedconfig; + +import com.github.tomakehurst.wiremock.WireMockServer; + +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.containing; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HttpClientAdvancedConfigurationIntegrationTest { + + public WireMockServer serviceMock; + public WireMockServer proxyMock; + + @BeforeEach + public void before () { + serviceMock = new WireMockServer(8089); + serviceMock.start(); + proxyMock = new WireMockServer(8090); + proxyMock.start(); + } + + @AfterEach + public void after () { + serviceMock.stop(); + proxyMock.stop(); + } + + @Test + void givenClientWithCustomUserAgentHeader_whenExecuteRequest_shouldReturn200() throws IOException { + //given + String userAgent = "BaeldungAgent/1.0"; + serviceMock.stubFor(get(urlEqualTo("/detail")) + .withHeader("User-Agent", equalTo(userAgent)) + .willReturn(aResponse() + .withStatus(200))); + + HttpClient httpClient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet("http://localhost:8089/detail"); + httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent); + + //when + HttpResponse response = httpClient.execute(httpGet); + + //then + assertEquals(200, response.getStatusLine().getStatusCode()); + } + + @Test + void givenClientThatSendDataInBody_whenSendXmlInBody_shouldReturn200() throws IOException { + //given + String xmlBody = "1"; + serviceMock.stubFor(post(urlEqualTo("/person")) + .withHeader("Content-Type", equalTo("application/xml")) + .withRequestBody(equalTo(xmlBody)) + .willReturn(aResponse() + .withStatus(200))); + + HttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost("http://localhost:8089/person"); + httpPost.setHeader("Content-Type", "application/xml"); + StringEntity xmlEntity = new StringEntity(xmlBody); + httpPost.setEntity(xmlEntity); + + //when + HttpResponse response = httpClient.execute(httpPost); + + //then + assertEquals(200, response.getStatusLine().getStatusCode()); + } + + @Test + void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException { + //given + proxyMock.stubFor(get(urlMatching(".*")) + .willReturn(aResponse().proxiedFrom("http://localhost:8089/"))); + + serviceMock.stubFor(get(urlEqualTo("/private")) + .willReturn(aResponse().withStatus(200))); + + + HttpHost proxy = new HttpHost("localhost", 8090); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + HttpClient httpclient = HttpClients.custom() + .setRoutePlanner(routePlanner) + .build(); + + //when + final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + HttpResponse response = httpclient.execute(httpGet); + + //then + assertEquals(200, response.getStatusLine().getStatusCode()); + proxyMock.verify(getRequestedFor(urlEqualTo("/private"))); + serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); + } + + @Test + void givenServerThatIsBehindAuthorizationProxy_whenClientSendRequest_shouldAuthorizeProperly() throws IOException { + //given + proxyMock.stubFor(get(urlMatching("/private")) + .willReturn(aResponse().proxiedFrom("http://localhost:8089/"))); + serviceMock.stubFor(get(urlEqualTo("/private")) + .willReturn(aResponse().withStatus(200))); + + + HttpHost proxy = new HttpHost("localhost", 8090); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + + // Client credentials + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials("username_admin", "secret_password")); + + + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + + // Generate BASIC scheme object and add it to the local auth cache + BasicScheme basicAuth = new BasicScheme(); + authCache.put(proxy, basicAuth); + HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credentialsProvider); + context.setAuthCache(authCache); + + + HttpClient httpclient = HttpClients.custom() + .setRoutePlanner(routePlanner) + .setDefaultCredentialsProvider(credentialsProvider) + .build(); + + + //when + final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + HttpResponse response = httpclient.execute(httpGet, context); + + //then + assertEquals(200, response.getStatusLine().getStatusCode()); + proxyMock.verify(getRequestedFor(urlEqualTo("/private")).withHeader("Authorization", containing("Basic"))); + serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); + } + + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/expandurl/HttpClientExpandUrlLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/expandurl/HttpClientExpandUrlLiveTest.java index 5a8c87f4aa..c1b04c6728 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/expandurl/HttpClientExpandUrlLiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/expandurl/HttpClientExpandUrlLiveTest.java @@ -12,34 +12,35 @@ import org.apache.http.client.methods.HttpHead; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -public class HttpClientExpandUrlLiveTest { + +class HttpClientExpandUrlLiveTest { private CloseableHttpClient client; - @Before - public final void before() { + @BeforeEach + public final void beforeEach() { client = HttpClientBuilder.create().disableRedirectHandling().build(); } @Test - public final void givenShortenedOnce_whenUrlIsExpanded_thenCorrectResult() throws IOException { + final void givenShortenedOnce_whenUrlIsExpanded_thenCorrectResult() throws IOException { final String expectedResult = "https://www.baeldung.com/rest-versioning"; final String actualResult = expandSingleLevel("http://bit.ly/3LScTri"); assertThat(actualResult, equalTo(expectedResult)); } @Test - public final void givenShortenedMultiple_whenUrlIsExpanded_thenCorrectResult() throws IOException { + final void givenShortenedMultiple_whenUrlIsExpanded_thenCorrectResult() throws IOException { final String expectedResult = "https://www.baeldung.com/rest-versioning"; final String actualResult = expand("http://t.co/e4rDDbnzmk"); assertThat(actualResult, equalTo(expectedResult)); diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java index 9a7a734b65..a7948bcf64 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java @@ -17,7 +17,6 @@ import com.baeldung.GetRequestMockServer; class ApacheHttpClientUnitTest extends GetRequestMockServer { - @Test void givenDeveloperUsedCloseableHttpResponse_whenExecutingGetRequest_thenStatusIsOk() throws IOException { try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java new file mode 100644 index 0000000000..c207aadd28 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -0,0 +1,352 @@ +package com.baeldung.httpclient.httpclient.conn; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.ConnectionRequest; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpCoreContext; +import org.apache.http.protocol.HttpRequestExecutor; +import org.apache.http.util.EntityUtils; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +class HttpClientConnectionManagementLiveTest { + + // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) + @Test + final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { + try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final ConnectionRequest connRequest = connManager.requestConnection(route, null); + assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); + } + } + + // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient + @Test + final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + client.execute(new HttpGet("https://www.baeldung.com")); + + assertEquals(1, poolingConnManager.getTotalStats() + .getLeased()); + } + + // Example 3.2. Using Two HttpClients to Connect to One Target Host Each + @Test + final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client1, get1); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client2, get2); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(); + + assertEquals(0, connManager.getTotalStats() + .getLeased()); + } + + // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits + @Test + final void whenIncreasingConnectionPool_thenNoEceptions() { + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + } + } + + // Example 4.2. Using Threads to Execute Connections + @Test + final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + HttpGet get = new HttpGet("http://www.baeldung.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(); + thread2.join(); + thread3.join(); + } + + // Example 5.1. A Custom Keep Alive Strategy + @Test + final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { + final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { + @Override + public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { + final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + final HeaderElement he = it.nextElement(); + final String param = he.getName(); + final String value = he.getValue(); + if ((value != null) && param.equalsIgnoreCase("timeout")) { + return Long.parseLong(value) * 1000; + } + } + final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); + if ("localhost".equalsIgnoreCase(target.getHostName())) { + return 10 * 1000; + } else { + return 5 * 1000; + } + } + + }; + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setKeepAliveStrategy(myStrategy) + .setConnectionManager(connManager) + .build(); + } + + // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + @Test + final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { + BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); + HttpClientContext context = HttpClientContext.create(); + + // low level + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); + HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); + basicConnManager.connect(conn, route, 1000, context); + basicConnManager.routeComplete(conn, route, context); + + HttpRequestExecutor exeRequest = new HttpRequestExecutor(); + context.setTargetHost((new HttpHost("www.baeldung.com", 80))); + HttpGet get = new HttpGet("http://www.baeldung.com"); + exeRequest.execute(get, conn, context); + + basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + + // high level + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(basicConnManager) + .build(); + client.execute(get); + } + + // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads + @Test + final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { + HttpGet get = new HttpGet("http://echo.200please.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(5); + connManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, get, connManager); + } + for (MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (MultiHttpClientConnThread thread : threads) { + thread.join(1000); + } + } + + // Example 7.1. Setting Socket Timeout to 5 Seconds + @Test + final void whenConfiguringTimeOut_thenNoExceptions() { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() + .setSoTimeout(5000) + .build()); + assertEquals(5000, connManager.getSocketConfig(route.getTargetHost()) + .getSoTimeout()); + } + } + + // Example 8.1. Setting the HttpClient to Check for Stale Connections + @Test + final void whenHttpClientChecksStaleConns_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom() + .setStaleConnectionCheckEnabled(true) + .build()) + .setConnectionManager(connManager) + .build(); + } + + // Example 8.2. Using a Stale Connection Monitor Thread + @Test + final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setConnectionManager(connManager) + .build(); + IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); + staleMonitor.start(); + staleMonitor.join(1000); + } + + // Example 9.1. Closing Connection and Releasing Resources + @Test + final void whenClosingConnectionsAndManager_thenCloseWithNoExceptions1() throws IOException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + final HttpGet get = new HttpGet("http://google.com"); + CloseableHttpResponse response = client.execute(get); + + EntityUtils.consume(response.getEntity()); + response.close(); + client.close(); + connManager.close(); + connManager.shutdown(); + + assertThrows(IllegalStateException.class, () -> { + client.execute(get); + }); + } + + @Test + // Example 3.2. TESTER VERSION + final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + final CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client1, get1, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client2, get2, poolingConnManager); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(1000); + assertEquals(2, poolingConnManager.getTotalStats() + .getLeased()); + } + + @Test + // Example 4.2 Tester Version + final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(10000); + thread2.join(10000); + thread3.join(10000); + } + + @Test + // 6.2 TESTER VERSION + final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + poolingConnManager.setDefaultMaxPerRoute(5); + poolingConnManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + int countConnMade = 0; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.join(10000); + countConnMade++; + if (countConnMade == 0) { + assertEquals(5, thread.getLeasedConn()); + } + } + } + + @Test + @Disabled("Very Long Running") + // 8.2 TESTER VERSION + final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); + final HttpGet get = new HttpGet("http://google.com"); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + staleMonitor.start(); + thread1.start(); + thread1.join(); + thread2.start(); + thread2.join(); + thread3.start(); + assertEquals(1, poolingConnManager.getTotalStats() + .getAvailable()); + thread3.join(32000); + assertEquals(0, poolingConnManager.getTotalStats() + .getAvailable()); + } +} diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/IdleConnectionMonitorThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java similarity index 95% rename from apache-httpclient/src/test/java/com/baeldung/httpclient/conn/IdleConnectionMonitorThread.java rename to apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java index f1d7cbc427..4bf97e4fa6 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/IdleConnectionMonitorThread.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java @@ -1,4 +1,4 @@ -package com.baeldung.httpclient.conn; +package com.baeldung.httpclient.httpclient.conn; import java.util.concurrent.TimeUnit; diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java new file mode 100644 index 0000000000..b09a06050b --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java @@ -0,0 +1,68 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + + private PoolingHttpClientConnectionManager connManager; + private int leasedConn; + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = connManager; + leasedConn = 0; + } + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get) { + this.client = client; + this.get = get; + } + + // API + + final int getLeasedConn() { + return leasedConn; + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.debug("Thread Running: " + getName()); + + if (connManager != null) { + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + final HttpResponse response = client.execute(get); + + if (connManager != null) { + leasedConn = connManager.getTotalStats().getLeased(); + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + EntityUtils.consume(response.getEntity()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java new file mode 100644 index 0000000000..cd4979541e --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -0,0 +1,45 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class TesterVersion_MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + private PoolingHttpClientConnectionManager connManager; + + TesterVersion_MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = Preconditions.checkNotNull(connManager); + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + + client.execute(get); + + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClientUnitTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClientUnitTest.java index 4d88211d0d..a47a5cc743 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClientUnitTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/readresponsebodystring/ApacheHttpClientUnitTest.java @@ -6,18 +6,19 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; -import org.junit.Test; + +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -public class ApacheHttpClientUnitTest { +class ApacheHttpClientUnitTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public static final String DUMMY_URL = "https://postman-echo.com/get"; @Test - public void whenUseApacheHttpClient_thenCorrect() throws IOException { + void whenUseApacheHttpClient_thenCorrect() throws IOException { HttpGet request = new HttpGet(DUMMY_URL); try (CloseableHttpClient client = HttpClients.createDefault(); CloseableHttpResponse response = client.execute(request)) { diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/retry/ApacheHttpClientRetryLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/retry/ApacheHttpClientRetryLiveTest.java index 3a8ff252c2..f04ebff3f8 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/retry/ApacheHttpClientRetryLiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/retry/ApacheHttpClientRetryLiveTest.java @@ -24,7 +24,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class ApacheHttpClientRetryLiveTest { +class ApacheHttpClientRetryLiveTest { private Integer requestCounter; private CloseableHttpClient httpClient; @@ -93,14 +93,14 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenDefaultConfiguration_whenReceivedIOException_thenRetriesPerformed() { + void givenDefaultConfiguration_whenReceivedIOException_thenRetriesPerformed() { createFailingHttpClient(); assertThrows(IOException.class, () -> httpClient.execute(new HttpGet("https://httpstat.us/200"))); assertThat(requestCounter).isEqualTo(4); } @Test - public void givenDefaultConfiguration_whenDomainNameNotResolved_thenNoRetryApplied() { + void givenDefaultConfiguration_whenDomainNameNotResolved_thenNoRetryApplied() { createDefaultApacheHttpClient(); HttpGet request = new HttpGet(URI.create("http://domain.that.does.not.exist:80/api/v1")); @@ -109,7 +109,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenDefaultConfiguration_whenGotInternalServerError_thenNoRetryLogicApplied() throws IOException { + void givenDefaultConfiguration_whenGotInternalServerError_thenNoRetryLogicApplied() throws IOException { createDefaultApacheHttpClient(); HttpGet request = new HttpGet(URI.create("https://httpstat.us/500")); @@ -120,7 +120,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenDefaultConfiguration_whenHttpPatchRequest_thenRetryIsNotApplied() { + void givenDefaultConfiguration_whenHttpPatchRequest_thenRetryIsNotApplied() { createFailingHttpClient(); HttpPatch request = new HttpPatch(URI.create("https://httpstat.us/500")); @@ -129,7 +129,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenDefaultConfiguration_whenHttpPutRequest_thenRetryIsNotApplied() { + void givenDefaultConfiguration_whenHttpPutRequest_thenRetryIsNotApplied() { createFailingHttpClient(); HttpPut request = new HttpPut(URI.create("https://httpstat.us/500")); @@ -138,7 +138,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenConfiguredRetryHandler_whenHttpPostRequest_thenRetriesPerformed() { + void givenConfiguredRetryHandler_whenHttpPostRequest_thenRetriesPerformed() { createHttpClientWithRetryHandler(); HttpPost request = new HttpPost(URI.create("https://httpstat.us/200")); @@ -148,7 +148,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenCustomRetryHandler_whenUnknownHostException_thenRetryAnyway() { + void givenCustomRetryHandler_whenUnknownHostException_thenRetryAnyway() { createHttpClientWithCustomRetryHandler(); HttpGet request = new HttpGet(URI.create("https://domain.that.does.not.exist/200")); @@ -158,7 +158,7 @@ public class ApacheHttpClientRetryLiveTest { } @Test - public void givenDisabledRetries_whenExecutedHttpRequestEndUpWithIOException_thenRetryIsNotApplied() { + void givenDisabledRetries_whenExecutedHttpRequestEndUpWithIOException_thenRetryIsNotApplied() { createHttpClientWithRetriesDisabled(); HttpGet request = new HttpGet(URI.create("https://httpstat.us/200")); diff --git a/apache-kafka-2/README.md b/apache-kafka-2/README.md index 81239d4a7b..40ee701be1 100644 --- a/apache-kafka-2/README.md +++ b/apache-kafka-2/README.md @@ -12,3 +12,5 @@ You can build the project from the command line using: *mvn clean install*, or i - [Is a Key Required as Part of Sending Messages to Kafka?](https://www.baeldung.com/java-kafka-message-key) - [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read) - [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) +- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server) +- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka) diff --git a/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java b/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java new file mode 100644 index 0000000000..7501b40056 --- /dev/null +++ b/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java @@ -0,0 +1,39 @@ +package com.baeldung.kafka.consumer; + +import org.apache.kafka.clients.consumer.*; +import org.apache.kafka.common.serialization.LongDeserializer; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; + +public class SimpleConsumerWithBootStrapServers { + + public static void main(String[] args) { + try(final Consumer consumer = createConsumer()) { + ConsumerRecords records = consumer.poll(Duration.ofMinutes(1)); + for(ConsumerRecord record : records) { + System.out.println(record.value()); + } + } + } + + private static Consumer createConsumer() { + final Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + "localhost:9092,another-host.com:29092"); + props.put(ConsumerConfig.GROUP_ID_CONFIG, + "MySampleConsumer"); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, + LongDeserializer.class.getName()); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, + StringDeserializer.class.getName()); + // Create the consumer using props. + final Consumer consumer = new KafkaConsumer(props); + // Subscribe to the topic. + consumer.subscribe(Arrays.asList("samples")); + return consumer; + } + +} diff --git a/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java new file mode 100644 index 0000000000..653456a678 --- /dev/null +++ b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java @@ -0,0 +1,103 @@ +package com.baeldung.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.ExecutionException; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +// This live test needs a Docker Daemon running so that a kafka container can be created + +@Testcontainers +public class MultipleTopicsLiveTest { + + private final Logger log = LoggerFactory.getLogger(MultipleTopicsLiveTest.class); + + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + private static KafkaProducer producer; + private static KafkaConsumer consumer; + + @Container + private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest")); + + @BeforeAll + static void setup() { + KAFKA_CONTAINER.addExposedPort(9092); + producer = new KafkaProducer<>(getProducerProperties()); + consumer = new KafkaConsumer<>(getConsumerProperties()); + } + + @AfterAll + static void destroy() { + KAFKA_CONTAINER.stop(); + } + + private static Properties getProducerProperties() { + Properties producerProperties = new Properties(); + producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + return producerProperties; + } + + private static Properties getConsumerProperties() { + Properties consumerProperties = new Properties(); + consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "payments"); + return consumerProperties; + } + + @Test + void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + publishMessages(); + + consumer.subscribe(Arrays.asList(CARD_PAYMENTS_TOPIC, BANK_TRANSFERS_TOPIC)); + + int eventsProcessed = 0; + for (ConsumerRecord record : consumer.poll(Duration.ofSeconds(10))) { + log.info("Event on topic={}, payload={}", record.topic(), record.value()); + eventsProcessed++; + } + + assertThat(eventsProcessed).isEqualTo(2); + } + + private void publishMessages() throws ExecutionException, InterruptedException { + ProducerRecord cardPayment = new ProducerRecord<>(CARD_PAYMENTS_TOPIC, createCardPayment()); + producer.send(cardPayment).get(); + + ProducerRecord bankTransfer = new ProducerRecord<>(BANK_TRANSFERS_TOPIC, createBankTransfer()); + producer.send(bankTransfer).get(); + } + + private String createCardPayment() { + return "{\"paymentReference\":\"A184028KM0013790\", \"type\":\"card\", \"amount\":\"275\", \"currency\":\"GBP\"}"; + } + + private String createBankTransfer() { + return "{\"paymentReference\":\"19ae2-18mk73-009\", \"type\":\"bank\", \"amount\":\"150\", \"currency\":\"EUR\"}"; + } +} diff --git a/apache-libraries-2/README.md b/apache-libraries-2/README.md new file mode 100644 index 0000000000..cc910c5c2c --- /dev/null +++ b/apache-libraries-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Understanding XSLT Processing in Java](https://www.baeldung.com/java-extensible-stylesheet-language-transformations) diff --git a/guest/memory-leaks/pom.xml b/apache-libraries-2/pom.xml similarity index 50% rename from guest/memory-leaks/pom.xml rename to apache-libraries-2/pom.xml index 42bb71617d..d188204208 100644 --- a/guest/memory-leaks/pom.xml +++ b/apache-libraries-2/pom.xml @@ -3,28 +3,26 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - memory-leaks + apache-libraries-2 0.0.1-SNAPSHOT - memory-leaks + apache-libraries-2 com.baeldung parent-modules 1.0.0-SNAPSHOT - ../../ - - - - src/main/resources/ - - **/*.java - - - - src/test/resources/ - - - + + + javax.validation + validation-api + ${javax.validation.validation-api.version} + + + + + 2.0.1.Final + + \ No newline at end of file diff --git a/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java b/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java new file mode 100644 index 0000000000..6bc0023485 --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java @@ -0,0 +1,18 @@ +package com.baeldung.xslt; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.File; + +public class XSLTProcessor { + public static void transformXMLUsingXSLT(String inputXMLPath, String xsltPath, String outputHTMLPath) throws TransformerException { + Source xmlSource = new StreamSource(new File(inputXMLPath)); + Source xsltSource = new StreamSource(new File(xsltPath)); + Result output = new StreamResult(new File(outputHTMLPath)); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(xsltSource); + transformer.transform(xmlSource, output); + } +} diff --git a/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithParametersAndOption.java b/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithParametersAndOption.java new file mode 100644 index 0000000000..07efab080d --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithParametersAndOption.java @@ -0,0 +1,31 @@ +package com.baeldung.xsltProcessing; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.File; + +public class XSLTProcessorWithParametersAndOption { + public static void transformXMLWithParametersAndOption( + String inputXMLPath, + String xsltPath, + String outputHTMLPath, + String companyName, + boolean enableIndentation + ) throws TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Source xsltSource = new StreamSource(new File(xsltPath)); + Transformer transformer = transformerFactory.newTransformer(xsltSource); + + transformer.setParameter("companyName", companyName); + + if (enableIndentation) { + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + } + + Source xmlSource = new StreamSource(new File(inputXMLPath)); + Result outputResult = new StreamResult(new File(outputHTMLPath)); + + transformer.transform(xmlSource, outputResult); + } +} diff --git a/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithTemplate.java b/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithTemplate.java new file mode 100644 index 0000000000..017fc0db8b --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/xsltProcessing/XSLTProcessorWithTemplate.java @@ -0,0 +1,21 @@ +package com.baeldung.xsltProcessing; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.File; + +public class XSLTProcessorWithTemplate { + public static void transformXMLUsingTemplate(String inputXMLPath, String xsltPath, String outputHTMLPath) throws TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Source xsltSource = new StreamSource(new File(xsltPath)); + Templates templates = transformerFactory.newTemplates(xsltSource); + + Transformer transformer = templates.newTransformer(); + + Source xmlSource = new StreamSource(new File(inputXMLPath)); + Result outputResult = new StreamResult(new File(outputHTMLPath)); + + transformer.transform(xmlSource, outputResult); + } +} diff --git a/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc b/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc new file mode 100644 index 0000000000..18179a9cde --- /dev/null +++ b/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc @@ -0,0 +1,47 @@ +{ + "type":"record", + "name":"AvroHttpRequest", + "namespace":"com.baeldung.avro.model", + "fields":[ + { + "name":"requestTime", + "type":"long" + }, + { + "name":"clientIdentifier", + "type":{ + "type":"record", + "name":"ClientIdentifier", + "fields":[ + { + "name":"hostName", + "type":"string" + }, + { + "name":"ipAddress", + "type":"string" + } + ] + } + }, + { + "name":"employeeNames", + "type":{ + "type":"array", + "items":"string" + }, + "default":null + }, + { + "name":"active", + "type":{ + "type":"enum", + "name":"Active", + "symbols":[ + "YES", + "NO" + ] + } + } + ] +} \ No newline at end of file diff --git a/apache-libraries-2/src/main/resources/log4j2.xml b/apache-libraries-2/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..d1ea5173fa --- /dev/null +++ b/apache-libraries-2/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/annotations/annotation-processing/src/main/resources/logback.xml b/apache-libraries-2/src/main/resources/logback.xml similarity index 100% rename from annotations/annotation-processing/src/main/resources/logback.xml rename to apache-libraries-2/src/main/resources/logback.xml diff --git a/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java b/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java new file mode 100644 index 0000000000..cbfbf78c87 --- /dev/null +++ b/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.xslt; + +import org.junit.jupiter.api.Test; + +import javax.xml.transform.TransformerException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class XSLTProcessorUnitTest { + + @Test + public void givenValidInputAndStylesheet_whenTransformingXML_thenOutputHTMLCreated() throws TransformerException, IOException { + // Given + String inputXMLPath = "src/test/resources/input.xml"; + String xsltPath = "src/test/resources/stylesheet.xslt"; + String outputHTMLPath = "src/test/resources/output.html"; + + + XSLTProcessor.transformXMLUsingXSLT(inputXMLPath, xsltPath, outputHTMLPath); + + + Path outputFile = Paths.get(outputHTMLPath); + assertTrue(Files.exists(outputFile)); + } +} diff --git a/apache-libraries-2/src/test/resources/input.xml b/apache-libraries-2/src/test/resources/input.xml new file mode 100644 index 0000000000..e283680337 --- /dev/null +++ b/apache-libraries-2/src/test/resources/input.xml @@ -0,0 +1,11 @@ + + + + John Doe + 30 + + + Jane Smith + 25 + + diff --git a/apache-libraries-2/src/test/resources/output.html b/apache-libraries-2/src/test/resources/output.html new file mode 100644 index 0000000000..b75e73ca15 --- /dev/null +++ b/apache-libraries-2/src/test/resources/output.html @@ -0,0 +1,3 @@ + +

Male person: John Doe, Age: 30

+

Female person: Jane Smith, Age: 25

diff --git a/apache-libraries-2/src/test/resources/stylesheet.xslt b/apache-libraries-2/src/test/resources/stylesheet.xslt new file mode 100644 index 0000000000..9f07852a2a --- /dev/null +++ b/apache-libraries-2/src/test/resources/stylesheet.xslt @@ -0,0 +1,22 @@ + + + + + + Male person: + + , Age: + + + + + + + Female person: + + , Age: + + + + + diff --git a/apache-poi-2/README.md b/apache-poi-2/README.md index 0132147201..65641e7c37 100644 --- a/apache-poi-2/README.md +++ b/apache-poi-2/README.md @@ -13,4 +13,5 @@ This module contains articles about Apache POI. - [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) - [Set the Date Format Using Apache POI](https://www.baeldung.com/java-apache-poi-date-format) - [Replacing Variables in a Document Template with Java](https://www.baeldung.com/java-replace-pattern-word-document-doc-docx) +- [Lock Header Rows With Apache POI](https://www.baeldung.com/java-apache-poi-lock-header-rows) - More articles: [[<-- prev]](../apache-poi) diff --git a/apache-poi-3/README.md b/apache-poi-3/README.md new file mode 100644 index 0000000000..9e9d6a94eb --- /dev/null +++ b/apache-poi-3/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [How To Convert Excel Data Into List Of Java Objects](https://www.baeldung.com/java-convert-excel-data-into-list) +- [Expand Columns with Apache POI](https://www.baeldung.com/java-apache-poi-expand-columns) diff --git a/apache-poi-3/pom.xml b/apache-poi-3/pom.xml new file mode 100644 index 0000000000..e6e85d1212 --- /dev/null +++ b/apache-poi-3/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + apache-poi-3 + 0.0.1-SNAPSHOT + apache-poi-3 + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + org.apache.poi + poi-scratchpad + ${poi.version} + + + + com.github.ozlerhakan + poiji + ${poiji.version} + + + + + org.apache.poi + poi + ${poi.version} + + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + + org.apache.xmlbeans + xmlbeans + 5.1.1 + + + + org.apache.commons + commons-collections4 + 4.4 + + + + org.dhatim + fastexcel + ${fastexcel.version} + + + + org.dhatim + fastexcel-reader + ${fastexcel.version} + + + + net.sourceforge.jexcelapi + jxl + ${jxl.version} + + + + org.apache.logging.log4j + log4j-api + 2.17.1 + + + + org.apache.logging.log4j + log4j-core + 2.17.1 + + + + + 5.2.3 + 4.1.1 + 0.15.7 + 2.6.12 + + + \ No newline at end of file diff --git a/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/FoodInfo.java b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/FoodInfo.java new file mode 100644 index 0000000000..b8fe4522de --- /dev/null +++ b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/FoodInfo.java @@ -0,0 +1,54 @@ +package com.baeldung.convert.exceldatatolist; + +import com.poiji.annotation.ExcelCellName; + +public class FoodInfo { + + @ExcelCellName("Category") + private String category; //food category + @ExcelCellName("Name") + private String name; // food name + @ExcelCellName("Measure") + private String measure; + @ExcelCellName("Calories") + private double calories; //amount of calories in kcal/measure + + @Override + public String toString() { + return "FoodInfo{" + "category='" + category + '\'' + ", name='" + name + '\'' + ", measure='" + measure + '\'' + ", calories=" + calories + "} \n"; + } + + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMeasure() { + return measure; + } + + public void setMeasure(String measure) { + this.measure = measure; + } + + public double getCalories() { + return calories; + } + + public void setCalories(double calories) { + this.calories = calories; + } + +} diff --git a/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/fastexcel/ExcelDataToListOfObjectsFastExcel.java b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/fastexcel/ExcelDataToListOfObjectsFastExcel.java new file mode 100644 index 0000000000..87d31520e6 --- /dev/null +++ b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/fastexcel/ExcelDataToListOfObjectsFastExcel.java @@ -0,0 +1,42 @@ +package com.baeldung.convert.exceldatatolist.fastexcel; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + +import org.dhatim.fastexcel.reader.ReadableWorkbook; +import org.dhatim.fastexcel.reader.Row; +import org.dhatim.fastexcel.reader.Sheet; + +import com.baeldung.convert.exceldatatolist.FoodInfo; + +public class ExcelDataToListOfObjectsFastExcel { + public static List excelDataToListOfObjets_withFastExcel(String fileLocation)throws IOException, NumberFormatException { + List foodData = new ArrayList(); + + try (FileInputStream file = new FileInputStream(fileLocation); + ReadableWorkbook wb = new ReadableWorkbook(file)) { + Sheet sheet = wb.getFirstSheet(); + for (Row row: + sheet.read() + ) { + if(row.getRowNum() == 1) { + continue; + } + FoodInfo food = new FoodInfo(); + food.setCategory(row.getCellText(0)); + food.setName(row.getCellText(1)); + food.setMeasure(row.getCellText(2)); + food.setCalories(Double.parseDouble(row.getCellText(3))); + + foodData.add(food); + + } + } + + return foodData; + } +} diff --git a/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/jexcelapi/ExcelDataToListOfObjectsJxl.java b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/jexcelapi/ExcelDataToListOfObjectsJxl.java new file mode 100644 index 0000000000..61ba5e4700 --- /dev/null +++ b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/jexcelapi/ExcelDataToListOfObjectsJxl.java @@ -0,0 +1,37 @@ +package com.baeldung.convert.exceldatatolist.jexcelapi; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.baeldung.convert.exceldatatolist.FoodInfo; + +import jxl.Sheet; +import jxl.Workbook; +import jxl.read.biff.BiffException; + +public class ExcelDataToListOfObjectsJxl { + public static List excelDataToListOfObjets_withJxl(String fileLocation) throws IOException, BiffException { + + List foodData = new ArrayList(); + + Workbook workbook = Workbook.getWorkbook(new File(fileLocation)); + Sheet sheet = workbook.getSheet(0); + + int rows = sheet.getRows(); + + for (int i = 1; i < rows; i++) { + FoodInfo foodInfo = new FoodInfo(); + + foodInfo.setCategory(sheet.getCell(0, i).getContents()); + foodInfo.setName(sheet.getCell(1, i).getContents()); + foodInfo.setMeasure(sheet.getCell(2, i).getContents()); + foodInfo.setCalories(Double.parseDouble(sheet.getCell(3, i).getContents())); + + foodData.add(foodInfo); + + } + return foodData; + } +} diff --git a/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poi/ExcelDataToListApachePOI.java b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poi/ExcelDataToListApachePOI.java new file mode 100644 index 0000000000..8b568b889a --- /dev/null +++ b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poi/ExcelDataToListApachePOI.java @@ -0,0 +1,39 @@ +package com.baeldung.convert.exceldatatolist.poi; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import com.baeldung.convert.exceldatatolist.FoodInfo; + +public class ExcelDataToListApachePOI { + public static List excelDataToListOfObjets_withApachePOI(String fileLocation) throws IOException { + FileInputStream file = new FileInputStream(new File(fileLocation)); + Workbook workbook = new XSSFWorkbook(file); + Sheet sheet = workbook.getSheetAt(0); + List foodData = new ArrayList(); + DataFormatter dataFormatter = new DataFormatter(); + for (int n = 1; n < sheet.getPhysicalNumberOfRows(); n++) { + Row row = sheet.getRow(n); + FoodInfo foodInfo = new FoodInfo(); + int i = row.getFirstCellNum(); + + foodInfo.setCategory(dataFormatter.formatCellValue(row.getCell(i))); + foodInfo.setName(dataFormatter.formatCellValue(row.getCell(++i))); + foodInfo.setMeasure(dataFormatter.formatCellValue(row.getCell(++i))); + foodInfo.setCalories(Double.parseDouble(dataFormatter.formatCellValue(row.getCell(++i)))); + + foodData.add(foodInfo); + + } + return foodData; + } +} diff --git a/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poiji/ExcelDataToListOfObjectsPOIJI.java b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poiji/ExcelDataToListOfObjectsPOIJI.java new file mode 100644 index 0000000000..be190d38f7 --- /dev/null +++ b/apache-poi-3/src/main/java/com/baeldung/convert/exceldatatolist/poiji/ExcelDataToListOfObjectsPOIJI.java @@ -0,0 +1,13 @@ +package com.baeldung.convert.exceldatatolist.poiji; + +import java.io.File; +import java.util.List; + +import com.baeldung.convert.exceldatatolist.FoodInfo; +import com.poiji.bind.Poiji; + +public class ExcelDataToListOfObjectsPOIJI { + public static List excelDataToListOfObjets_withPOIJI(String fileLocation){ + return Poiji.fromExcel(new File(fileLocation), FoodInfo.class); + } +} diff --git a/apache-poi-3/src/main/resources/food_info.xls b/apache-poi-3/src/main/resources/food_info.xls new file mode 100644 index 0000000000..1377d8e18d Binary files /dev/null and b/apache-poi-3/src/main/resources/food_info.xls differ diff --git a/apache-poi-3/src/main/resources/food_info.xlsx b/apache-poi-3/src/main/resources/food_info.xlsx new file mode 100644 index 0000000000..c604ff367d Binary files /dev/null and b/apache-poi-3/src/main/resources/food_info.xlsx differ diff --git a/apache-poi-3/src/test/java/com/baeldung/convert/exceldatatolist/ExcelDataToListOfObjectsUnitTest.java b/apache-poi-3/src/test/java/com/baeldung/convert/exceldatatolist/ExcelDataToListOfObjectsUnitTest.java new file mode 100644 index 0000000000..5d65c04b31 --- /dev/null +++ b/apache-poi-3/src/test/java/com/baeldung/convert/exceldatatolist/ExcelDataToListOfObjectsUnitTest.java @@ -0,0 +1,53 @@ +package com.baeldung.convert.exceldatatolist; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.List; + +// import org.junit.jupiter.api.Test; +// import static org.junit.jupiter.api.Assertions.*; +import org.junit.Test; + +import com.baeldung.convert.exceldatatolist.fastexcel.ExcelDataToListOfObjectsFastExcel; +import com.baeldung.convert.exceldatatolist.jexcelapi.ExcelDataToListOfObjectsJxl; +import com.baeldung.convert.exceldatatolist.poi.ExcelDataToListApachePOI; +import com.baeldung.convert.exceldatatolist.poiji.ExcelDataToListOfObjectsPOIJI; + +import jxl.read.biff.BiffException; + +public class ExcelDataToListOfObjectsUnitTest { + + @Test + public void whenParsingExcelFileWithPOIJI_thenConvertsToList() throws IOException { + List foodInfoList = ExcelDataToListOfObjectsPOIJI.excelDataToListOfObjets_withPOIJI("src/main/resources/food_info.xlsx"); + + assertEquals("Beverages", foodInfoList.get(0).getCategory()); + assertEquals("Dairy", foodInfoList.get(3).getCategory()); + } + + @Test + public void whenParsingExcelFileWithApachePOI_thenConvertsToList() throws IOException { + List foodInfoList = ExcelDataToListApachePOI.excelDataToListOfObjets_withApachePOI("src/main/resources/food_info.xlsx"); + + assertEquals("Beverages", foodInfoList.get(0).getCategory()); + assertEquals("Dairy", foodInfoList.get(3).getCategory()); + } + + @Test + public void whenParsingExcelFileWithFastExcel_thenConvertsToList() throws IOException { + List foodInfoList = ExcelDataToListOfObjectsFastExcel.excelDataToListOfObjets_withFastExcel("src/main/resources/food_info.xlsx"); + + assertEquals("Beverages", foodInfoList.get(0).getCategory()); + assertEquals("Dairy", foodInfoList.get(3).getCategory()); + } + + @Test + public void whenParsingExcelFileWithJxl_thenConvertsToList() throws IOException, BiffException { + List foodInfoList = ExcelDataToListOfObjectsJxl.excelDataToListOfObjets_withJxl("src/main/resources/food_info.xls"); + + assertEquals("Beverages", foodInfoList.get(0).getCategory()); + assertEquals("Dairy", foodInfoList.get(3).getCategory()); + } + +} diff --git a/apache-poi-3/src/test/java/com/baeldung/poi/excel/expandcolumn/ExpandColumnUnitTest.java b/apache-poi-3/src/test/java/com/baeldung/poi/excel/expandcolumn/ExpandColumnUnitTest.java new file mode 100644 index 0000000000..04d0aef211 --- /dev/null +++ b/apache-poi-3/src/test/java/com/baeldung/poi/excel/expandcolumn/ExpandColumnUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.poi.excel.expandcolumn; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; + +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ExpandColumnUnitTest { + + private Workbook workbook; + private Sheet sheet; + + @BeforeEach + void prepareSpreadsheet() { + workbook = new XSSFWorkbook(); + sheet = workbook.createSheet(); + + Row headerRow = sheet.createRow(0); + Cell headerCell1 = headerRow.createCell(0); + headerCell1.setCellValue("Full Name"); + Cell headerCell2 = headerRow.createCell(1); + headerCell2.setCellValue("Abbreviation"); + + Row dataRow = sheet.createRow(1); + Cell dataCell1 = dataRow.createCell(0); + dataCell1.setCellValue("Java Virtual Machine"); + Cell dataCell2 = dataRow.createCell(1); + dataCell2.setCellValue("JVM"); + + dataRow = sheet.createRow(2); + dataCell1 = dataRow.createCell(0); + dataCell1.setCellValue("Java Runtime Environment"); + dataCell2 = dataRow.createCell(1); + dataCell2.setCellValue("JRE"); + } + + @Test + void whenSetColumnWidth_thenColumnSetToTheSpecifiedWidth() { + + Row row = sheet.getRow(2); + String cellValue = row.getCell(0).getStringCellValue(); + int targetWidth = cellValue.length() * 256; + + sheet.setColumnWidth(0, targetWidth); + + assertEquals(targetWidth, sheet.getColumnWidth(0)); + } + + @Test + void whenAutoSizeColumn_thenColumnExpands() { + + int originalWidth = sheet.getColumnWidth(0); + + sheet.autoSizeColumn(0); + + assertThat(sheet.getColumnWidth(0)).isGreaterThan(originalWidth); + } + + @AfterEach + void cleanup() throws IOException { + workbook.close(); + } + +} \ No newline at end of file diff --git a/apache-velocity/pom.xml b/apache-velocity/pom.xml index a562ebeec0..f4b6de8872 100644 --- a/apache-velocity/pom.xml +++ b/apache-velocity/pom.xml @@ -63,7 +63,6 @@ 4.5.2 1.7 2.0 - 3.3.2 \ No newline at end of file diff --git a/asm/pom.xml b/asm/pom.xml index f1e60d2560..4edfe86ae5 100644 --- a/asm/pom.xml +++ b/asm/pom.xml @@ -49,7 +49,6 @@ 5.2 - 2.4 \ No newline at end of file diff --git a/aws-modules/aws-dynamodb/.gitignore b/aws-modules/aws-dynamodb/.gitignore new file mode 100644 index 0000000000..bf11a4cc38 --- /dev/null +++ b/aws-modules/aws-dynamodb/.gitignore @@ -0,0 +1,2 @@ +/target/ +.idea/ \ No newline at end of file diff --git a/aws-modules/aws-dynamodb/README.md b/aws-modules/aws-dynamodb/README.md new file mode 100644 index 0000000000..68a353e555 --- /dev/null +++ b/aws-modules/aws-dynamodb/README.md @@ -0,0 +1,7 @@ +## AWS DYNAMODB + +This module contains articles about AWS DynamoDB + +### Relevant articles +- [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests) + diff --git a/aws-modules/aws-dynamodb/pom.xml b/aws-modules/aws-dynamodb/pom.xml new file mode 100644 index 0000000000..37b88327f4 --- /dev/null +++ b/aws-modules/aws-dynamodb/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + aws-dynamodb + 0.1.0-SNAPSHOT + aws-dynamodb + jar + + + com.baeldung + aws-modules + 1.0.0-SNAPSHOT + + + + + com.amazonaws + aws-java-sdk + ${aws-java-sdk.version} + + + com.amazonaws + DynamoDBLocal + ${dynamodblocal.version} + test + + + commons-io + commons-io + ${commons-io.version} + + + com.google.code.gson + gson + ${gson.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + false + + + + package + + shade + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-plugins-version} + + + copy + compile + + copy-dependencies + + + + so,dll,dylib + native-libs + + + + + + + + + 2.8.0 + 1.21.1 + 3.1.1 + + + \ No newline at end of file diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java diff --git a/annotations/annotation-user/src/main/resources/logback.xml b/aws-modules/aws-dynamodb/src/main/resources/logback.xml similarity index 100% rename from annotations/annotation-user/src/main/resources/logback.xml rename to aws-modules/aws-dynamodb/src/main/resources/logback.xml diff --git a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java similarity index 91% rename from aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java rename to aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java index 18f55544cd..e4dc0c65b8 100644 --- a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java +++ b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java @@ -49,10 +49,10 @@ public class ProductInfoRepositoryIntegrationTest { @BeforeClass public static void setupClass() { Properties testProperties = loadFromFileInClasspath("test.properties") - .filter(properties -> !isEmpty(properties.getProperty(AWS_ACCESSKEY))) - .filter(properties -> !isEmpty(properties.getProperty(AWS_SECRETKEY))) - .filter(properties -> !isEmpty(properties.getProperty(DYNAMODB_ENDPOINT))) - .orElseThrow(() -> new RuntimeException("Unable to get all of the required test property values")); + .filter(properties -> !isEmpty(properties.getProperty(AWS_ACCESSKEY))) + .filter(properties -> !isEmpty(properties.getProperty(AWS_SECRETKEY))) + .filter(properties -> !isEmpty(properties.getProperty(DYNAMODB_ENDPOINT))) + .orElseThrow(() -> new RuntimeException("Unable to get all of the required test property values")); String amazonAWSAccessKey = testProperties.getProperty(AWS_ACCESSKEY); String amazonAWSSecretKey = testProperties.getProperty(AWS_SECRETKEY); diff --git a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java rename to aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java diff --git a/aws-modules/aws-miscellaneous/src/test/resources/test.properties b/aws-modules/aws-dynamodb/src/test/resources/test.properties similarity index 100% rename from aws-modules/aws-miscellaneous/src/test/resources/test.properties rename to aws-modules/aws-dynamodb/src/test/resources/test.properties diff --git a/aws-modules/aws-miscellaneous/README.md b/aws-modules/aws-miscellaneous/README.md index 5be8e6a3f2..104c8719df 100644 --- a/aws-modules/aws-miscellaneous/README.md +++ b/aws-modules/aws-miscellaneous/README.md @@ -5,6 +5,5 @@ This module contains articles about various Amazon Web Services (AWS) such as EC ### Relevant articles - [Managing EC2 Instances in Java](https://www.baeldung.com/ec2-java) -- [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests) - [Managing Amazon SQS Queues in Java](https://www.baeldung.com/aws-queues-java) - [Guide to AWS Aurora RDS with Java](https://www.baeldung.com/aws-aurora-rds-java) diff --git a/aws-modules/aws-miscellaneous/pom.xml b/aws-modules/aws-miscellaneous/pom.xml index 2fb7e397a0..4126256fb9 100644 --- a/aws-modules/aws-miscellaneous/pom.xml +++ b/aws-modules/aws-miscellaneous/pom.xml @@ -16,31 +16,9 @@ - com.amazonaws - aws-java-sdk - ${aws-java-sdk.version} - - - com.amazonaws - aws-lambda-java-core - ${aws-lambda-java-core.version} - - - commons-logging - commons-logging - - - - - com.amazonaws - aws-lambda-java-events - ${aws-lambda-java-events.version} - - - commons-logging - commons-logging - - + software.amazon.awssdk + aws-sdk-java + ${aws-java-sdk-v2.version} commons-io @@ -52,12 +30,6 @@ gson ${gson.version} - - com.amazonaws - DynamoDBLocal - ${dynamodblocal.version} - test - @@ -101,8 +73,6 @@ - 1.3.0 - 1.1.0 2.8.0 1.21.1 1.10.L001 diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java index 6755188fcd..e12a38e1de 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java @@ -2,136 +2,148 @@ package com.baeldung.ec2; import java.util.Arrays; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; -import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest; -import com.amazonaws.services.ec2.model.CreateKeyPairRequest; -import com.amazonaws.services.ec2.model.CreateKeyPairResult; -import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesResult; -import com.amazonaws.services.ec2.model.DescribeKeyPairsRequest; -import com.amazonaws.services.ec2.model.DescribeKeyPairsResult; -import com.amazonaws.services.ec2.model.IpPermission; -import com.amazonaws.services.ec2.model.IpRange; -import com.amazonaws.services.ec2.model.MonitorInstancesRequest; -import com.amazonaws.services.ec2.model.RebootInstancesRequest; -import com.amazonaws.services.ec2.model.RunInstancesRequest; -import com.amazonaws.services.ec2.model.StartInstancesRequest; -import com.amazonaws.services.ec2.model.StopInstancesRequest; -import com.amazonaws.services.ec2.model.UnmonitorInstancesRequest; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressRequest; +import software.amazon.awssdk.services.ec2.model.CreateKeyPairRequest; +import software.amazon.awssdk.services.ec2.model.CreateKeyPairResponse; +import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupRequest; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; +import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsRequest; +import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsResponse; +import software.amazon.awssdk.services.ec2.model.IpPermission; +import software.amazon.awssdk.services.ec2.model.IpRange; +import software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RebootInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RunInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RunInstancesResponse; +import software.amazon.awssdk.services.ec2.model.StartInstancesRequest; +import software.amazon.awssdk.services.ec2.model.StartInstancesResponse; +import software.amazon.awssdk.services.ec2.model.StopInstancesRequest; +import software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest; public class EC2Application { - private static final AWSCredentials credentials; - - static { - // put your accesskey and secretkey here - credentials = new BasicAWSCredentials( - "", - "" - ); - } - public static void main(String[] args) { // Set up the client - AmazonEC2 ec2Client = AmazonEC2ClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(Regions.US_EAST_1) + Ec2Client ec2Client = Ec2Client.builder() + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .region(Region.US_EAST_1) .build(); // Create a security group - CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest().withGroupName("BaeldungSecurityGroup") - .withDescription("Baeldung Security Group"); + CreateSecurityGroupRequest createSecurityGroupRequest = CreateSecurityGroupRequest.builder() + .groupName("BaeldungSecurityGroup") + .description("Baeldung Security Group") + .build(); + ec2Client.createSecurityGroup(createSecurityGroupRequest); // Allow HTTP and SSH traffic - IpRange ipRange1 = new IpRange().withCidrIp("0.0.0.0/0"); + IpRange ipRange1 = IpRange.builder() + .cidrIp("0.0.0.0/0") + .build(); - IpPermission ipPermission1 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 })) - .withIpProtocol("tcp") - .withFromPort(80) - .withToPort(80); + IpPermission ipPermission1 = IpPermission.builder() + .ipRanges(Arrays.asList(ipRange1)) + .ipProtocol("tcp") + .fromPort(80) + .toPort(80) + .build(); - IpPermission ipPermission2 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 })) - .withIpProtocol("tcp") - .withFromPort(22) - .withToPort(22); + IpPermission ipPermission2 = IpPermission.builder() + .ipRanges(Arrays.asList(ipRange1)) + .ipProtocol("tcp") + .fromPort(22) + .toPort(22) + .build(); - AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest() - .withGroupName("BaeldungSecurityGroup") - .withIpPermissions(ipPermission1, ipPermission2); + AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = AuthorizeSecurityGroupIngressRequest + .builder() + .groupName("BaeldungSecurityGroup") + .ipPermissions(ipPermission1, ipPermission2) + .build(); ec2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); // Create KeyPair - CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest() - .withKeyName("baeldung-key-pair"); - CreateKeyPairResult createKeyPairResult = ec2Client.createKeyPair(createKeyPairRequest); - String privateKey = createKeyPairResult - .getKeyPair() - .getKeyMaterial(); // make sure you keep it, the private key, Amazon doesn't store the private key + CreateKeyPairRequest createKeyPairRequest = CreateKeyPairRequest.builder() + .keyName("baeldung-key-pair") + .build(); + + CreateKeyPairResponse createKeyPairResponse = ec2Client.createKeyPair(createKeyPairRequest); + String privateKey = createKeyPairResponse.keyMaterial(); + // make sure you keep it, the private key, Amazon doesn't store the private key // See what key-pairs you've got - DescribeKeyPairsRequest describeKeyPairsRequest = new DescribeKeyPairsRequest(); - DescribeKeyPairsResult describeKeyPairsResult = ec2Client.describeKeyPairs(describeKeyPairsRequest); + DescribeKeyPairsRequest describeKeyPairsRequest = DescribeKeyPairsRequest.builder() + .build(); + DescribeKeyPairsResponse describeKeyPairsResponse = ec2Client.describeKeyPairs(describeKeyPairsRequest); // Launch an Amazon Instance - RunInstancesRequest runInstancesRequest = new RunInstancesRequest().withImageId("ami-97785bed") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html | https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingsharedamis-finding.html - .withInstanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html - .withMinCount(1) - .withMaxCount(1) - .withKeyName("baeldung-key-pair") // optional - if not present, can't connect to instance - .withSecurityGroups("BaeldungSecurityGroup"); + RunInstancesRequest runInstancesRequest = RunInstancesRequest.builder() + .imageId("ami-97785bed") + .instanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html + .minCount(1) + .maxCount(1) + .keyName("baeldung-key-pair") // optional - if not present, can't connect to instance + .securityGroups("BaeldungSecurityGroup") + .build(); - String yourInstanceId = ec2Client.runInstances(runInstancesRequest).getReservation().getInstances().get(0).getInstanceId(); + RunInstancesResponse runInstancesResponse = ec2Client.runInstances(runInstancesRequest); + String yourInstanceId = runInstancesResponse.instances().get(0).instanceId(); // Start an Instance - StartInstancesRequest startInstancesRequest = new StartInstancesRequest() - .withInstanceIds(yourInstanceId); + StartInstancesRequest startInstancesRequest = StartInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + + StartInstancesResponse startInstancesResponse = ec2Client.startInstances(startInstancesRequest); - ec2Client.startInstances(startInstancesRequest); // Monitor Instances - MonitorInstancesRequest monitorInstancesRequest = new MonitorInstancesRequest() - .withInstanceIds(yourInstanceId); + MonitorInstancesRequest monitorInstancesRequest = MonitorInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + ec2Client.monitorInstances(monitorInstancesRequest); - UnmonitorInstancesRequest unmonitorInstancesRequest = new UnmonitorInstancesRequest() - .withInstanceIds(yourInstanceId); + UnmonitorInstancesRequest unmonitorInstancesRequest = UnmonitorInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); ec2Client.unmonitorInstances(unmonitorInstancesRequest); // Reboot an Instance - - RebootInstancesRequest rebootInstancesRequest = new RebootInstancesRequest() - .withInstanceIds(yourInstanceId); + RebootInstancesRequest rebootInstancesRequest = RebootInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); ec2Client.rebootInstances(rebootInstancesRequest); // Stop an Instance - StopInstancesRequest stopInstancesRequest = new StopInstancesRequest() - .withInstanceIds(yourInstanceId); + StopInstancesRequest stopInstancesRequest = StopInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + ec2Client.stopInstances(stopInstancesRequest) - .getStoppingInstances() + .stoppingInstances() .get(0) - .getPreviousState() - .getName(); + .previousState() + .name(); // Describe an Instance - DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest(); - DescribeInstancesResult response = ec2Client.describeInstances(describeInstancesRequest); - System.out.println(response.getReservations() + DescribeInstancesRequest describeInstancesRequest = DescribeInstancesRequest.builder().build(); + DescribeInstancesResponse response = ec2Client.describeInstances(describeInstancesRequest); + System.out.println(response.reservations() .get(0) - .getInstances() + .instances() .get(0) - .getKernelId()); + .kernelId()); } } diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java index d4da92f30f..09309b92bb 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java @@ -1,13 +1,5 @@ package com.baeldung.rds; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.rds.AmazonRDS; -import com.amazonaws.services.rds.AmazonRDSClientBuilder; -import com.amazonaws.services.rds.model.*; - import java.io.IOException; import java.io.InputStream; import java.sql.*; @@ -16,12 +8,22 @@ import java.util.Properties; import java.util.UUID; import java.util.logging.Logger; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.rds.RdsClient; +import software.amazon.awssdk.services.rds.model.CreateDbInstanceRequest; +import software.amazon.awssdk.services.rds.model.CreateDbInstanceResponse; +import software.amazon.awssdk.services.rds.model.DBInstance; +import software.amazon.awssdk.services.rds.model.DeleteDbInstanceRequest; +import software.amazon.awssdk.services.rds.model.DeleteDbInstanceResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbInstancesResponse; +import software.amazon.awssdk.services.rds.model.Endpoint; + public class AWSRDSService { final static Logger logger = Logger.getLogger(AWSRDSService.class.getName()); - private AWSCredentialsProvider credentials; - private AmazonRDS amazonRDS; + private RdsClient rdsClient; private String db_username; private String db_password; private String db_database; @@ -34,22 +36,17 @@ public class AWSRDSService { * **/ public AWSRDSService() throws IOException { //Init RDS client with credentials and region. - credentials = new - AWSStaticCredentialsProvider(new - BasicAWSCredentials("", - "")); - amazonRDS = AmazonRDSClientBuilder.standard().withCredentials(credentials) - .withRegion(Regions.AP_SOUTHEAST_2).build(); Properties prop = new Properties(); InputStream input = AWSRDSService.class.getClassLoader().getResourceAsStream("db.properties"); prop.load(input); db_username = prop.getProperty("db_username"); db_password = prop.getProperty("db_password"); db_database = prop.getProperty("db_database"); - } - public AWSRDSService(AmazonRDS amazonRDS){ - this.amazonRDS = amazonRDS; + rdsClient = RdsClient.builder() + .region(Region.AP_SOUTHEAST_2) + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .build(); } /** @@ -60,29 +57,29 @@ public class AWSRDSService { public String launchInstance() { String identifier = ""; - CreateDBInstanceRequest request = new CreateDBInstanceRequest(); - // RDS instance name - request.setDBInstanceIdentifier("Sydney"); - request.setEngine("postgres"); - request.setMultiAZ(false); - request.setMasterUsername(db_username); - request.setMasterUserPassword(db_password); - request.setDBName(db_database); - request.setStorageType("gp2"); - request.setAllocatedStorage(10); + CreateDbInstanceRequest instanceRequest = CreateDbInstanceRequest.builder() + .dbInstanceIdentifier("Sydney") + .engine("postgres") + .multiAZ(false) + .masterUsername(db_username) + .masterUserPassword(db_password) + .dbName(db_database) + .storageType("gp2") + .allocatedStorage(10) + .build(); - DBInstance instance = amazonRDS.createDBInstance(request); + CreateDbInstanceResponse createDbInstanceResponse = rdsClient.createDBInstance(instanceRequest); // Information about the new RDS instance - identifier = instance.getDBInstanceIdentifier(); - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + identifier = createDbInstanceResponse.dbInstance().dbInstanceIdentifier(); + String status = createDbInstanceResponse.dbInstance().dbInstanceStatus(); + Endpoint endpoint = createDbInstanceResponse.dbInstance().endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + status); - logger.info(endpoint_url); + logger.info(endpointUrl); return identifier; @@ -90,44 +87,44 @@ public class AWSRDSService { // Describe DB instances public void listInstances() { - DescribeDBInstancesResult result = amazonRDS.describeDBInstances(); - List instances = result.getDBInstances(); + DescribeDbInstancesResponse response = rdsClient.describeDBInstances(); + List instances = response.dbInstances(); for (DBInstance instance : instances) { // Information about each RDS instance - String identifier = instance.getDBInstanceIdentifier(); - String engine = instance.getEngine(); - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + String identifier = instance.dbInstanceIdentifier(); + String engine = instance.engine(); + String status = instance.dbInstanceStatus(); + Endpoint endpoint = instance.endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + engine + "\t" + status); - logger.info("\t" + endpoint_url); + logger.info("\t" + endpointUrl); } - } //Delete RDS instance public void terminateInstance(String identifier) { - DeleteDBInstanceRequest request = new DeleteDBInstanceRequest(); - request.setDBInstanceIdentifier(identifier); - request.setSkipFinalSnapshot(true); + DeleteDbInstanceRequest request = DeleteDbInstanceRequest.builder() + .dbInstanceIdentifier(identifier) + .skipFinalSnapshot(true) + .build(); // Delete the RDS instance - DBInstance instance = amazonRDS.deleteDBInstance(request); + DeleteDbInstanceResponse response = rdsClient.deleteDBInstance(request); // Information about the RDS instance being deleted - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + String status = response.dbInstance().dbInstanceStatus(); + Endpoint endpoint = response.dbInstance().endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + status); - logger.info(endpoint_url); + logger.info(endpointUrl); } diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java index 978506a24f..3b78d73f60 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java @@ -5,140 +5,190 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.sqs.AmazonSQSClientBuilder; -import com.amazonaws.services.sqs.model.CreateQueueRequest; -import com.amazonaws.services.sqs.model.DeleteMessageRequest; -import com.amazonaws.services.sqs.model.GetQueueAttributesRequest; -import com.amazonaws.services.sqs.model.GetQueueAttributesResult; -import com.amazonaws.services.sqs.model.MessageAttributeValue; -import com.amazonaws.services.sqs.model.ReceiveMessageRequest; -import com.amazonaws.services.sqs.model.SendMessageBatchRequest; -import com.amazonaws.services.sqs.model.SendMessageRequest; -import com.amazonaws.services.sqs.model.SetQueueAttributesRequest; -import com.amazonaws.services.sqs.model.SendMessageBatchRequestEntry; -import com.amazonaws.services.sqs.model.Message; -import com.amazonaws.services.sqs.AmazonSQS; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; +import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueAttributesResponse; +import software.amazon.awssdk.services.sqs.model.GetQueueUrlRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueUrlResponse; +import software.amazon.awssdk.services.sqs.model.Message; +import software.amazon.awssdk.services.sqs.model.MessageAttributeValue; +import software.amazon.awssdk.services.sqs.model.QueueAttributeName; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; +import software.amazon.awssdk.services.sqs.model.SetQueueAttributesRequest; public class SQSApplication { - private static final AWSCredentials credentials; - - static { - // put your accesskey and secretkey here - credentials = new BasicAWSCredentials( - "", - "" - ); - } + private static final String STANDARD_QUEUE_NAME = "baeldung-queue"; + private static final String FIFO_QUEUE_NAME = "baeldung-queue.fifo"; + private static final String DEAD_LETTER_QUEUE_NAME = "baeldung-dead-letter-queue"; public static void main(String[] args) { // Set up the client - AmazonSQS sqs = AmazonSQSClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(Regions.US_EAST_1) + SqsClient sqsClient = SqsClient.builder() + .region(Region.US_EAST_1) + .credentialsProvider(ProfileCredentialsProvider.create()) .build(); // Create a standard queue + CreateQueueRequest createStandardQueueRequest = CreateQueueRequest.builder() + .queueName(STANDARD_QUEUE_NAME) + .build(); - CreateQueueRequest createStandardQueueRequest = new CreateQueueRequest("baeldung-queue"); - String standardQueueUrl = sqs.createQueue(createStandardQueueRequest) - .getQueueUrl(); + sqsClient.createQueue(createStandardQueueRequest); + + System.out.println("\nGet queue url"); + + GetQueueUrlResponse getQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder() + .queueName(STANDARD_QUEUE_NAME) + .build()); + String standardQueueUrl = getQueueUrlResponse.queueUrl(); System.out.println(standardQueueUrl); // Create a fifo queue + Map queueAttributes = new HashMap<>(); + queueAttributes.put(QueueAttributeName.FIFO_QUEUE, "true"); + queueAttributes.put(QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true"); - Map queueAttributes = new HashMap(); - queueAttributes.put("FifoQueue", "true"); - queueAttributes.put("ContentBasedDeduplication", "true"); + CreateQueueRequest createFifoQueueRequest = CreateQueueRequest.builder() + .queueName(FIFO_QUEUE_NAME) + .attributes(queueAttributes) + .build(); - CreateQueueRequest createFifoQueueRequest = new CreateQueueRequest("baeldung-queue.fifo").withAttributes(queueAttributes); - String fifoQueueUrl = sqs.createQueue(createFifoQueueRequest) - .getQueueUrl(); + sqsClient.createQueue(createFifoQueueRequest); + + GetQueueUrlResponse getFifoQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder() + .queueName(FIFO_QUEUE_NAME) + .build()); + + String fifoQueueUrl = getFifoQueueUrlResponse.queueUrl(); System.out.println(fifoQueueUrl); // Set up a dead letter queue + CreateQueueRequest createDeadLetterQueueRequest = CreateQueueRequest.builder() + .queueName(DEAD_LETTER_QUEUE_NAME) + .build(); - String deadLetterQueueUrl = sqs.createQueue("baeldung-dead-letter-queue") - .getQueueUrl(); + String deadLetterQueueUrl = sqsClient.createQueue(createDeadLetterQueueRequest) + .queueUrl(); - GetQueueAttributesResult deadLetterQueueAttributes = sqs.getQueueAttributes(new GetQueueAttributesRequest(deadLetterQueueUrl).withAttributeNames("QueueArn")); + GetQueueAttributesRequest getQueueAttributesRequest = GetQueueAttributesRequest.builder() + .queueUrl(deadLetterQueueUrl) + .attributeNames(QueueAttributeName.QUEUE_ARN) + .build(); - String deadLetterQueueARN = deadLetterQueueAttributes.getAttributes() + GetQueueAttributesResponse deadLetterQueueAttributes = sqsClient.getQueueAttributes(getQueueAttributesRequest); + + String deadLetterQueueARN = deadLetterQueueAttributes.attributes() .get("QueueArn"); - SetQueueAttributesRequest queueAttributesRequest = new SetQueueAttributesRequest().withQueueUrl(standardQueueUrl) - .addAttributesEntry("RedrivePolicy", "{\"maxReceiveCount\":\"2\", " + "\"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}"); + Map attributes = new HashMap<>(); + attributes.put(QueueAttributeName.REDRIVE_POLICY, "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}"); - sqs.setQueueAttributes(queueAttributesRequest); + SetQueueAttributesRequest queueAttributesRequest = SetQueueAttributesRequest.builder() + .queueUrl(standardQueueUrl) + .attributes(attributes) + .build(); + + sqsClient.setQueueAttributes(queueAttributesRequest); // Send a message to a standard queue Map messageAttributes = new HashMap<>(); + MessageAttributeValue messageAttributeValue = MessageAttributeValue.builder() + .stringValue("This is an attribute") + .dataType("String") + .build(); - messageAttributes.put("AttributeOne", new MessageAttributeValue().withStringValue("This is an attribute") - .withDataType("String")); + messageAttributes.put("AttributeOne", messageAttributeValue); - SendMessageRequest sendMessageStandardQueue = new SendMessageRequest().withQueueUrl(standardQueueUrl) - .withMessageBody("A simple message.") - .withDelaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues - .withMessageAttributes(messageAttributes); + SendMessageRequest sendMessageStandardQueue = SendMessageRequest.builder() + .queueUrl(standardQueueUrl) + .messageBody("A simple message.") + .delaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues + .messageAttributes(messageAttributes) + .build(); - sqs.sendMessage(sendMessageStandardQueue); + sqsClient.sendMessage(sendMessageStandardQueue); // Send a message to a fifo queue - SendMessageRequest sendMessageFifoQueue = new SendMessageRequest().withQueueUrl(fifoQueueUrl) - .withMessageBody("FIFO Queue") - .withMessageGroupId("baeldung-group-1") - .withMessageAttributes(messageAttributes); + SendMessageRequest sendMessageFifoQueue = SendMessageRequest.builder() + .queueUrl(fifoQueueUrl) + .messageBody("FIFO Queue") + .messageGroupId("baeldung-group-1") + .messageAttributes(messageAttributes) + .build(); - sqs.sendMessage(sendMessageFifoQueue); + sqsClient.sendMessage(sendMessageFifoQueue); // Send multiple messages List messageEntries = new ArrayList<>(); - messageEntries.add(new SendMessageBatchRequestEntry().withId("id-1") - .withMessageBody("batch-1") - .withMessageGroupId("baeldung-group-1")); - messageEntries.add(new SendMessageBatchRequestEntry().withId("id-2") - .withMessageBody("batch-2") - .withMessageGroupId("baeldung-group-1")); + SendMessageBatchRequestEntry messageBatchRequestEntry1 = SendMessageBatchRequestEntry.builder() + .id("id-1") + .messageBody("batch-1") + .messageGroupId("baeldung-group-1") + .build(); - SendMessageBatchRequest sendMessageBatchRequest = new SendMessageBatchRequest(fifoQueueUrl, messageEntries); - sqs.sendMessageBatch(sendMessageBatchRequest); + SendMessageBatchRequestEntry messageBatchRequestEntry2 = SendMessageBatchRequestEntry.builder() + .id("id-2") + .messageBody("batch-2") + .messageGroupId("baeldung-group-1") + .build(); + + messageEntries.add(messageBatchRequestEntry1); + messageEntries.add(messageBatchRequestEntry2); + + SendMessageBatchRequest sendMessageBatchRequest = SendMessageBatchRequest.builder() + .queueUrl(fifoQueueUrl) + .entries(messageEntries) + .build(); + + sqsClient.sendMessageBatch(sendMessageBatchRequest); // Read a message from a queue - ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(fifoQueueUrl).withWaitTimeSeconds(10) // Long polling; - .withMaxNumberOfMessages(1); // Max is 10 + ReceiveMessageRequest receiveMessageRequest = ReceiveMessageRequest.builder() + .waitTimeSeconds(10) + .maxNumberOfMessages(10) + .build(); - List sqsMessages = sqs.receiveMessage(receiveMessageRequest) - .getMessages(); + List sqsMessages = sqsClient.receiveMessage(receiveMessageRequest) + .messages(); sqsMessages.get(0) - .getAttributes(); + .attributes(); sqsMessages.get(0) - .getBody(); + .body(); // Delete a message from a queue + DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder() + .queueUrl(fifoQueueUrl) + .receiptHandle(sqsMessages.get(0) + .receiptHandle()) + .build(); - sqs.deleteMessage(new DeleteMessageRequest().withQueueUrl(fifoQueueUrl) - .withReceiptHandle(sqsMessages.get(0) - .getReceiptHandle())); + sqsClient.deleteMessage(deleteMessageRequest); // Monitoring - GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(standardQueueUrl).withAttributeNames("All"); - GetQueueAttributesResult getQueueAttributesResult = sqs.getQueueAttributes(getQueueAttributesRequest); - System.out.println(String.format("The number of messages on the queue: %s", getQueueAttributesResult.getAttributes() + GetQueueAttributesRequest getQueueAttributesRequestForMonitoring = GetQueueAttributesRequest.builder() + .queueUrl(standardQueueUrl) + .build(); + + GetQueueAttributesResponse attributesResponse = sqsClient.getQueueAttributes(getQueueAttributesRequestForMonitoring); + System.out.println(String.format("The number of messages on the queue: %s", attributesResponse.attributes() .get("ApproximateNumberOfMessages"))); - System.out.println(String.format("The number of messages in flight: %s", getQueueAttributesResult.getAttributes() + System.out.println(String.format("The number of messages in flight: %s", attributesResponse.attributes() .get("ApproximateNumberOfMessagesNotVisible"))); } diff --git a/aws-modules/aws-s3/README.md b/aws-modules/aws-s3/README.md index 3389fdf454..f3b34b584e 100644 --- a/aws-modules/aws-s3/README.md +++ b/aws-modules/aws-s3/README.md @@ -4,8 +4,11 @@ This module contains articles about Simple Storage Service (S3) on AWS ### Relevant articles -- [AWS S3 with Java](https://www.baeldung.com/aws-s3-java) +- [AWS S3 with Java](https://www.baeldung.com/java-aws-s3) - [Multipart Uploads in Amazon S3 with Java](https://www.baeldung.com/aws-s3-multipart-upload) - [Using the JetS3t Java Client With Amazon S3](https://www.baeldung.com/jets3t-amazon-s3) - [Check if a Specified Key Exists in a Given S3 Bucket Using Java](https://www.baeldung.com/java-aws-s3-check-specified-key-exists) -- [Listing All AWS S3 Objects in a Bucket Using Java](https://www.baeldung.com/java-aws-s3-list-bucket-objects) \ No newline at end of file +- [Listing All AWS S3 Objects in a Bucket Using Java](https://www.baeldung.com/java-aws-s3-list-bucket-objects) +- [Update an Existing Amazon S3 Object Using Java](https://www.baeldung.com/java-update-amazon-s3-object) +- [How To Rename Files and Folders in Amazon S3](https://www.baeldung.com/java-amazon-s3-rename-files-folders) +- [Update an Existing Amazon S3 Object Using Java](https://www.baeldung.com/java-update-amazon-s3-object) diff --git a/aws-modules/aws-s3/pom.xml b/aws-modules/aws-s3/pom.xml index 157aeb671d..e2bc04964a 100644 --- a/aws-modules/aws-s3/pom.xml +++ b/aws-modules/aws-s3/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 aws-s3 0.1.0-SNAPSHOT diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java new file mode 100644 index 0000000000..0ca586c73b --- /dev/null +++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java @@ -0,0 +1,79 @@ +package com.baeldung.s3; + +import java.util.List; + +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.CopyObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.S3Object; + +public class RenameObjectService { + + private S3Client s3Client; + + public RenameObjectService(S3Client s3Client) { + this.s3Client = s3Client; + } + + public RenameObjectService() { + init(); + } + + public void init() { + this.s3Client = S3Client.builder() + .region(Region.US_EAST_1) + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .build(); + } + + public void renameFile(String bucketName, String keyName, String destinationKeyName) { + CopyObjectRequest copyObjRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(keyName) + .destinationBucket(destinationKeyName) + .destinationKey(bucketName) + .build(); + s3Client.copyObject(copyObjRequest); + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(keyName) + .build(); + s3Client.deleteObject(deleteRequest); + } + + public void renameFolder(String bucketName, String sourceFolderKey, String destinationFolderKey) { + ListObjectsV2Request listRequest = ListObjectsV2Request.builder() + .bucket(bucketName) + .prefix(sourceFolderKey) + .build(); + + ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest); + List objects = listResponse.contents(); + + for (S3Object s3Object : objects) { + String newKey = destinationFolderKey + s3Object.key() + .substring(sourceFolderKey.length()); + + // Copy object to destination folder + CopyObjectRequest copyRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(s3Object.key()) + .destinationBucket(bucketName) + .destinationKey(newKey) + .build(); + s3Client.copyObject(copyRequest); + + // Delete object from source folder + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(s3Object.key()) + .build(); + s3Client.deleteObject(deleteRequest); + } + } + +} diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Application.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Application.java index abf570f0d0..3328006bc0 100644 --- a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Application.java +++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Application.java @@ -45,6 +45,13 @@ public class S3Application { new File("/Users/user/Document/hello.txt") ); + s3Service.updateObject( + AWS_BUCKET, + "Document/hello2.txt", + new File("/Users/user/Document/hello2.txt") + ); + + //listing objects s3Service.listObjects(AWS_BUCKET); diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Service.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Service.java index f4f768d1b4..dfc8e9de5f 100644 --- a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Service.java +++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3Service.java @@ -24,6 +24,7 @@ import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.model.HeadBucketRequest; import software.amazon.awssdk.services.s3.model.HeadObjectRequest; +import software.amazon.awssdk.services.s3.model.HeadObjectResponse; import software.amazon.awssdk.services.s3.model.ListBucketsResponse; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; @@ -99,7 +100,13 @@ class S3Service { .key(key) .build(); - return s3Client.putObject(request, Path.of(file.toURI()) ); + + return s3Client.putObject(request, Path.of(file.toURI())); + } + + //updating object + public PutObjectResponse updateObject(String bucketName, String key, java.io.File file) { + return this.putObject(bucketName, key, file); } //listing objects @@ -110,6 +117,7 @@ class S3Service { ListObjectsV2Response listObjectsV2Response = s3Client.listObjectsV2(listObjectsV2Request); for(S3Object os : listObjectsV2Response.contents()) { + System.out.println(os.key()); } } diff --git a/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3ServiceIntegrationTest.java b/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3ServiceIntegrationTest.java index bf24bcaa43..15db15831c 100644 --- a/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3ServiceIntegrationTest.java +++ b/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3ServiceIntegrationTest.java @@ -11,6 +11,8 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.io.File; +import java.nio.file.Path; import java.util.Collections; import software.amazon.awssdk.services.s3.S3Client; @@ -23,6 +25,7 @@ import software.amazon.awssdk.services.s3.model.HeadBucketRequest; import software.amazon.awssdk.services.s3.model.ListBucketsResponse; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; class S3ServiceIntegrationTest { @@ -38,6 +41,8 @@ class S3ServiceIntegrationTest { private final String AWS_BUCKET = "baeldung-tutorial-s3"; + private File file = new File("/Users/user/Document/hello2.txt"); + @BeforeEach public void setup() { MockitoAnnotations.openMocks(this); @@ -75,6 +80,17 @@ class S3ServiceIntegrationTest { verify(s3Client).createBucket(bucketRequest); } + @Test + void whenVerifyingUploadOfS3Object_thenCorrect() { + PutObjectRequest request = PutObjectRequest.builder() + .bucket(BUCKET_NAME) + .key(KEY_NAME) + .build(); + + s3Service.putObject(BUCKET_NAME, KEY_NAME, file); + verify(s3Client).putObject(request, Path.of(file.toURI()) ); + } + @Test void whenVerifyingListBuckets_thenCorrect() { when(s3Client.listBuckets()).thenReturn(ListBucketsResponse.builder().buckets(Collections.emptyList()).build()); diff --git a/aws-modules/pom.xml b/aws-modules/pom.xml index 02473815b5..06cea2f260 100644 --- a/aws-modules/pom.xml +++ b/aws-modules/pom.xml @@ -5,6 +5,14 @@ 4.0.0 aws-modules aws-modules + + + com.amazonaws + aws-java-sdk-dynamodb + 1.12.523 + compile + + pom @@ -15,6 +23,7 @@ aws-app-sync + aws-dynamodb aws-lambda-modules aws-miscellaneous aws-reactive @@ -23,6 +32,7 @@ 1.12.331 + 2.20.147 3.0.0 diff --git a/azure/pom.xml b/azure/pom.xml index aae84db0c6..6a06282a71 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -122,7 +122,6 @@ ${azure.containerRegistry}.azurecr.io 1.1.0 1.1.0 - 3.3.2 \ No newline at end of file diff --git a/core-groovy-modules/pom.xml b/core-groovy-modules/pom.xml index 6faa7f94c8..4fdaf3ee7a 100644 --- a/core-groovy-modules/pom.xml +++ b/core-groovy-modules/pom.xml @@ -27,6 +27,7 @@ 2.7.1 2.3-groovy-3.0 2.1.0 + 2.21.0 diff --git a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ConstraintsBuilder.java b/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ConstraintsBuilder.java deleted file mode 100644 index ce437fac6d..0000000000 --- a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ConstraintsBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package reminderapplication; - -import java.awt.GridBagConstraints; -import java.awt.Insets; - -public class ConstraintsBuilder { - - static GridBagConstraints constraint(int x, int y) { - final GridBagConstraints gridBagConstraints = new GridBagConstraints(); - gridBagConstraints.gridx = x; - gridBagConstraints.gridy = y; - gridBagConstraints.insets = new Insets(5, 5, 5, 5); - return gridBagConstraints; - } -} diff --git a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/EditReminderFrame.java b/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/EditReminderFrame.java deleted file mode 100644 index 818cea403e..0000000000 --- a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/EditReminderFrame.java +++ /dev/null @@ -1,194 +0,0 @@ -package reminderapplication; - -import static reminderapplication.ConstraintsBuilder.*; - -import java.awt.GridBagLayout; -import java.awt.HeadlessException; -import java.lang.reflect.InvocationTargetException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; -import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; - -public class EditReminderFrame extends JFrame { - - private static Timer TIMER = new Timer(); - - private final TimeReminderApplication reminderApplication; - private final JLabel reminderTextLabel; - private final JLabel repeatPeriodLabel; - private final JLabel setDelayLabel; - private final JComboBox delay; - private final JComboBox period; - private final JButton cancelButton; - private final JButton okButton; - private final JTextField textField; - private final JLabel delaysLabel; - private final JLabel periodLabel; - - private final int reminderIndex; - - public EditReminderFrame(TimeReminderApplication reminderApp, String reminderText, int delayInSeconds, int periodInSeconds, int index) throws HeadlessException { - this.reminderApplication = reminderApp; - reminderIndex = index; - textField = createTextField(reminderText); - delay = createDelayComboBox(delayInSeconds); - period = createPeriodComboBox(periodInSeconds); - cancelButton = createCancelButton(); - okButton = createOkButton(); - reminderTextLabel = createReminderTextLabel(); - repeatPeriodLabel = createRepeatPeriodLabel(); - setDelayLabel = createSetDelayLabel(); - delaysLabel = createDelaysLabel(); - periodLabel = createPeriodLabel(); - configureVisualRepresentation(); - configureActions(); - } - - private void configureActions() { - updateReminder(); - } - - private void configureVisualRepresentation() { - configureFrame(); - setLocationRelativeTo(null); - setLayout(new GridBagLayout()); - add(reminderTextLabel, constraint(0,0)); - add(repeatPeriodLabel, constraint(1,0)); - add(setDelayLabel, constraint(2,0)); - add(textField, constraint(0, 1)); - add(delay, constraint(1, 1)); - add(period, constraint(2, 1)); - add(delaysLabel, constraint(1,3)); - add(periodLabel, constraint(2,3)); - add(okButton, constraint(1, 4)); - add(cancelButton, constraint(2, 4)); - pack(); - setVisible(true); - } - - private void configureFrame() { - setTitle("Set Reminder"); - setName("Set Reminder"); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - } - - private static JLabel createSetDelayLabel() { - return createLabel("Set Delay", "Set Delay Label"); - } - - private static JLabel createRepeatPeriodLabel() { - return createLabel("Set Period", "Set Repeat Period Label"); - } - - private static JLabel createReminderTextLabel() { - return createLabel("Reminder Text", "Reminder Text Label"); - } - - private JLabel createPeriodLabel() { - return createLabel("0", "Period label"); - } - - private JLabel createDelaysLabel() { - return createLabel("30", "Delays Label"); - } - - private JComboBox createPeriodComboBox(final int periodInSeconds) { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{0, 5, 10, 20})); - comboBox.setSelectedItem(periodInSeconds); - comboBox.setName("set Period"); - comboBox.addActionListener(e -> periodLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JComboBox createDelayComboBox(final int delayInSeconds) { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{30, 25, 15, 5})); - comboBox.setSelectedItem(delayInSeconds); - comboBox.setName("set Delay"); - comboBox.addActionListener(e -> delaysLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JTextField createTextField(final String reminderText) { - final JTextField textField = new JTextField(20); - textField.setName("Field"); - textField.setText(reminderText); - return textField; - } - - private JButton createOkButton() { - final JButton button = new JButton("ok"); - button.setName("OK"); - return button; - } - - private void updateReminder() { - okButton.addActionListener(e -> this.dispose()); - okButton.addActionListener(e -> { - final int periodInSeconds = getTimeInSeconds(period); - final int delayInSeconds = getTimeInSeconds(delay); - final Reminder reminder = new Reminder(textField.getText(), delayInSeconds, periodInSeconds); - ((DefaultListModel) reminderApplication.getReminders()).set(reminderIndex, reminder); - }); - okButton.addActionListener(e -> scheduleReminder(textField, delay, period)); - } - - private void scheduleReminder(final JTextField textField, final JComboBox delay, final JComboBox period) { - final int periodInSeconds = getTimeInSeconds(period); - if (periodInSeconds == 0) - scheduleNonRepeatedReminder(textField, delay); - else - scheduleRepeatedReminder(textField, delay, period); - } - - private void scheduleRepeatedReminder(final JTextField textField, final JComboBox delay, final JComboBox period) { - final int delayInSeconds = getTimeInSeconds(delay); - final int periodInSeconds = getTimeInSeconds(period); - final TimerTask timerTask = getTimerTask(textField.getText(), delayInSeconds, periodInSeconds); - TIMER.schedule(timerTask, TimeUnit.SECONDS.toMillis(delayInSeconds), TimeUnit.SECONDS.toMillis(periodInSeconds)); - } - - private void scheduleNonRepeatedReminder(final JTextField textField, final JComboBox delay) { - final int delayInSeconds = getTimeInSeconds(delay); - final int periodInSeconds = 0; - final TimerTask timerTask = getTimerTask(textField.getText(), delayInSeconds, periodInSeconds); - TIMER.schedule(timerTask, TimeUnit.SECONDS.toMillis(delayInSeconds)); - - } - - private int getTimeInSeconds(final JComboBox comboBox) { - if (comboBox != null && comboBox.getSelectedItem() != null) - return ((Integer) comboBox.getSelectedItem()); - else - return 0; - } - - private TimerTask getTimerTask(final String reminderText, final Integer delayInSeconds, final Integer periodInSeconds) { - return new TimerTask() { - @Override - public void run() { - new ReminderPopupFrame(reminderApplication, reminderText, delayInSeconds, periodInSeconds); - } - }; - } - - private JButton createCancelButton() { - final JButton button = new JButton("cancel"); - button.setName("Cancel"); - button.addActionListener(e -> this.dispose()); - return button; - } - - private static JLabel createLabel(final String text, final String name) { - JLabel label = new JLabel(text); - label.setName(name); - return label; - } -} diff --git a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/Reminder.java b/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/Reminder.java deleted file mode 100644 index 8f6ff336ed..0000000000 --- a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/Reminder.java +++ /dev/null @@ -1,33 +0,0 @@ -package reminderapplication; - -public class Reminder { - - private static String REMINDER_FORMAT = "Reminder Text: %s; Delay: %d; Period: %d;"; - - private final String name; - private final int delay; - private final int period; - - public Reminder(final String name, final int delay, final int period) { - this.name = name; - this.delay = delay; - this.period = period; - } - - public String getName() { - return name; - } - - public int getDelay() { - return delay; - } - - public int getPeriod() { - return period; - } - - @Override - public String toString() { - return REMINDER_FORMAT.formatted(name, delay, period); - } -} diff --git a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderFrame.java b/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderFrame.java deleted file mode 100644 index 3a1623219c..0000000000 --- a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderFrame.java +++ /dev/null @@ -1,186 +0,0 @@ -package reminderapplication; - -import static reminderapplication.ConstraintsBuilder.*; - -import java.awt.GridBagLayout; -import java.awt.HeadlessException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; -import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextField; - -public class ReminderFrame extends JFrame { - - private static Timer TIMER = new Timer(); - private final TimeReminderApplication reminderApplication; - private final JLabel reminderTextLabel; - private final JLabel repeatPeriodLabel; - private final JLabel setDelayLabel; - private final JComboBox delay; - private final JComboBox period; - private final JButton cancelButton; - private final JButton okButton; - private final JTextField textField; - private final JLabel delaysLabel; - private final JLabel periodLabel; - - public ReminderFrame(TimeReminderApplication reminderApp) throws HeadlessException { - this.reminderApplication = reminderApp; - textField = createTextField(); - delay = createDelayComboBox(); - period = createPeriodComboBox(); - cancelButton = createCancelButton(); - okButton = createOkButton(); - reminderTextLabel = createReminderTextLabel(); - repeatPeriodLabel = createRepeatPeriodLabel(); - setDelayLabel = createSetDelayLabel(); - delaysLabel = createDelaysLabel(); - periodLabel = createPeriodLabel(); - configureVisualRepresentation(); - configureActions(); - } - - private void configureActions() { - createNewReminder(); - } - - private void configureVisualRepresentation() { - configureFrame(); - setLocationRelativeTo(null); - setLayout(new GridBagLayout()); - add(reminderTextLabel, constraint(0,0)); - add(repeatPeriodLabel, constraint(1,0)); - add(setDelayLabel, constraint(2,0)); - add(textField, constraint(0, 1)); - add(delay, constraint(1, 1)); - add(period, constraint(2, 1)); - add(delaysLabel, constraint(1,3)); - add(periodLabel, constraint(2,3)); - add(okButton, constraint(1, 4)); - add(cancelButton, constraint(2, 4)); - pack(); - setVisible(true); - } - - private void configureFrame() { - setTitle("Set Reminder"); - setName("Set Reminder"); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - } - - private static JLabel createSetDelayLabel() { - return createLabel("Set Delay", "Set Delay Label"); - } - - private static JLabel createRepeatPeriodLabel() { - return createLabel("Set Period", "Set Repeat Period Label"); - } - - private static JLabel createReminderTextLabel() { - return createLabel("Reminder Text", "Reminder Text Label"); - } - - private JLabel createPeriodLabel() { - return createLabel("0", "Period label"); - } - - private JLabel createDelaysLabel() { - return createLabel("30", "Delays Label"); - } - - private JComboBox createPeriodComboBox() { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{0, 5, 10, 20})); - comboBox.setName("set Period"); - comboBox.addActionListener(e -> periodLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JComboBox createDelayComboBox() { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{30, 25, 15, 5})); - comboBox.setName("set Delay"); - comboBox.addActionListener(e -> delaysLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JTextField createTextField() { - final JTextField textField = new JTextField(20); - textField.setName("Field"); - return textField; - } - - private JButton createOkButton() { - final JButton button = new JButton("ok"); - button.setName("OK"); - return button; - } - - private void createNewReminder() { - - okButton.addActionListener(e -> this.dispose()); - okButton.addActionListener(e -> { - final int periodInSeconds = getTimeInSeconds(period); - final int delayInSeconds = getTimeInSeconds(delay); - final Reminder reminder = new Reminder(textField.getText(), delayInSeconds, periodInSeconds); - ((DefaultListModel) reminderApplication.getReminders()).addElement(reminder); - }); - okButton.addActionListener(e -> scheduleReminder(textField, delay, period)); - } - - private void scheduleReminder(final JTextField textField, final JComboBox delay, final JComboBox period) { - final int periodInSeconds = getTimeInSeconds(period); - if (periodInSeconds == 0) - scheduleNonRepeatedReminder(textField, delay); - else - scheduleRepeatedReminder(textField, delay, period); - } - - private void scheduleRepeatedReminder(final JTextField textField, final JComboBox delay, final JComboBox period) { - final int delayInSeconds = getTimeInSeconds(delay) + 200; - final int periodInSeconds = getTimeInSeconds(period); - final TimerTask timerTask = getTimerTask(textField.getText(), delayInSeconds, periodInSeconds); - TIMER.schedule(timerTask, TimeUnit.SECONDS.toMillis(delayInSeconds), TimeUnit.SECONDS.toMillis(periodInSeconds)); - } - - private void scheduleNonRepeatedReminder(final JTextField textField, final JComboBox delay) { - final int delayInSeconds = getTimeInSeconds(delay); - final int periodInSeconds = 0; - final TimerTask timerTask = getTimerTask(textField.getText(), delayInSeconds, periodInSeconds); - TIMER.schedule(timerTask, TimeUnit.SECONDS.toMillis(delayInSeconds)); - - } - - private int getTimeInSeconds(final JComboBox comboBox) { - if (comboBox != null && comboBox.getSelectedItem() != null) - return ((Integer) comboBox.getSelectedItem()); - else - return 0; - } - - private TimerTask getTimerTask(final String reminderText, final Integer delayInSeconds, final Integer periodInSeconds) { - return new TimerTask() { - @Override - public void run() { - new ReminderPopupFrame(reminderApplication, reminderText, delayInSeconds, periodInSeconds); - } - }; - } - - private JButton createCancelButton() { - final JButton button = new JButton("cancel"); - button.setName("Cancel"); - button.addActionListener(e -> this.dispose()); - return button; - } - - private static JLabel createLabel(final String text, final String name) { - JLabel label = new JLabel(text); - label.setName(name); - return label; - } -} diff --git a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderPopupFrame.java b/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderPopupFrame.java deleted file mode 100644 index d41343cb6d..0000000000 --- a/core-java-modules/Reminder Application/Reminder Application/task/src/reminderapplication/ReminderPopupFrame.java +++ /dev/null @@ -1,151 +0,0 @@ -package reminderapplication; - -import static reminderapplication.ConstraintsBuilder.*; - -import java.awt.GridBagLayout; -import java.awt.HeadlessException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; -import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextField; - -public class ReminderPopupFrame extends JFrame { - - private static final Timer TIMER = new Timer(); - private final int AUTOMATIC_CLOSE_TIME_IN_SECONDS = 10; - private final TimeReminderApplication reminderApplication; - private final JLabel reminderTextLabel; - private final JLabel repeatPeriodLabel; - private final JLabel setDelayLabel; - private final JComboBox delay; - private final JComboBox period; - private final JButton cancelButton; - private final JButton okButton; - private final JTextField textField; - private final JLabel delaysLabel; - private final JLabel periodLabel; - - public ReminderPopupFrame(TimeReminderApplication reminderApp, final String text, final Integer delayInSeconds, final Integer periodInSeconds) throws HeadlessException { - this.reminderApplication = reminderApp; - textField = createTextField(text); - delay = createDelayComboBox(delayInSeconds); - period = createPeriodComboBox(periodInSeconds); - cancelButton = createCancelButton(); - okButton = createDisabledOkButton(); - reminderTextLabel = createReminderTextLabel(); - repeatPeriodLabel = createRepeatPeriodLabel(); - setDelayLabel = createSetDelayLabel(); - delaysLabel = createDelaysLabel(); - periodLabel = createPeriodLabel(); - configureVisualRepresentation(); - configureActions(); - } - - private void configureActions() { - scheduleClosing(); - } - - private void scheduleClosing() { - final TimerTask timerTask = new TimerTask() { - @Override - public void run() { - ReminderPopupFrame.this.dispose(); - } - }; - TIMER.schedule(timerTask, TimeUnit.SECONDS.toMillis(AUTOMATIC_CLOSE_TIME_IN_SECONDS)); - } - - private void configureVisualRepresentation() { - configureFrame(); - setLocationRelativeTo(null); - setLayout(new GridBagLayout()); - add(reminderTextLabel, constraint(0,0)); - add(repeatPeriodLabel, constraint(1,0)); - add(setDelayLabel, constraint(2,0)); - add(textField, constraint(0, 1)); - add(delay, constraint(1, 1)); - add(period, constraint(2, 1)); - add(delaysLabel, constraint(1,3)); - add(periodLabel, constraint(2,3)); - add(okButton, constraint(1, 4)); - add(cancelButton, constraint(2, 4)); - pack(); - setVisible(true); - } - - private void configureFrame() { - setTitle("Set Reminder"); - setName("Set Reminder"); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - } - - private static JLabel createSetDelayLabel() { - return createLabel("Set Delay", "Set Delay Label"); - } - - private static JLabel createRepeatPeriodLabel() { - return createLabel("Set Period", "Set Repeat Period Label"); - } - - private static JLabel createReminderTextLabel() { - return createLabel("Reminder Text", "Reminder Text Label"); - } - - private JLabel createPeriodLabel() { - return createLabel("0", "Period label"); - } - - private JLabel createDelaysLabel() { - return createLabel("30", "Delays Label"); - } - - private JComboBox createPeriodComboBox(final Integer periodInSeconds) { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{0, 5, 10, 20})); - comboBox.setName("set Period"); - comboBox.setSelectedItem(periodInSeconds); - comboBox.addActionListener(e -> periodLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JComboBox createDelayComboBox(Integer delay) { - final JComboBox comboBox = new JComboBox<>(new DefaultComboBoxModel<>(new Integer[]{30, 25, 15, 5})); - comboBox.setSelectedItem(delay); - comboBox.setName("set Delay"); - comboBox.addActionListener(e -> delaysLabel.setText(comboBox.getSelectedItem().toString())); - return comboBox; - } - - private JTextField createTextField(final String text) { - final JTextField textField = new JTextField(20); - textField.setName("Field"); - textField.setText(text); - return textField; - } - - private JButton createDisabledOkButton() { - final JButton button = new JButton("ok"); - button.setName("OK"); - button.setEnabled(false); - return button; - } - - private JButton createCancelButton() { - final JButton button = new JButton("cancel"); - button.setName("Cancel"); - button.addActionListener(e -> this.dispose()); - return button; - } - - private static JLabel createLabel(final String text, final String name) { - JLabel label = new JLabel(text); - label.setName(name); - return label; - } - -} diff --git a/core-java-modules/core-java-11-2/README.md b/core-java-modules/core-java-11-2/README.md index ab8331f41c..b9dc82bc7f 100644 --- a/core-java-modules/core-java-11-2/README.md +++ b/core-java-modules/core-java-11-2/README.md @@ -5,7 +5,6 @@ This module contains articles about Java 11 core features ### Relevant articles - [Guide To Java 8 Optional](https://www.baeldung.com/java-optional) - [Guide to Java Reflection](http://www.baeldung.com/java-reflection) -- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors) - [New Features in Java 11](https://www.baeldung.com/java-11-new-features) - [Getting the Java Version at Runtime](https://www.baeldung.com/get-java-version-runtime) - [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service) diff --git a/core-java-modules/core-java-12/pom.xml b/core-java-modules/core-java-12/pom.xml index ba6dfc62bc..8165549d8c 100644 --- a/core-java-modules/core-java-12/pom.xml +++ b/core-java-modules/core-java-12/pom.xml @@ -8,9 +8,9 @@ jar - com.baeldung - parent-modules - 1.0.0-SNAPSHOT + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT @@ -21,30 +21,8 @@
- - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source.version} - ${maven.compiler.target.version} - --enable-preview - - - - maven-surefire-plugin - - --enable-preview - - - - - - 12 - 12 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java b/core-java-modules/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java index 708e416090..994c6d9a73 100644 --- a/core-java-modules/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java +++ b/core-java-modules/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java @@ -19,19 +19,6 @@ public class SwitchUnitTest { Assert.assertEquals(value, 2); } - @Test - public void switchLocalVariable(){ - var month = Month.AUG; - int i = switch (month){ - case JAN,JUN, JUL -> 3; - case FEB,SEP, OCT, NOV, DEC -> 1; - case MAR,MAY, APR, AUG -> { - int j = month.toString().length() * 4; - break j; - } - }; - Assert.assertEquals(12, i); - } enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC} } diff --git a/core-java-modules/core-java-13/pom.xml b/core-java-modules/core-java-13/pom.xml index 11d6ee7007..52cf227583 100644 --- a/core-java-modules/core-java-13/pom.xml +++ b/core-java-modules/core-java-13/pom.xml @@ -8,39 +8,13 @@ jar - com.baeldung - parent-modules - 1.0.0-SNAPSHOT + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source.version} - ${maven.compiler.target.version} - 13 - --enable-preview - - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire.plugin.version} - - --enable-preview - - - - - - 13 - 13 - 3.0.0-M3 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/SwitchExpressionsWithYieldUnitTest.java b/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/SwitchExpressionsWithYieldUnitTest.java index be1fcfd167..3d3f319218 100644 --- a/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/SwitchExpressionsWithYieldUnitTest.java +++ b/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/SwitchExpressionsWithYieldUnitTest.java @@ -7,7 +7,6 @@ import org.junit.Test; public class SwitchExpressionsWithYieldUnitTest { @Test - @SuppressWarnings("preview") public void whenSwitchingOnOperationSquareMe_thenWillReturnSquare() { var me = 4; var operation = "squareMe"; diff --git a/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/TextBlocksUnitTest.java b/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/TextBlocksUnitTest.java index 1f8ddcbfb4..e028e5f02c 100644 --- a/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/TextBlocksUnitTest.java +++ b/core-java-modules/core-java-13/src/test/java/com/baeldung/newfeatures/TextBlocksUnitTest.java @@ -8,7 +8,6 @@ public class TextBlocksUnitTest { private static final String JSON_STRING = "{\r\n" + "\"name\" : \"Baeldung\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}"; - @SuppressWarnings("preview") private static final String TEXT_BLOCK_JSON = """ { "name" : "Baeldung", @@ -25,7 +24,6 @@ public class TextBlocksUnitTest { } - @SuppressWarnings("removal") @Test public void whenTextBlocks_thenFormattedWorksAsFormat() { assertThat(TEXT_BLOCK_JSON.formatted("baeldung") diff --git a/core-java-modules/core-java-13/src/test/java/com/baeldung/switchExpression/SwitchExpressionsUnitTest.java b/core-java-modules/core-java-13/src/test/java/com/baeldung/switchExpression/SwitchExpressionsUnitTest.java index bb9250f000..04aea79a67 100644 --- a/core-java-modules/core-java-13/src/test/java/com/baeldung/switchExpression/SwitchExpressionsUnitTest.java +++ b/core-java-modules/core-java-13/src/test/java/com/baeldung/switchExpression/SwitchExpressionsUnitTest.java @@ -13,7 +13,6 @@ import org.junit.Test; public class SwitchExpressionsUnitTest { @Test - @SuppressWarnings ("preview") public void whenSwitchingOverMonthJune_thenWillReturn3() { var month = JUNE; @@ -29,7 +28,6 @@ public class SwitchExpressionsUnitTest { } @Test - @SuppressWarnings ("preview") public void whenSwitchingOverMonthAugust_thenWillReturn24() { var month = AUGUST; @@ -47,7 +45,6 @@ public class SwitchExpressionsUnitTest { } @Test - @SuppressWarnings ("preview") public void whenSwitchingOverMonthJanuary_thenWillReturn3() { Function func = (month) -> { @@ -61,7 +58,6 @@ public class SwitchExpressionsUnitTest { } @Test - @SuppressWarnings ("preview") public void whenSwitchingOverMonthAugust_thenWillReturn2() { var month = AUGUST; diff --git a/core-java-modules/core-java-14/pom.xml b/core-java-modules/core-java-14/pom.xml index 9f48c0b8b2..55c50b2a5c 100644 --- a/core-java-modules/core-java-14/pom.xml +++ b/core-java-modules/core-java-14/pom.xml @@ -48,7 +48,6 @@ 14 - 3.8.1 3.0.0-M3 diff --git a/core-java-modules/core-java-15/pom.xml b/core-java-modules/core-java-15/pom.xml index 059e2cc8f3..3996c69fa4 100644 --- a/core-java-modules/core-java-15/pom.xml +++ b/core-java-modules/core-java-15/pom.xml @@ -8,10 +8,9 @@ jar - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../pom.xml + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT @@ -27,34 +26,8 @@ - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.release} - --enable-preview - 14 - 14 - - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire.plugin.version} - - --enable-preview - - - - - - 15 - 3.8.1 - 3.0.0-M3 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-16/README.md b/core-java-modules/core-java-16/README.md index b2740d194c..a0392dcfed 100644 --- a/core-java-modules/core-java-16/README.md +++ b/core-java-modules/core-java-16/README.md @@ -4,4 +4,4 @@ - [Guide to mapMulti in Stream API](https://www.baeldung.com/java-mapmulti) - [Collecting Stream Elements into a List in Java](https://www.baeldung.com/java-stream-to-list-collecting) - [New Features in Java 16](https://www.baeldung.com/java-16-new-features) -- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector) +- [Value-Based Classes in Java](https://www.baeldung.com/java-value-based-classes) diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java new file mode 100644 index 0000000000..a3055985af --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java @@ -0,0 +1,54 @@ +package com.baeldung.value_based_class; + +import java.util.Objects; + +import jdk.internal.ValueBased; + +/** + * This class is written with the intention that it can serve as an example of + * what a Value-based class could be. + */ + +@ValueBased +public final class Point { + private final int x; + private final int y; + private final int z; + + private static Point ORIGIN = new Point(0, 0, 0); + + private Point(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public static Point valueOfPoint(int x, int y, int z) { + // returns a cached instance if it is origin, or a new instance + if (isOrigin(x, y, z)) + return ORIGIN; + return new Point(x, y, z); + } + + @Override + public String toString() { + return "Point{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; + } + + @Override + public boolean equals(Object other) { + if (other == null || getClass() != other.getClass()) + return false; + Point point = (Point) other; + return x == point.x && y == point.y && z == point.z; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } + + private static boolean isOrigin(int x, int y, int z) { + return x == 0 && y == 0 && z == 0; + } +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java new file mode 100644 index 0000000000..fe031a652f --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.value_based_class; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class ValueBasedClassUnitTest { + @Test + public void givenAutoboxedAndPrimitive_whenCompared_thenReturnEquals() { + List list = new ArrayList<>(); + list.add(1); // this is autoboxed + Assert.assertEquals(list.get(0), Integer.valueOf(1)); + } + + @Test + public void givenValueBasedPoint_whenCreated_thenReturnsObjects() { + Point p1 = Point.valueOfPoint(1, 2, 3); + Point p2 = Point.valueOfPoint(2, 3, 4); + + Assert.assertNotEquals(p1, p2); + } + + @Test + public void givenValueBasedPoint_whenCompared_thenReturnEquals() { + Point p1 = Point.valueOfPoint(1, 2, 3); + Point p2 = Point.valueOfPoint(1, 2, 3); + + Assert.assertEquals(p1, p2); + } + + @Test + public void givenValueBasedPoint_whenOrigin_thenReturnCachedInstance() { + Point p1 = Point.valueOfPoint(0, 0, 0); + Point p2 = Point.valueOfPoint(0, 0, 0); + Point p3 = Point.valueOfPoint(1, 2, 3); + + // the following should not be assumed for value-based classes + + Assert.assertTrue(p1 == p2); + Assert.assertFalse(p1 == p3); + } +} diff --git a/core-java-modules/core-java-17/README.md b/core-java-modules/core-java-17/README.md index 1af860b7c4..4b1125532d 100644 --- a/core-java-modules/core-java-17/README.md +++ b/core-java-modules/core-java-17/README.md @@ -7,3 +7,5 @@ - [Random Number Generators in Java 17](https://www.baeldung.com/java-17-random-number-generators) - [Sealed Classes and Interfaces in Java](https://www.baeldung.com/java-sealed-classes-interfaces) - [Migrate From Java 8 to Java 17](https://www.baeldung.com/java-migrate-8-to-17) +- [Format Multiple ‘or’ Conditions in an If Statement in Java](https://www.baeldung.com/java-multiple-or-conditions-if-statement) +- [Get All Record Fields and Its Values via Reflection](https://www.baeldung.com/java-reflection-record-fields-values) diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/multipleorwithif/MultipleOrWithIfUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/multipleorwithif/MultipleOrWithIfUnitTest.java new file mode 100644 index 0000000000..09b8d3c2b1 --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/multipleorwithif/MultipleOrWithIfUnitTest.java @@ -0,0 +1,126 @@ +package com.baeldung.multipleorwithif; + +import static java.time.Month.DECEMBER; +import static java.time.Month.NOVEMBER; +import static java.time.Month.OCTOBER; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.in; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Month; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +class MultipleOrWithIfUnitTest { + + private final Random rand = new Random(); + + final Set months = Set.of(OCTOBER, NOVEMBER, DECEMBER); + + @Test + public void givenIfStatement_whenMultipleOrOperator_thenAssert() { + assertTrue(multipleOrOperatorIf(monthIn())); + assertFalse(multipleOrOperatorIf(monthNotIn())); + } + + boolean multipleOrOperatorIf(Month month) { + if (month == OCTOBER || month == NOVEMBER || month == DECEMBER) { + return true; + } + return false; + } + + @Test + public void givenSwitch_whenMultipleCase_thenBreakAndAssert() { + assertTrue(switchMonth(monthIn())); + assertFalse(switchMonth(monthNotIn())); + } + + boolean switchMonth(Month month) { + return switch (month) { + case OCTOBER, NOVEMBER, DECEMBER -> true; + default -> false; + }; + } + + @Test + public void givenAllowedValuesList_whenContains_thenAssert() { + assertTrue(contains(monthIn())); + assertFalse(contains(monthNotIn())); + } + + @Test + public void givenPredicates_whenTestMultipleOr_thenAssert() { + assertTrue(predicateWithIf(monthIn())); + assertFalse(predicateWithIf(monthNotIn())); + } + + @Test + public void givenInputList_whenFilterWithPredicate_thenAssert() { + + List list = List.of(monthIn(), monthIn(), monthNotIn()); + + list.stream() + .filter(this::predicateWithIf) + .forEach(m -> assertThat(m, is(in(months)))); + } + + Predicate orPredicate() { + Predicate predicate = x -> x == OCTOBER; + Predicate predicate1 = x -> x == NOVEMBER; + Predicate predicate2 = x -> x == DECEMBER; + + return predicate.or(predicate1) + .or(predicate2); + } + + boolean predicateWithIf(Month month) { + if (orPredicate().test(month)) { + return true; + } + return false; + } + + @Test + public void givenContainsInSetPredicate_whenTestPredicate_thenAssert() { + Predicate collectionPredicate = this::contains; + + assertTrue(collectionPredicate.test(monthIn())); + assertFalse(collectionPredicate.test(monthNotIn())); + } + + @Test + public void givenInputList_whenFilterWithContains_thenAssert() { + + List monthList = List.of(monthIn(), monthIn(), monthNotIn()); + + monthList.stream() + .filter(this::contains) + .forEach(m -> assertThat(m, is(in(months)))); + } + + private boolean contains(Month month) { + if (months.contains(month)) { + return true; + } + return false; + } + + private Month monthIn() { + return Month.of(rand.ints(10, 13) + .findFirst() + .orElse(10)); + } + + private Month monthNotIn() { + return Month.of(rand.ints(1, 10) + .findFirst() + .orElse(1)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java new file mode 100644 index 0000000000..4ffe3ecbeb --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java @@ -0,0 +1,89 @@ +package com.baeldung.recordproperties; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.reflect.Field; +import java.lang.reflect.RecordComponent; +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +record Player(String name, int age, Long score) { +} + +public class ReadRecordPropertiesByReflectionUnitTest { + private static final Player ERIC = new Player("Eric", 28, 4242L); + + @Test + void whenUsingRecordComponent_thenGetExpectedResult() { + var fields = new ArrayList(); + RecordComponent[] components = Player.class.getRecordComponents(); + for (var comp : components) { + try { + Field field = ERIC.getClass() + .getDeclaredField(comp.getName()); + field.setAccessible(true); + fields.add(field); + } catch (NoSuchFieldException e) { + // for simplicity, error handling is skipped + } + } + + assertEquals(3, fields.size()); + + var nameField = fields.get(0); + var ageField = fields.get(1); + var scoreField = fields.get(2); + try { + assertEquals("name", nameField.getName()); + assertEquals(String.class, nameField.getType()); + assertEquals("Eric", nameField.get(ERIC)); + + assertEquals("age", ageField.getName()); + assertEquals(int.class, ageField.getType()); + assertEquals(28, ageField.get(ERIC)); + + assertEquals("score", scoreField.getName()); + assertEquals(Long.class, scoreField.getType()); + assertEquals(4242L, scoreField.get(ERIC)); + } catch (IllegalAccessException exception) { + // for simplicity, error handling is skipped + } + + } + + @Test + void whenUsingClassGetDeclaredField_thenGetExpectedResult() { + // record has no public fields + assertEquals(0, Player.class.getFields().length); + + var fields = new ArrayList(); + for (var field : Player.class.getDeclaredFields()) { + field.setAccessible(true); + fields.add(field); + } + + assertEquals(3, fields.size()); + var nameField = fields.get(0); + var ageField = fields.get(1); + var scoreField = fields.get(2); + + try { + assertEquals("name", nameField.getName()); + assertEquals(String.class, nameField.getType()); + assertEquals("Eric", nameField.get(ERIC)); + + assertEquals("age", ageField.getName()); + assertEquals(int.class, ageField.getType()); + assertEquals(28, ageField.get(ERIC)); + + assertEquals("score", scoreField.getName()); + assertEquals(Long.class, scoreField.getType()); + assertEquals(4242L, scoreField.get(ERIC)); + } catch (IllegalAccessException ex) { + // for simplicity, error handling is skipped + } + + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-18/README.md b/core-java-modules/core-java-18/README.md new file mode 100644 index 0000000000..63772e96b3 --- /dev/null +++ b/core-java-modules/core-java-18/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Deprecate Finalization in Java 18](https://www.baeldung.com/java-18-deprecate-finalization) diff --git a/core-java-modules/core-java-18/pom.xml b/core-java-modules/core-java-18/pom.xml new file mode 100644 index 0000000000..7af6258497 --- /dev/null +++ b/core-java-modules/core-java-18/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + core-java-18 + core-java-18 + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.release} + --enable-preview + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + 1 + + + + org.apache.maven.surefire + surefire-api + ${surefire.plugin.version} + + + + + + + + 18 + 18 + 18 + 3.0.0-M5 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java new file mode 100644 index 0000000000..3ff77c37d6 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java @@ -0,0 +1,27 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.IOException; + +public class FinalizationExamples { + FileInputStream fis = null; + + public void readFileOperationWithFinalization() throws IOException { + try { + fis = new FileInputStream("input.txt"); + // perform operation on the file + System.out.println(fis.readAllBytes().length); + + } finally { + if (fis != null) + fis.close(); + } + } + + public void readFileOperationWithTryWith() throws IOException { + try (FileInputStream fis = new FileInputStream("input.txt")) { + // perform operations + System.out.println(fis.readAllBytes().length); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java new file mode 100644 index 0000000000..1dcdd216cb --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java @@ -0,0 +1,48 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.lang.ref.Cleaner; + +public class MyCleanerResourceClass implements AutoCloseable { + private static Resource resource; + + private static final Cleaner cleaner = Cleaner.create(); + private final Cleaner.Cleanable cleanable; + + public MyCleanerResourceClass() { + resource = new Resource(); + this.cleanable = cleaner.register(this, new CleaningState()); + } + + public void useResource() { + // using the resource here + resource.use(); + } + + @Override + public void close() { + // perform actions to close all underlying resources + this.cleanable.clean(); + } + + static class CleaningState implements Runnable { + CleaningState() { + // constructor + } + + @Override + public void run() { + // some cleanup action + System.out.println("Cleanup done"); + } + } + + static class Resource { + void use() { + System.out.println("Using the resource"); + } + + void close() { + System.out.println("Cleanup done"); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java new file mode 100644 index 0000000000..b11cb4e49e --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java @@ -0,0 +1,25 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyCloseableResourceClass implements AutoCloseable { + + private final FileInputStream fis; + + public MyCloseableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + @Override + public void close() throws IOException { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java new file mode 100644 index 0000000000..a2c6a123b4 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java @@ -0,0 +1,24 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyFinalizableResourceClass { + private FileInputStream fis; + + public MyFinalizableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + + @Override + protected void finalize() throws Throwable { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/resources/file.txt b/core-java-modules/core-java-18/src/main/resources/file.txt new file mode 100644 index 0000000000..af27ff4986 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/resources/file.txt @@ -0,0 +1 @@ +This is a test file. \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java new file mode 100644 index 0000000000..22ff228227 --- /dev/null +++ b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.finalization_closeable_cleaner; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +public class FinalizationCloseableCleanerUnitTest { + + @Test + public void givenMyFinalizationResource_whenUsingFinalize_thenShouldClean() { + assertDoesNotThrow(() -> { + MyFinalizableResourceClass mfr = new MyFinalizableResourceClass(); + mfr.getByteLength(); + }); + } + @Test + public void givenMyCleanerResource_whenUsingCleanerAPI_thenShouldClean() { + assertDoesNotThrow(() -> { + try (MyCleanerResourceClass myCleanerResourceClass = new MyCleanerResourceClass()) { + myCleanerResourceClass.useResource(); + } + }); + } + + @Test + public void givenCloseableResource_whenUsingTryWith_thenShouldClose() throws IOException { + int length = 0; + try (MyCloseableResourceClass mcr = new MyCloseableResourceClass()) { + length = mcr.getByteLength(); + } + Assert.assertEquals(20, length); + } +} diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md new file mode 100644 index 0000000000..ffb999a4ba --- /dev/null +++ b/core-java-modules/core-java-21/README.md @@ -0,0 +1,5 @@ +## Relevant Articles +- [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) +- [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates) +- [Unnamed Classes and Instance Main Methods in Java 21](https://www.baeldung.com/java-21-unnamed-class-instance-main) +- [Unnamed Patterns and Variables in Java 21](https://www.baeldung.com/java-unnamed-patterns-variables) diff --git a/core-java-modules/core-java-21/pom.xml b/core-java-modules/core-java-21/pom.xml new file mode 100644 index 0000000000..bfe1cd2c78 --- /dev/null +++ b/core-java-modules/core-java-21/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + core-java-21 + core-java-21 + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + + false + + --enable-preview + + + + + org.apache.maven.plugins + maven-surefire-plugin + + --enable-preview + + + + + + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedCollection.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedCollection.java new file mode 100644 index 0000000000..58f5dbd014 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedCollection.java @@ -0,0 +1,15 @@ +package com.baeldung.sequenced.collections; + +/* +interface SequencedCollection extends Collection { + // new method + SequencedCollection reversed(); + // methods promoted from Deque + void addFirst(E); + void addLast(E); + E getFirst(); + E getLast(); + E removeFirst(); + E removeLast(); +} + */ diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedMap.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedMap.java new file mode 100644 index 0000000000..925449a090 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedMap.java @@ -0,0 +1,18 @@ +package com.baeldung.sequenced.collections; + +/* +interface SequencedMap extends Map { + // new methods + SequencedMap reversed(); + SequencedSet sequencedKeySet(); + SequencedCollection sequencedValues(); + SequencedSet> sequencedEntrySet(); + V putFirst(K, V); + V putLast(K, V); + // methods promoted from NavigableMap + Entry firstEntry(); + Entry lastEntry(); + Entry pollFirstEntry(); + Entry pollLastEntry(); +} + */ \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedSet.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedSet.java new file mode 100644 index 0000000000..a8fb4caa1f --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/sequenced/collections/SequencedSet.java @@ -0,0 +1,7 @@ +package com.baeldung.sequenced.collections; + +/* +interface SequencedSet extends Set, SequencedCollection { + SequencedSet reversed(); // covariant override +} + */ diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringCompositionTechniques.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringCompositionTechniques.java new file mode 100644 index 0000000000..7e66144f1c --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringCompositionTechniques.java @@ -0,0 +1,37 @@ +package com.baeldung.stringtemplates; + +import java.text.MessageFormat; + +public class StringCompositionTechniques { + String composeUsingPlus(String feelsLike, String temperature, String unit) { + return "Today's weather is " + feelsLike + ", with a temperature of " + temperature + " degrees " + unit; + } + + String composeUsingStringBuffer(String feelsLike, String temperature, String unit) { + return new StringBuffer().append("Today's weather is ") + .append(feelsLike) + .append(", with a temperature of ") + .append(temperature) + .append(" degrees ") + .append(unit) + .toString(); + } + + String composeUsingStringBuilder(String feelsLike, String temperature, String unit) { + return new StringBuilder().append("Today's weather is ") + .append(feelsLike) + .append(", with a temperature of ") + .append(temperature) + .append(" degrees ") + .append(unit) + .toString(); + } + + String composeUsingFormatters(String feelsLike, String temperature, String unit) { + return String.format("Today's weather is %s, with a temperature of %s degrees %s", feelsLike, temperature, unit); + } + + String composeUsingMessageFormatter(String feelsLike, String temperature, String unit) { + return MessageFormat.format("Today''s weather is {0}, with a temperature of {1} degrees {2}", feelsLike, temperature, unit); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringTemplateExamples.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringTemplateExamples.java new file mode 100644 index 0000000000..0fb18a84e9 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/stringtemplates/StringTemplateExamples.java @@ -0,0 +1,56 @@ +package com.baeldung.stringtemplates; + +import static java.lang.StringTemplate.RAW; +import static java.util.FormatProcessor.FMT; + +public class StringTemplateExamples { + String interpolationUsingSTRProcessor(String feelsLike, String temperature, String unit) { + return STR + . "Today's weather is \{ feelsLike }, with a temperature of \{ temperature } degrees \{ unit }" ; + } + + String interpolationOfJSONBlock(String feelsLike, String temperature, String unit) { + return STR + . """ + { + "feelsLike": "\{ feelsLike }", + "temperature": "\{ temperature }", + "unit": "\{ unit }" + } + """ ; + } + + String interpolationWithExpressions() { + return STR + . "Today's weather is \{ getFeelsLike() }, with a temperature of \{ getTemperature() } degrees \{ getUnit() }" ; + } + + String interpolationWithTemplates() { + StringTemplate str = RAW + . "Today's weather is \{ getFeelsLike() }, with a temperature of \{ getTemperature() } degrees \{ getUnit() }" ; + return STR.process(str); + } + + String interpolationOfJSONBlockWithFMT(String feelsLike, float temperature, String unit) { + return FMT + . """ + { + "feelsLike": "%1s\{ feelsLike }", + "temperature": "%2.2f\{ temperature }", + "unit": "%1s\{ unit }" + } + """ ; + } + + private String getFeelsLike() { + return "pleasant"; + } + + private String getTemperature() { + return "25"; + } + + private String getUnit() { + return "Celsius"; + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java new file mode 100644 index 0000000000..8f51c03539 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java @@ -0,0 +1,11 @@ +package com.baeldung.unnamed.variables; + +public record Car(String name, String color, T engine) { } + +abstract class Engine { } + +class GasEngine extends Engine { } + +class ElectricEngine extends Engine { } + +class HybridEngine extends Engine { } \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java new file mode 100644 index 0000000000..310ce621f9 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java @@ -0,0 +1,50 @@ +package com.baeldung.unnamed.variables; + +public class UnnamedPatterns { + + static String getObjectsColorWithNamedPattern(Object object) { + if (object instanceof Car(String name, String color, Engine engine)) { + return color; + } + return "No color!"; + } + + static String getObjectsColorWithUnnamedPattern(Object object) { + if (object instanceof Car(_, String color, _)) { + return color; + } + return "No color!"; + } + + static String getObjectsColorWithSwitchAndNamedPattern(Object object) { + return switch (object) { + case Car(String name, String color, Engine engine) -> color; + default -> "No color!"; + }; + } + + static String getObjectsColorWithSwitchAndUnnamedPattern(Object object) { + return switch (object) { + case Car(_, String color, _) -> color; + default -> "No color!"; + }; + } + + static String getEngineTypeWithNamedPattern(Car car) { + return switch (car) { + case Car(String name, String color, GasEngine engine) -> "gas"; + case Car(String name, String color, ElectricEngine engine) -> "electric"; + case Car(String name, String color, HybridEngine engine) -> "hybrid"; + default -> "none"; + }; + } + + static String getEngineTypeWithUnnamedPattern(Car car) { + return switch (car) { + case Car(_, _, GasEngine _) -> "gas"; + case Car(_, _, ElectricEngine _) -> "electric"; + case Car(_, _, HybridEngine _) -> "hybrid"; + default -> "none"; + }; + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java new file mode 100644 index 0000000000..82e76b40a4 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java @@ -0,0 +1,134 @@ +package com.baeldung.unnamed.variables; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +class Transaction implements AutoCloseable { + + @Override + public void close() { + System.out.println("Closed!"); + } +} + +public class UnnamedVariables { + + static int countCarsOverLimitWithNamedVariable(Collection> cars, int limit) { + var total = 0; + var totalOverLimit = 0; + for (var car : cars) { + total++; + if (total > limit) { + totalOverLimit++; + // side effect + } + } + return totalOverLimit; + } + + static int countCarsOverLimitWithUnnamedVariable(Collection> cars, int limit) { + var total = 0; + var totalOverLimit = 0; + for (var _ : cars) { + total++; + if (total > limit) { + totalOverLimit++; + // side effect + } + } + return totalOverLimit; + } + + static void sendNotificationToCarsWithNamedVariable(Collection> cars) { + sendOneTimeNotification(); + for (int i = 0; i < cars.size(); i++) { + // Notify car + } + } + + static void sendNotificationToCarsWithUnnamedVariable(Collection> cars) { + for (int i = 0, _ = sendOneTimeNotification(); i < cars.size(); i++) { + // Notify car + } + } + + private static int sendOneTimeNotification() { + System.out.println("Sending one time notification!"); + return 1; + } + + static Car removeThreeCarsAndReturnFirstRemovedWithNamedVariables(Queue> cars) { + var x = cars.poll(); + var y = cars.poll(); + var z = cars.poll(); + return x; + } + + static Car removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables(Queue> cars) { + var car = cars.poll(); + var _ = cars.poll(); + var _ = cars.poll(); + return car; + } + + static void handleCarExceptionWithNamedVariables(Car car) { + try { + someOperationThatFails(car); + } catch (IllegalStateException ex) { + System.out.println("Got an illegal state exception for: " + car.name()); + } catch (RuntimeException ex) { + System.out.println("Got a runtime exception!"); + } + } + + static void handleCarExceptionWithUnnamedVariables(Car car) { + try { + someOperationThatFails(car); + } catch (IllegalStateException | NumberFormatException _) { + System.out.println("Got an illegal state exception for: " + car.name()); + } catch (RuntimeException _) { + System.out.println("Got a runtime exception!"); + } + } + + static void obtainTransactionAndUpdateCarWithNamedVariables(Car car) { + try (var transaction = new Transaction()) { + updateCar(car); + } + } + + static void obtainTransactionAndUpdateCarWithUnnamedVariables(Car car) { + try (var _ = new Transaction()) { + updateCar(car); + } + } + + static void updateCar(Car car) { + // Some update logic + System.out.println("Car updated!"); + } + + static Map>> getCarsByFirstLetterWithNamedVariables(List> cars) { + Map>> carMap = new HashMap<>(); + cars.forEach(car -> + carMap.computeIfAbsent(car.name().substring(0, 1), firstLetter -> new ArrayList<>()).add(car) + ); + return carMap; + } + + static Map>> getCarsByFirstLetterWithUnnamedVariables(List> cars) { + Map>> carMap = new HashMap<>(); + cars.forEach(car -> + carMap.computeIfAbsent(car.name().substring(0, 1), _ -> new ArrayList<>()).add(car) + ); + return carMap; + } + + private static void someOperationThatFails(Car car) { + throw new IllegalStateException("Triggered exception for: " + car.name()); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java new file mode 100644 index 0000000000..bf0e2c96c2 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java @@ -0,0 +1,3 @@ +void main() { + System.out.println("Hello, World!"); +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java new file mode 100644 index 0000000000..827be7c788 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldChild extends HelloWorldSuper { + void main() { + System.out.println("Hello, World!"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java new file mode 100644 index 0000000000..59c88716a4 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldSuper { + public static void main(String[] args) { + System.out.println("Hello from the superclass"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java new file mode 100644 index 0000000000..698516544e --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java @@ -0,0 +1,6 @@ +private String getMessage() { + return "Hello, World!"; +} +void main() { + System.out.println(getMessage()); +} diff --git a/core-java-modules/core-java-21/src/test/java/com.baeldung.stringtemplates/StringTemplatesUnitTest.java b/core-java-modules/core-java-21/src/test/java/com.baeldung.stringtemplates/StringTemplatesUnitTest.java new file mode 100644 index 0000000000..b9917cab18 --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com.baeldung.stringtemplates/StringTemplatesUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.stringtemplates; + +import org.junit.Assert; +import org.junit.Test; + +public class StringTemplatesUnitTest { + + @Test + public void whenStringConcat_thenReturnComposedString() { + StringCompositionTechniques stringCompositionTechniques = new StringCompositionTechniques(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", stringCompositionTechniques.composeUsingPlus("pleasant", "25", "Celsius")); + } + + @Test + public void whenStringBuffer_thenReturnComposedString() { + StringCompositionTechniques stringCompositionTechniques = new StringCompositionTechniques(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", stringCompositionTechniques.composeUsingStringBuffer("pleasant", "25", "Celsius")); + } + + @Test + public void whenStringBuilder_thenReturnComposedString() { + StringCompositionTechniques stringCompositionTechniques = new StringCompositionTechniques(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", stringCompositionTechniques.composeUsingStringBuilder("pleasant", "25", "Celsius")); + } + + @Test + public void whenStringFormatter_thenReturnComposedFormattedString() { + StringCompositionTechniques stringCompositionTechniques = new StringCompositionTechniques(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", stringCompositionTechniques.composeUsingFormatters("pleasant", "25", "Celsius")); + } + + @Test + public void whenMessageFormatter_thenReturnComposedFormattedString() { + StringCompositionTechniques stringCompositionTechniques = new StringCompositionTechniques(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", stringCompositionTechniques.composeUsingMessageFormatter("pleasant", "25", "Celsius")); + } + + @Test + public void whenUsingStringTemplateSTR_thenReturnInterpolatedString() { + StringTemplateExamples templateExamples = new StringTemplateExamples(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", templateExamples.interpolationUsingSTRProcessor("pleasant", "25", "Celsius")); + } + + @Test + public void whenUsingMultilineStringTemplateSTR_thenReturnInterpolatedString() { + StringTemplateExamples templateExamples = new StringTemplateExamples(); + Assert.assertEquals("{\n" + " \"feelsLike\": \"pleasant\",\n" + " \"temperature\": \"25\",\n" + " \"unit\": \"Celsius\"\n" + "}\n", templateExamples.interpolationOfJSONBlock("pleasant", "25", "Celsius")); + } + + @Test + public void whenUsingExpressionSTR_thenReturnInterpolatedString() { + StringTemplateExamples templateExamples = new StringTemplateExamples(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", templateExamples.interpolationWithExpressions()); + } + + @Test + public void whenUsingExpressionRAW_thenReturnInterpolatedString() { + StringTemplateExamples templateExamples = new StringTemplateExamples(); + Assert.assertEquals("Today's weather is pleasant, with a temperature of 25 degrees Celsius", templateExamples.interpolationWithTemplates()); + } + + @Test + public void whenUsingExpressionFMT_thenReturnInterpolatedString() { + StringTemplateExamples templateExamples = new StringTemplateExamples(); + Assert.assertEquals("{\n" + " \"feelsLike\": \"pleasant\",\n" + " \"temperature\": \"25.86\",\n" + " \"unit\": \"Celsius\"\n" + "}\n", templateExamples.interpolationOfJSONBlockWithFMT("pleasant", 25.8636F, "Celsius")); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java new file mode 100644 index 0000000000..2acb83cdef --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java @@ -0,0 +1,13 @@ +package com.baeldung.unnamed.variables; + +import java.util.List; + +class CarScenario { + + protected final List> cars = List.of( + new Car<>("Mitsubishi", "blue", new GasEngine()), + new Car<>("Toyota", "red", new ElectricEngine()), + new Car<>("Jaguar", "white", new HybridEngine()) + ); + +} diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java new file mode 100644 index 0000000000..9d860a201a --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.unnamed.variables; + +import static com.baeldung.unnamed.variables.UnnamedPatterns.getEngineTypeWithNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getEngineTypeWithUnnamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithSwitchAndNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithSwitchAndUnnamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithUnnamedPattern; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class UnnamedPatternsUnitTest extends CarScenario { + + @Test + public void whenExtractingColorWithNamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithUnnamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithUnnamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithSwitchAndNamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithSwitchAndNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithSwitchAndUnnamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithSwitchAndUnnamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingEngineTypeWithNamedPatterns_thenReturnGas() { + assertEquals("gas", getEngineTypeWithNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingEngineTypeWithUnnamedPatterns_thenReturnGas() { + assertEquals("gas", getEngineTypeWithUnnamedPattern(cars.get(0))); + } +} diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java new file mode 100644 index 0000000000..094879c277 --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.unnamed.variables; + +import static com.baeldung.unnamed.variables.UnnamedVariables.countCarsOverLimitWithNamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.countCarsOverLimitWithUnnamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.getCarsByFirstLetterWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.getCarsByFirstLetterWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.handleCarExceptionWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.handleCarExceptionWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.obtainTransactionAndUpdateCarWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.obtainTransactionAndUpdateCarWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.removeThreeCarsAndReturnFirstRemovedWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.sendNotificationToCarsWithNamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.sendNotificationToCarsWithUnnamedVariable; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.LinkedList; + +import org.junit.jupiter.api.Test; + +public class UnnamedVariablesUnitTest extends CarScenario { + + @Test + public void whenCountingCarsOverLimitWithNamedVariables_thenShouldReturnOne() { + assertEquals(1, countCarsOverLimitWithNamedVariable(cars, 2)); + } + + @Test + public void whenCountingCarsOverLimitWithUnnamedVariables_thenShouldReturnOne() { + assertEquals(1, countCarsOverLimitWithUnnamedVariable(cars, 2)); + } + + @Test + public void whenNotifyingCarsWithNamedVariables_thenShouldNotFail() { + assertDoesNotThrow(() -> sendNotificationToCarsWithNamedVariable(cars)); + } + + @Test + public void whenNotifyingCarsWithUnnamedVariables_thenShouldNotFail() { + assertDoesNotThrow(() -> sendNotificationToCarsWithUnnamedVariable(cars)); + } + + @Test + public void whenPollingCarsWithNamedVariables_thenReturnFirstOneAndEmptyQueue() { + var carQueue = new LinkedList<>(cars); + assertEquals("Mitsubishi", removeThreeCarsAndReturnFirstRemovedWithNamedVariables(carQueue).name()); + assertEquals(0, carQueue.size()); + } + + @Test + public void whenPollingCarsWithUnnamedVariables_thenReturnFirstOneAndEmptyQueue() { + var carQueue = new LinkedList<>(cars); + assertEquals("Mitsubishi", removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables(carQueue).name()); + assertEquals(0, carQueue.size()); + } + + @Test + public void whenHandlingExceptionWithNamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> handleCarExceptionWithNamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingExceptionWithUnnamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> handleCarExceptionWithUnnamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingTransactionUpdateWithNamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> obtainTransactionAndUpdateCarWithNamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingTransactionUpdateWithUnnamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> obtainTransactionAndUpdateCarWithUnnamedVariables(cars.get(0))); + } + + @Test + public void whenGettingCarsByFirstLetterWithNamedVariables_thenHaveThreeKeys() { + var carsByLetter = getCarsByFirstLetterWithNamedVariables(cars); + assertEquals(1, carsByLetter.get("M").size()); + assertEquals(1, carsByLetter.get("T").size()); + assertEquals(1, carsByLetter.get("J").size()); + } + + @Test + public void whenGettingCarsByFirstLetterWithUnnamedVariables_thenHaveThreeKeys() { + var carsByLetter = getCarsByFirstLetterWithUnnamedVariables(cars); + assertEquals(1, carsByLetter.get("M").size()); + assertEquals(1, carsByLetter.get("T").size()); + assertEquals(1, carsByLetter.get("J").size()); + } +} diff --git a/core-java-modules/core-java-8-datetime-2/README.md b/core-java-modules/core-java-8-datetime-2/README.md index b860ca979d..ac1e1ca81f 100644 --- a/core-java-modules/core-java-8-datetime-2/README.md +++ b/core-java-modules/core-java-8-datetime-2/README.md @@ -5,4 +5,5 @@ - [Parsing Date Strings with Varying Formats](https://www.baeldung.com/java-parsing-dates-many-formats) - [How Many Days Are There in a Particular Month of a Given Year?](https://www.baeldung.com/days-particular-month-given-year) - [Difference Between Instant and LocalDateTime](https://www.baeldung.com/java-instant-vs-localdatetime) +- [Add Minutes to a Time String in Java](https://www.baeldung.com/java-string-time-add-mins) - [[<-- Prev]](/core-java-modules/core-java-datetime-java8-1) diff --git a/core-java-modules/core-java-8-datetime-2/src/main/java/com/baeldung/rounddate/RoundDate.java b/core-java-modules/core-java-8-datetime-2/src/main/java/com/baeldung/rounddate/RoundDate.java new file mode 100644 index 0000000000..6fb7cf87b7 --- /dev/null +++ b/core-java-modules/core-java-8-datetime-2/src/main/java/com/baeldung/rounddate/RoundDate.java @@ -0,0 +1,113 @@ +package com.baeldung.rounddate; + +import java.time.DayOfWeek; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAdjusters; +import java.util.Calendar; +import java.util.Date; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +public class RoundDate { + public static Date getDate(int year, int month, int day, int hour, int minute) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month); + calendar.set(Calendar.DAY_OF_MONTH, day); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + + return calendar.getTime(); + } + + public static Date roundToDay(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + + public static Date roundToNearestUnit(Date date, int unit) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + + switch (unit) { + case Calendar.HOUR: + int minute = calendar.get(Calendar.MINUTE); + if (minute >= 0 && minute < 15) { + calendar.set(Calendar.MINUTE, 0); + } else if (minute >= 15 && minute < 45) { + calendar.set(Calendar.MINUTE, 30); + } else { + calendar.set(Calendar.MINUTE, 0); + calendar.add(Calendar.HOUR_OF_DAY, 1); + } + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + break; + + case Calendar.DAY_OF_MONTH: + int hour = calendar.get(Calendar.HOUR_OF_DAY); + if (hour >= 12) { + calendar.add(Calendar.DAY_OF_MONTH, 1); + } + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + break; + + case Calendar.MONTH: + int day = calendar.get(Calendar.DAY_OF_MONTH); + if (day >= 15) { + calendar.add(Calendar.MONTH, 1); + } + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + break; + } + + return calendar.getTime(); + } + + public static LocalDateTime roundToStartOfMonthUsingLocalDateTime(LocalDateTime dateTime) { + return dateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + } + + public static LocalDateTime roundToEndOfWeekUsingLocalDateTime(LocalDateTime dateTime) { + return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY)) + .withHour(23) + .withMinute(59) + .withSecond(59) + .withNano(999); + } + + public static ZonedDateTime roundToStartOfMonthUsingZonedDateTime(ZonedDateTime dateTime) { + return dateTime.withDayOfMonth(1) + .withHour(0) + .withMinute(0) + .withSecond(0) + .with(ChronoField.MILLI_OF_SECOND, 0) + .with(ChronoField.MICRO_OF_SECOND, 0) + .with(ChronoField.NANO_OF_SECOND, 0); + } + + public static ZonedDateTime roundToEndOfWeekUsingZonedDateTime(ZonedDateTime dateTime) { + return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY)) + .withHour(23) + .withMinute(59) + .withSecond(59) + .with(ChronoField.MILLI_OF_SECOND, 999) + .with(ChronoField.MICRO_OF_SECOND, 999) + .with(ChronoField.NANO_OF_SECOND, 999); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/rounddate/DateRoundingUnitTest.java b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/rounddate/DateRoundingUnitTest.java new file mode 100644 index 0000000000..bbe49d8340 --- /dev/null +++ b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/rounddate/DateRoundingUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.rounddate; + +import org.junit.Test; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; + +import static org.junit.Assert.assertEquals; + +public class DateRoundingUnitTest { + + @Test + public void givenDate_whenRoundToDay_thenBeginningOfDay() { + Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 30); + Date result = RoundDate.roundToDay(date); + assertEquals(RoundDate.getDate(2023, Calendar.JANUARY, 27, 0, 0), result); + } + + @Test + public void givenDate_whenRoundToNearestUnit_thenNearestUnit() { + Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 12); + Date result = RoundDate.roundToNearestUnit(date, Calendar.DAY_OF_MONTH); + Date expected = RoundDate.getDate(2023, Calendar.JANUARY, 28, 0, 0); + assertEquals(expected, result); + } + + @Test + public void givenLocalDateTime_whenRoundToStartOfMonth_thenStartOfMonth() { + LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12); + LocalDateTime result = RoundDate.roundToStartOfMonthUsingLocalDateTime(dateTime); + LocalDateTime expected = LocalDateTime.of(2023, 1, 1, 0, 0, 0); + assertEquals(expected, result); + } + + + @Test + public void givenZonedDateTime_whenRoundToStartOfMonth_thenStartOfMonth() { + ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault()); + ZonedDateTime result = RoundDate.roundToStartOfMonthUsingZonedDateTime(dateTime); + ZonedDateTime expected = ZonedDateTime.of(2023, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + assertEquals(expected, result); + } + + @Test + public void givenLocalDateTime_whenRoundToEndOfWeek_thenEndOfWeek() { + LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12); + LocalDateTime result = RoundDate.roundToEndOfWeekUsingLocalDateTime(dateTime); + LocalDateTime expected = LocalDateTime.of(2023, 1, 28, 23, 59, 59, 999); + assertEquals(expected, result); + } + + @Test + public void givenZonedDateTime_whenRoundToEndOfWeek_thenEndOfWeek() { + ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault()); + ZonedDateTime result = RoundDate.roundToEndOfWeekUsingZonedDateTime(dateTime); + ZonedDateTime expected = ZonedDateTime.of(2023, 1, 28, 23, 59, 59, 999, ZoneId.systemDefault()); + assertEquals(expected, result); + } + +} diff --git a/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/stringtime/AddMinuteStringTimeUnitTest.java b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/stringtime/AddMinuteStringTimeUnitTest.java new file mode 100644 index 0000000000..15b430cc6a --- /dev/null +++ b/core-java-modules/core-java-8-datetime-2/src/test/java/com/baeldung/stringtime/AddMinuteStringTimeUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.stringtime; + +import static org.junit.jupiter.api.Assertions.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalTime; +import java.util.Calendar; +import java.util.Date; +import org.junit.jupiter.api.Test; + +public class AddMinuteStringTimeUnitTest { + + @Test + public void givenTimeStringUsingSimpleDateFormat_whenIncrementedWith10Minutes_thenResultShouldBeCorrect() throws ParseException { + String timeString = "23:45"; + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm"); + Date date = timeFormat.parse(timeString); + + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.MINUTE, 10); + String result = timeFormat.format(cal.getTime()); + assertEquals("23:55", result); + + } + + @Test + public void givenTimeStringUsingLocalTime_whenIncrementedWith10Minutes_thenResultShouldBeCorrect() { + String timeString = "23:45"; + LocalTime time = LocalTime.parse(timeString); + LocalTime newTime = time.plusMinutes(10); + String result = newTime.toString(); + assertEquals("23:55", result); + } + +} diff --git a/core-java-modules/core-java-8-datetime/src/test/java/com/baeldung/dateapi/JavaDurationUnitTest.java b/core-java-modules/core-java-8-datetime/src/test/java/com/baeldung/dateapi/JavaDurationUnitTest.java index be43fb609a..d1bd77776a 100644 --- a/core-java-modules/core-java-8-datetime/src/test/java/com/baeldung/dateapi/JavaDurationUnitTest.java +++ b/core-java-modules/core-java-8-datetime/src/test/java/com/baeldung/dateapi/JavaDurationUnitTest.java @@ -3,9 +3,11 @@ package com.baeldung.dateapi; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; import java.time.Instant; +import java.time.LocalDateTime; import java.time.LocalTime; import java.time.temporal.ChronoUnit; @@ -19,7 +21,7 @@ public class JavaDurationUnitTest { LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30)); long seconds = Duration.between(initialTime, finalTime) - .getSeconds(); + .getSeconds(); assertThat(seconds).isEqualTo(30); } @@ -34,6 +36,22 @@ public class JavaDurationUnitTest { assertThat(seconds).isEqualTo(30); } + @Test + public void givenADuration_whenCallingisZeroAndisNegative_thenGetExpectedResult() { + LocalDateTime start = LocalDateTime.parse("2020-01-01T08:00:00"); + LocalDateTime end = LocalDateTime.parse("2020-01-01T12:00:00"); + assertFalse(Duration.between(start, end) + .isNegative()); + assertTrue(Duration.between(end, start) + .isNegative()); + + LocalDateTime theTime = LocalDateTime.parse("2023-09-09T08:00:00"); + assertTrue(Duration.between(theTime, theTime) + .isZero()); + assertFalse(Duration.between(theTime, theTime) + .isNegative()); + } + @Test public void test2() { Instant start = Instant.parse("2017-10-03T10:15:30.00Z"); @@ -53,17 +71,17 @@ public class JavaDurationUnitTest { assertEquals(1, fromMinutes.toHours()); assertEquals(120, duration.plusSeconds(60) - .getSeconds()); + .getSeconds()); assertEquals(30, duration.minusSeconds(30) - .getSeconds()); + .getSeconds()); assertEquals(120, duration.plus(60, ChronoUnit.SECONDS) - .getSeconds()); + .getSeconds()); assertEquals(30, duration.minus(30, ChronoUnit.SECONDS) - .getSeconds()); + .getSeconds()); Duration fromChar1 = Duration.parse("P1DT1H10M10.5S"); Duration fromChar2 = Duration.parse("PT10M"); } -} +} \ No newline at end of file diff --git a/core-java-modules/core-java-8/README.md b/core-java-modules/core-java-8/README.md index 6061f3318d..0921c1538a 100644 --- a/core-java-modules/core-java-8/README.md +++ b/core-java-modules/core-java-8/README.md @@ -11,5 +11,5 @@ This module contains articles about Java 8 core features - [Finding Min/Max in an Array with Java](https://www.baeldung.com/java-array-min-max) - [Internationalization and Localization in Java 8](https://www.baeldung.com/java-8-localization) - [Generalized Target-Type Inference in Java](https://www.baeldung.com/java-generalized-target-type-inference) -- [Monads in Java](https://www.baeldung.com/java-monads) +- [Monads in Java – Optional](https://www.baeldung.com/java-monads) - [[More -->]](/core-java-modules/core-java-8-2) diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/CustomSpliterator.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/CustomSpliterator.java new file mode 100644 index 0000000000..2f806cccda --- /dev/null +++ b/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/CustomSpliterator.java @@ -0,0 +1,48 @@ +package com.baeldung.spliterator; + +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class CustomSpliterator implements Spliterator { + private final List elements; + private int currentIndex; + + public CustomSpliterator(List elements) { + this.elements = elements; + this.currentIndex = 0; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (currentIndex < elements.size()) { + action.accept(elements.get(currentIndex)); + currentIndex++; + return true; + } + return false; + } + + @Override + public Spliterator trySplit() { + int currentSize = elements.size() - currentIndex; + if (currentSize < 2) { + return null; + } + + int splitIndex = currentIndex + currentSize / 2; + CustomSpliterator newSpliterator = new CustomSpliterator(elements.subList(currentIndex, splitIndex)); + currentIndex = splitIndex; + return newSpliterator; + } + + @Override + public long estimateSize() { + return elements.size() - currentIndex; + } + + @Override + public int characteristics() { + return ORDERED | SIZED | SUBSIZED | NONNULL; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/Executor.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/Executor.java deleted file mode 100644 index 3dc2fa06bb..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/Executor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.spliterator; - -import java.util.stream.Stream; - -public class Executor { - - public static int countAutors(Stream stream) { - RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true), - RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine); - return wordCounter.getCounter(); - } -} \ No newline at end of file diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorCounter.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorCounter.java deleted file mode 100644 index 8800eac55b..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorCounter.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.spliterator; - -public class RelatedAuthorCounter { - private final int counter; - private final boolean isRelated; - - public RelatedAuthorCounter(int counter, boolean isRelated) { - this.counter = counter; - this.isRelated = isRelated; - } - - public RelatedAuthorCounter accumulate(Author author) { - if (author.getRelatedArticleId() == 0) { - return isRelated ? this : new RelatedAuthorCounter(counter, true); - } else { - return isRelated ? new RelatedAuthorCounter(counter + 1, false) : this; - } - } - - public RelatedAuthorCounter combine(RelatedAuthorCounter RelatedAuthorCounter) { - return new RelatedAuthorCounter(counter + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated); - } - - public int getCounter() { - return counter; - } -} diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorSpliterator.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorSpliterator.java deleted file mode 100644 index 93c83b8127..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/spliterator/RelatedAuthorSpliterator.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.spliterator; - -import java.util.List; -import java.util.Spliterator; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -public class RelatedAuthorSpliterator implements Spliterator { - private final List list; - AtomicInteger current = new AtomicInteger(); - - public RelatedAuthorSpliterator(List list) { - this.list = list; - } - - @Override - public boolean tryAdvance(Consumer action) { - - action.accept(list.get(current.getAndIncrement())); - return current.get() < list.size(); - } - - @Override - public Spliterator trySplit() { - int currentSize = list.size() - current.get(); - if (currentSize < 10) { - return null; - } - for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) { - if (list.get(splitPos).getRelatedArticleId() == 0) { - Spliterator spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos)); - current.set(splitPos); - return spliterator; - } - } - return null; - } - - @Override - public long estimateSize() { - return list.size() - current.get(); - } - - @Override - public int characteristics() { - return CONCURRENT; - } - -} diff --git a/core-java-modules/core-java-8/src/test/java/com/baeldung/spliterator/ExecutorUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/baeldung/spliterator/ExecutorUnitTest.java index 4628f95481..30760ddf6f 100644 --- a/core-java-modules/core-java-8/src/test/java/com/baeldung/spliterator/ExecutorUnitTest.java +++ b/core-java-modules/core-java-8/src/test/java/com/baeldung/spliterator/ExecutorUnitTest.java @@ -6,10 +6,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Spliterator; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; - import org.junit.Before; import org.junit.Test; @@ -18,22 +18,50 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class ExecutorUnitTest { Article article; - Stream stream; - Spliterator spliterator; @Before public void init() { article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0); - - spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors()); } @Test - public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() { - Stream stream2 = StreamSupport.stream(spliterator, true); - assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9); + public void givenAStreamOfIntegers_whenProcessedSequentialCustomSpliterator_countProducesRightOutput() { + List numbers = new ArrayList<>(); + numbers.add(1); + numbers.add(2); + numbers.add(3); + numbers.add(4); + numbers.add(5); + + CustomSpliterator customSpliterator = new CustomSpliterator(numbers); + + AtomicInteger sum = new AtomicInteger(); + + customSpliterator.forEachRemaining(sum::addAndGet); + assertThat(sum.get()).isEqualTo(15); + } + + @Test + public void givenAStreamOfIntegers_whenProcessedInParallelWithCustomSpliterator_countProducesRightOutput() { + List numbers = new ArrayList<>(); + numbers.add(1); + numbers.add(2); + numbers.add(3); + numbers.add(4); + numbers.add(5); + + CustomSpliterator customSpliterator = new CustomSpliterator(numbers); + + // Create a ForkJoinPool for parallel processing + ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); + + AtomicInteger sum = new AtomicInteger(0); + + // Process elements in parallel using parallelStream + forkJoinPool.submit(() -> customSpliterator.forEachRemaining(sum::addAndGet)).join(); + assertThat(sum.get()).isEqualTo(15); } @Test @@ -43,9 +71,7 @@ public class ExecutorUnitTest { .collect(Collectors.toList()); Spliterator
spliterator = articles.spliterator(); - while (spliterator.tryAdvance(article -> article.setName(article.getName() - .concat("- published by Baeldung")))) - ; + while(spliterator.tryAdvance(article -> article.setName(article.getName().concat("- published by Baeldung")))); articles.forEach(article -> assertThat(article.getName()).isEqualTo("Java- published by Baeldung")); } diff --git a/core-java-modules/core-java-9-improvements/pom.xml b/core-java-modules/core-java-9-improvements/pom.xml index f6f13ff409..ce40a4acb8 100644 --- a/core-java-modules/core-java-9-improvements/pom.xml +++ b/core-java-modules/core-java-9-improvements/pom.xml @@ -10,7 +10,7 @@ com.baeldung parent-modules 1.0.0-SNAPSHOT - ../../ + ../../pom.xml diff --git a/core-java-modules/core-java-9-jigsaw/library-core/pom.xml b/core-java-modules/core-java-9-jigsaw/library-core/pom.xml index 80638367cf..415c7fb053 100644 --- a/core-java-modules/core-java-9-jigsaw/library-core/pom.xml +++ b/core-java-modules/core-java-9-jigsaw/library-core/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung + com.baeldung.core-java-modules core-java-9-jigsaw - 0.2-SNAPSHOT + 0.0.1-SNAPSHOT library-core diff --git a/core-java-modules/core-java-9-jigsaw/pom.xml b/core-java-modules/core-java-9-jigsaw/pom.xml index 288254b9cf..4afe2ae31a 100644 --- a/core-java-modules/core-java-9-jigsaw/pom.xml +++ b/core-java-modules/core-java-9-jigsaw/pom.xml @@ -11,10 +11,9 @@ - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../ + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT diff --git a/core-java-modules/core-java-9-new-features/pom.xml b/core-java-modules/core-java-9-new-features/pom.xml index 6821c9c340..9c897f1cea 100644 --- a/core-java-modules/core-java-9-new-features/pom.xml +++ b/core-java-modules/core-java-9-new-features/pom.xml @@ -152,7 +152,6 @@ 4.0.2 1.9 1.9 - 3.2.0 \ No newline at end of file diff --git a/core-java-modules/core-java-9-streams/README.md b/core-java-modules/core-java-9-streams/README.md index 0ad8500689..d9663e0858 100644 --- a/core-java-modules/core-java-9-streams/README.md +++ b/core-java-modules/core-java-9-streams/README.md @@ -4,3 +4,4 @@ This module contains articles about Java 9 streams ### Relevant Articles: - [How to Break from Java Stream forEach](https://www.baeldung.com/java-break-stream-foreach) +- [Creating Stream of Regex Matches](https://www.baeldung.com/java-stream-regex-matches) diff --git a/core-java-modules/core-java-9-streams/src/main/java/com/baeldung/streams/regexmatches/StreamFromRegexUtil.java b/core-java-modules/core-java-9-streams/src/main/java/com/baeldung/streams/regexmatches/StreamFromRegexUtil.java new file mode 100644 index 0000000000..f7187c79de --- /dev/null +++ b/core-java-modules/core-java-9-streams/src/main/java/com/baeldung/streams/regexmatches/StreamFromRegexUtil.java @@ -0,0 +1,16 @@ +package com.baeldung.streams.regexmatches; + +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +public class StreamFromRegexUtil { + + public static Stream getStream(String input, String regex) { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(input); + return matcher.results().map(MatchResult::group); + } + +} diff --git a/core-java-modules/core-java-9-streams/src/test/java/com/baeldung/streams/regexmatches/StreamFromRegexUnitTest.java b/core-java-modules/core-java-9-streams/src/test/java/com/baeldung/streams/regexmatches/StreamFromRegexUnitTest.java new file mode 100644 index 0000000000..9d8b840e0e --- /dev/null +++ b/core-java-modules/core-java-9-streams/src/test/java/com/baeldung/streams/regexmatches/StreamFromRegexUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.streams.regexmatches; + +import org.junit.Test; + +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class StreamFromRegexUnitTest { + + @Test + public void whenInputStringIncludeLettersAndNumbersAndRegex_ThenReturnStreamOfNumbers() { + List result = StreamFromRegexUtil.getStream("There are 3 apples and 2 bananas on the table.", "\\d+") + .collect(Collectors.toList()); + assertEquals(asList("3", "2"), result); + } + + @Test + public void whenInputStringsAndRegex_ThenReturnStreamOfJavaWords() { + List result = StreamFromRegexUtil.getStream("sample sentence with some words Java Java", "\\bJava\\b") + .collect(Collectors.toList()); + assertEquals(asList("Java", "Java"), result); + } + +} diff --git a/core-java-modules/core-java-arrays-convert/README.md b/core-java-modules/core-java-arrays-convert/README.md index b68773463d..2e34829525 100644 --- a/core-java-modules/core-java-arrays-convert/README.md +++ b/core-java-modules/core-java-arrays-convert/README.md @@ -9,3 +9,5 @@ This module contains articles about arrays conversion in Java - [Converting a String Array Into an int Array in Java](https://www.baeldung.com/java-convert-string-array-to-int-array) - [Convert Java Array to Iterable](https://www.baeldung.com/java-array-convert-to-iterable) - [Converting an int[] to HashSet in Java](https://www.baeldung.com/java-converting-int-array-to-hashset) +- [Convert an ArrayList of String to a String Array in Java](https://www.baeldung.com/java-convert-string-arraylist-array) +- [Convert Char Array to Int Array in Java](https://www.baeldung.com/java-convert-char-int-array) diff --git a/core-java-modules/core-java-arrays-convert/pom.xml b/core-java-modules/core-java-arrays-convert/pom.xml index c90b60e09a..480e1b3f07 100644 --- a/core-java-modules/core-java-arrays-convert/pom.xml +++ b/core-java-modules/core-java-arrays-convert/pom.xml @@ -20,5 +20,4 @@ ${commons-lang3.version} - \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java new file mode 100644 index 0000000000..fbd76a0113 --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java @@ -0,0 +1,67 @@ +package com.baeldung.array.conversions; + +import java.util.Arrays; + +public class CharArrayToIntArrayUtils { + + static int[] usingGetNumericValueMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.getNumericValue(chars[i]); + } + + return ints; + } + + static int[] usingDigitMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.digit(chars[i], 10); + } + + return ints; + } + + static int[] usingStreamApiMethod(char[] chars) { + if (chars == null) { + return null; + } + + return new String(chars).chars() + .map(c -> c - 48) + .toArray(); + } + + static int[] usingParseIntMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Integer.parseInt(String.valueOf(chars[i])); + } + + return ints; + } + + static int[] usingArraysSetAllMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + Arrays.setAll(ints, i -> Character.getNumericValue(chars[i])); + + return ints; + } + +} diff --git a/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java new file mode 100644 index 0000000000..534dc3893f --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.array.conversions; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +class CharArrayToIntArrayUtilsUnitTest { + + @Test + void givenCharArray_whenUsingGetNumericValueMethod_shouldGetIntArray() { + int[] expected = { 2, 3, 4, 5 }; + char[] chars = { '2', '3', '4', '5' }; + int[] result = CharArrayToIntArrayUtils.usingGetNumericValueMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingDigitMethod_shouldGetIntArray() { + int[] expected = { 1, 2, 3, 6 }; + char[] chars = { '1', '2', '3', '6' }; + int[] result = CharArrayToIntArrayUtils.usingDigitMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingStreamApi_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingStreamApiMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingParseIntMethod_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingParseIntMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingArraysSetAllMethod_shouldGetIntArray() { + int[] expected = { 4, 9, 2, 3 }; + char[] chars = { '4', '9', '2', '3' }; + int[] result = CharArrayToIntArrayUtils.usingArraysSetAllMethod(chars); + + assertArrayEquals(expected, result); + } + +} diff --git a/core-java-modules/core-java-arrays-guides/README.md b/core-java-modules/core-java-arrays-guides/README.md index 0af77980af..d8b0d126a1 100644 --- a/core-java-modules/core-java-arrays-guides/README.md +++ b/core-java-modules/core-java-arrays-guides/README.md @@ -9,3 +9,4 @@ This module contains complete guides about arrays in Java - [Guide to ArrayStoreException](https://www.baeldung.com/java-arraystoreexception) - [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array) - [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size) +- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates) diff --git a/core-java-modules/core-java-arrays-guides/src/main/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicate.java b/core-java-modules/core-java-arrays-guides/src/main/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicate.java new file mode 100644 index 0000000000..e0b249565f --- /dev/null +++ b/core-java-modules/core-java-arrays-guides/src/main/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicate.java @@ -0,0 +1,96 @@ +package com.baeldung.mergeandremoveduplicate; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + +public class MergeArraysAndRemoveDuplicate { + + public static int[] removeDuplicateOnSortedArray(int[] arr) { + // Initialize a new array to store unique elements + int[] uniqueArray = new int[arr.length]; + uniqueArray[0] = arr[0]; + int uniqueCount = 1; + + // Iterate through the sorted array to remove duplicates + for (int i = 1; i < arr.length; i++) { + if (arr[i] != arr[i - 1]) { + uniqueArray[uniqueCount] = arr[i]; + uniqueCount++; + } + } + int[] truncatedArray = new int[uniqueCount]; + System.arraycopy(uniqueArray, 0, truncatedArray, 0, uniqueCount); + return truncatedArray; + } + + public static int[] mergeAndRemoveDuplicatesUsingStream(int[] arr1, int[] arr2) { + Stream s1 = Arrays.stream(arr1).boxed(); + Stream s2 = Arrays.stream(arr2).boxed(); + return Stream.concat(s1, s2) + .distinct() + .mapToInt(Integer::intValue) + .toArray(); + } + + public static int[] mergeAndRemoveDuplicatesUsingSet(int[] arr1, int[] arr2) { + int[] mergedArr = mergeArrays(arr1, arr2); + Set uniqueInts = new HashSet<>(); + + for (int el : mergedArr) { + uniqueInts.add(el); + } + + return getArrayFromSet(uniqueInts); + } + + private static int[] getArrayFromSet(Set set) { + int[] mergedArrWithoutDuplicated = new int[set.size()]; + int i = 0; + for (Integer el: set) { + mergedArrWithoutDuplicated[i] = el; + i++; + } + return mergedArrWithoutDuplicated; + } + + public static int[] mergeAndRemoveDuplicates(int[] arr1, int[] arr2) { + return removeDuplicate(mergeArrays(arr1, arr2)); + } + + public static int[] mergeAndRemoveDuplicatesOnSortedArray(int[] arr1, int[] arr2) { + return removeDuplicateOnSortedArray(mergeArrays(arr1, arr2)); + } + + private static int[] mergeArrays(int[] arr1, int[] arr2) { + int[] mergedArrays = new int[arr1.length + arr2.length]; + System.arraycopy(arr1, 0, mergedArrays, 0, arr1.length); + System.arraycopy(arr2, 0, mergedArrays, arr1.length, arr2.length); + + return mergedArrays; + } + private static int[] removeDuplicate(int[] arr) { + int[] withoutDuplicates = new int[arr.length]; + int i = 0; + + for(int element : arr) { + if(!isElementPresent(withoutDuplicates, element)) { + withoutDuplicates[i] = element; + i++; + } + } + int[] truncatedArray = new int[i]; + System.arraycopy(withoutDuplicates, 0, truncatedArray, 0, i); + return truncatedArray; + } + + private static boolean isElementPresent(int[] arr, int element) { + for(int el : arr) { + if(el == element) { + return true; + } + } + return false; + } +} diff --git a/core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicateUnitTest.java b/core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicateUnitTest.java new file mode 100644 index 0000000000..5076ef8159 --- /dev/null +++ b/core-java-modules/core-java-arrays-guides/src/test/java/com/baeldung/mergeandremoveduplicate/MergeArraysAndRemoveDuplicateUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.mergeandremoveduplicate; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public class MergeArraysAndRemoveDuplicateUnitTest { + + private final Logger logger = LoggerFactory.getLogger(MergeArraysAndRemoveDuplicateUnitTest.class); + + private static String getCommaDelimited(int[] arr) { + return Arrays.stream(arr) + .mapToObj(Integer::toString) + .collect(Collectors.joining(", ")); + } + + @Test + public void givenNoLibraryAndUnSortedArrays_whenArr1andArr2_thenMergeAndRemoveDuplicates() { + int[] arr1 = {3, 2, 1, 4, 5, 6, 8, 7, 9}; + int[] arr2 = {8, 9, 10, 11, 12, 13, 15, 14, 15, 14, 16, 17}; + int[] expectedArr = {3, 2, 1, 4, 5, 6, 8, 7, 9, 10, 11, 12, 13, 15, 14, 16, 17}; + + int[] mergedArr = MergeArraysAndRemoveDuplicate.mergeAndRemoveDuplicates(arr1, arr2); + + //merged array maintains the order of the elements in the arrays + assertArrayEquals(expectedArr, mergedArr); + + logger.info(getCommaDelimited(mergedArr)); + } + + @Test + public void givenNoLibraryAndSortedArrays_whenArr1andArr2_thenMergeAndRemoveDuplicates() { + int[] arr1 = {1, 2, 3, 4, 5, 5, 6, 7, 7, 8}; + int[] arr2 = {8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 17}; + int[] expectedArr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; + + int[] mergedArr = MergeArraysAndRemoveDuplicate.mergeAndRemoveDuplicatesOnSortedArray(arr1, arr2); + + assertArrayEquals(expectedArr, mergedArr); + + logger.info(getCommaDelimited(mergedArr)); + } + + @Test + public void givenSet_whenArr1andArr2_thenMergeAndRemoveDuplicates() { + int[] arr1 = {3, 2, 1, 4, 5, 6, 8, 7, 9}; + int[] arr2 = {8, 9, 10, 11, 12, 13, 15, 14, 15, 14, 16, 17}; + int[] expectedArr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; + + int[] mergedArr = MergeArraysAndRemoveDuplicate.mergeAndRemoveDuplicatesUsingSet(arr1, arr2); + + assertArrayEquals(expectedArr, mergedArr); + + logger.info(getCommaDelimited(mergedArr)); + } + + @Test + public void givenStream_whenArr1andArr2_thenMergeAndRemoveDuplicates() { + int[] arr1 = {3, 2, 1, 4, 5, 6, 8, 7, 9}; + int[] arr2 = {8, 9, 10, 11, 12, 13, 15, 14, 15, 14, 16, 17}; + int[] expectedArr = {3, 2, 1, 4, 5, 6, 8, 7, 9, 10, 11, 12, 13, 15, 14, 16, 17}; + + int[] mergedArr = MergeArraysAndRemoveDuplicate.mergeAndRemoveDuplicatesUsingStream(arr1, arr2); + + assertArrayEquals(expectedArr, mergedArr); + + logger.info(getCommaDelimited(mergedArr)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/README.md b/core-java-modules/core-java-arrays-operations-advanced-2/README.md new file mode 100644 index 0000000000..17ffa2562d --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/pom.xml b/core-java-modules/core-java-arrays-operations-advanced-2/pom.xml new file mode 100644 index 0000000000..a0ae2398a4 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + core-java-arrays-operations-advanced-2 + core-java-arrays-operations-advanced-2 + jar + + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/src/main/java/com/baeldung/arraymiddle/MiddleOfArray.java b/core-java-modules/core-java-arrays-operations-advanced-2/src/main/java/com/baeldung/arraymiddle/MiddleOfArray.java new file mode 100644 index 0000000000..bfff003512 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/src/main/java/com/baeldung/arraymiddle/MiddleOfArray.java @@ -0,0 +1,65 @@ +package com.baeldung.arraymiddle; + +import java.util.Arrays; + +import org.apache.commons.lang3.ObjectUtils; + +public class MiddleOfArray { + int[] middleOfArray(int[] array) { + if (ObjectUtils.isEmpty(array) || array.length < 3) + return array; + int n = array.length; + int mid = n / 2; + if (n % 2 == 0) { + int mid2 = mid - 1; + return new int[] { array[mid2], array[mid] }; + } else { + return new int[] { array[mid] }; + } + } + + int[] middleOfArrayWithStartEndNaive(int[] array, int start, int end) { + int mid = (start + end) / 2; + int n = end - start; + if (n % 2 == 0) { + int mid2 = mid - 1; + return new int[] { array[mid2], array[mid] }; + } else { + return new int[] { array[mid] }; + } + } + + int[] middleOfArrayWithStartEnd(int[] array, int start, int end) { + int mid = start + (end - start) / 2; + int n = end - start; + if (n % 2 == 0) { + int mid2 = mid - 1; + return new int[] { array[mid2], array[mid] }; + } else { + return new int[] { array[mid] }; + } + } + + int[] middleOfArrayWithStartEndBitwise(int[] array, int start, int end) { + int mid = (start + end) >>> 1; + int n = end - start; + if (n % 2 == 0) { + int mid2 = mid - 1; + return new int[] { array[mid2], array[mid] }; + } else { + return new int[] { array[mid] }; + } + } + + int medianOfArray(int[] array, int start, int end) { + Arrays.sort(array); // for safety. This can be ignored + int mid = (start + end) >>> 1; + int n = end - start; + if (n % 2 == 0) { + int mid2 = mid - 1; + return (array[mid2] + array[mid]) / 2; + } else { + return array[mid]; + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/src/test/java/com/baeldung/arraymiddle/MiddleOfArrayUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced-2/src/test/java/com/baeldung/arraymiddle/MiddleOfArrayUnitTest.java new file mode 100644 index 0000000000..64a9796e67 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/src/test/java/com/baeldung/arraymiddle/MiddleOfArrayUnitTest.java @@ -0,0 +1,89 @@ +package com.baeldung.arraymiddle; + +import org.junit.Assert; +import org.junit.Test; + +public class MiddleOfArrayUnitTest { + + @Test + public void givenArrayOfEvenLength_whenMiddleOfArray_thenReturn2Values() { + int[] array = new int[100]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int[] expectedMidArray = { 50, 51 }; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArray(array)); + } + + @Test + public void givenArrayOfEdgeCaseLength_whenMiddleOfArray_thenReturn2Values() { + int[] array = new int[0]; + int[] expectedMidArray = new int[0]; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArray(array)); + + array = new int[] { 1, 2 }; + expectedMidArray = new int[] { 1, 2 }; + + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArray(array)); + } + + @Test + public void givenArrayOfOddLength_whenMiddleOfArray_thenReturnMid() { + int[] array = new int[99]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int[] expectedMidArray = { 50 }; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArray(array)); + } + + @Test + public void givenArrayWithStartAndEnd_whenMiddleOfArray_thenReturnMid() { + int[] array = new int[100]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int[] expectedMidArray = { 58 }; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArrayWithStartEndNaive(array, 55, 60)); + + expectedMidArray = new int[] { 58, 59 }; + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArrayWithStartEndNaive(array, 56, 60)); + } + + @Test + public void givenArrayWithStartAndEndOptimized_whenMiddleOfArray_thenReturnMid() { + int[] array = new int[100]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int[] expectedMidArray = { 78 }; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArrayWithStartEnd(array, 55, 100)); + } + + @Test + public void givenArrayWithStartAndEndBitwise_whenMiddleOfArray_thenReturnMid() { + int[] array = new int[100]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int[] expectedMidArray = { 78 }; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertArrayEquals(expectedMidArray, middleOfArray.middleOfArrayWithStartEndBitwise(array, 55, 100)); + } + + @Test + public void givenArrayWithStartAndEnd_whenMedianOfArray_thenReturnMid() { + int[] array = new int[100]; + for (int i = 0; i < array.length; i++) { + array[i] = i + 1; + } + int expectMedian = 50; + MiddleOfArray middleOfArray = new MiddleOfArray(); + Assert.assertEquals(expectMedian, middleOfArray.medianOfArray(array, 0, 100)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced/README.md b/core-java-modules/core-java-arrays-operations-advanced/README.md index e3465c9fa3..b379958f37 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced/README.md @@ -13,3 +13,4 @@ This module contains articles about advanced operations on arrays in Java. They - [Performance of System.arraycopy() vs. Arrays.copyOf()](https://www.baeldung.com/java-system-arraycopy-arrays-copyof-performance) - [Slicing Arrays in Java](https://www.baeldung.com/java-slicing-arrays) - [Combining Two or More Byte Arrays](https://www.baeldung.com/java-concatenate-byte-arrays) +- [Calculating the Sum of Two Arrays in Java](https://www.baeldung.com/java-sum-arrays-element-wise) diff --git a/core-java-modules/core-java-arrays-operations-advanced/pom.xml b/core-java-modules/core-java-arrays-operations-advanced/pom.xml index cbcd6ae440..52787cc0c9 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/pom.xml +++ b/core-java-modules/core-java-arrays-operations-advanced/pom.xml @@ -57,5 +57,9 @@ + + + 11 + \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java new file mode 100644 index 0000000000..3c2a75a409 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java @@ -0,0 +1,14 @@ +package com.baeldung.arraysums; + +public class SumArraysUsingForEach { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + int[] arr3 = new int[arr1.length]; + int counter = 0; + for (int num1 : arr1) { + arr3[counter] = num1 + arr2[counter]; + counter++; + } + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java new file mode 100644 index 0000000000..32e2e939d4 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java @@ -0,0 +1,12 @@ +package com.baeldung.arraysums; + +public class SumArraysUsingForLoop { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + int[] arr3 = new int[arr1.length]; + for (int i = 0; i < arr1.length; i++) { + arr3[i] = arr1[i] + arr2[i]; + } + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java new file mode 100644 index 0000000000..40bfda4b74 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java @@ -0,0 +1,14 @@ +package com.baeldung.arraysums; + +import java.util.Arrays; +import java.util.stream.IntStream; + +public class SumArraysUsingStreams { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + IntStream range = IntStream.range(0, Math.min(arr1.length, arr2.length)); + IntStream stream3 = range.map(i -> arr1[i] + arr2[i]); + int[] arr3 = stream3.toArray(); + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraycompare/ArraysCompareUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraycompare/ArraysCompareUnitTest.java new file mode 100644 index 0000000000..828560d71c --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraycompare/ArraysCompareUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.arraycompare; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +class ArraysCompareUnitTest { + + @Test + void givenSameContents_whenCompare_thenCorrect() { + String[] array1 = new String[] { "A", "B", "C" }; + String[] array2 = new String[] { "A", "B", "C" }; + + assertThat(Arrays.compare(array1, array2)).isEqualTo(0); + } + + @Test + void givenDifferentContents_whenCompare_thenDifferent() { + String[] array1 = new String[] { "A", "B", "C" }; + String[] array2 = new String[] { "A", "C", "B", "D" }; + + assertThat(Arrays.compare(array1, array2)).isLessThan(0); + assertThat(Arrays.compare(array2, array1)).isGreaterThan(0); + assertThat(Arrays.compare(array1, null)).isGreaterThan(0); + } + +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java new file mode 100644 index 0000000000..883b35b223 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingForEach; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingForEachUnitTest { + + @Test + public void sumOfTwoArraysUsingForEach_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = { 4, 5, 1, 6, 4, 15 }; + int[] arr2 = { 3, 5, 6, 1, 9, 6 }; + int[] expected = { 7, 10, 7, 7, 13, 21 }; + assertArrayEquals(expected, SumArraysUsingForEach.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java new file mode 100644 index 0000000000..7cffd5f4ff --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingForLoop; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingForLoopUnitTest { + + @Test + public void sumOfTwoArrays_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = {4, 5, 1, 6, 4, 15}; + int[] arr2 = {3, 5, 6, 1, 9, 6}; + int[] expected = {7, 10, 7, 7, 13, 21}; + assertArrayEquals(expected, SumArraysUsingForLoop.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java new file mode 100644 index 0000000000..62ea465ab0 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingStreams; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingStreamsUnitTest { + + @Test + public void sumOfTwoArraysUsingStreams_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = {4, 5, 1, 6, 4, 15}; + int[] arr2 = {3, 5, 6, 1, 9, 6}; + int[] expected = {7, 10, 7, 7, 13, 21}; + assertArrayEquals(expected, SumArraysUsingStreams.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-basic-2/README.md b/core-java-modules/core-java-arrays-operations-basic-2/README.md new file mode 100644 index 0000000000..07eb82ec68 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-basic-2/README.md @@ -0,0 +1,6 @@ +## Core Java Arrays - Basic Operations + +This module contains articles about Java array fundamentals. They assume no previous background knowledge on working with arrays. + +### Relevant Articles: +- [Arrays mismatch() Method in Java](https://www.baeldung.com/java-arrays-mismatch) diff --git a/core-java-modules/core-java-arrays-operations-basic-2/pom.xml b/core-java-modules/core-java-arrays-operations-basic-2/pom.xml new file mode 100644 index 0000000000..7257a39462 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-basic-2/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + core-java-arrays-operations-basic-2 + core-java-arrays-operations-basic-2 + jar + + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-basic-2/src/test/java/com/baeldung/array/mismatch/ArrayMismatchUnitTest.java b/core-java-modules/core-java-arrays-operations-basic-2/src/test/java/com/baeldung/array/mismatch/ArrayMismatchUnitTest.java new file mode 100644 index 0000000000..464221efd0 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-basic-2/src/test/java/com/baeldung/array/mismatch/ArrayMismatchUnitTest.java @@ -0,0 +1,269 @@ +package com.baeldung.array.mismatch; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Arrays; +import java.util.Comparator; + +import org.junit.jupiter.api.Test; + +class ArrayMismatchUnitTest { + + @Test + void givenTwoArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() { + int[] firstArray = {1, 2, 3, 4, 5}; + int[] secondArray = {1, 2, 3, 5, 8}; + assertEquals(3, Arrays.mismatch(firstArray, secondArray)); + } + + @Test + void givenTwoIdenticalArrays_whenMismatch_thenMinusOne() { + int[] firstArray = {1, 2, 3, 4, 5}; + int[] secondArray = {1, 2, 3, 4, 5}; + assertEquals(-1, Arrays.mismatch(firstArray, secondArray)); + } + + @Test + void givenFirstArrayIsAPrefixOfTheSecond_whenMismatch_thenFirstArrayLength() { + int[] firstArray = {1, 2, 3, 4, 5}; + int[] secondArray = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + assertEquals(firstArray.length, Arrays.mismatch(firstArray, secondArray)); + } + + @Test + void givenNoCommonPrefix_whenMismatch_thenZero() { + int[] firstArray = {1, 2, 3, 4, 5}; + int[] secondArray = {9, 8, 7}; + assertEquals(0, Arrays.mismatch(firstArray, secondArray)); + } + + @Test + void givenAtLeastANullArray_whenMismatch_thenThrowsNullPointerException() { + int[] firstArray = null; + int[] secondArray = {1, 2, 3, 4, 5}; + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, firstArray)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, firstArray)); + } + + @Test + void givenExactlyOneAnEmptyArray_whenMismatch_thenZero() { + int[] firstArray = {}; + int[] secondArray = {1, 2, 3}; + assertEquals(0, Arrays.mismatch(firstArray, secondArray)); + assertEquals(0, Arrays.mismatch(secondArray, firstArray)); + } + + @Test + void givenTwoEmptyArrays_whenMismatch_thenMinusOne() { + assertEquals(-1, Arrays.mismatch(new int[] {}, new int[] {})); + } + + @Test + void givenTwoSubArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() { + int[] firstArray = {1, 2, 3, 4, 5}; + int[] secondArray = {0, 1, 2, 3, 5, 8}; + assertEquals(3, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 6)); + } + + @Test + void givenTwoIdenticalSubArrays_whenMismatch_thenMinusOne() { + int[] firstArray = {0, 0, 1, 2}; + int[] secondArray = {0, 1, 2, 3, 4}; + assertEquals(-1, Arrays.mismatch(firstArray, 2, 4, secondArray, 1, 3)); + } + + @Test + void givenFirstSubArrayIsAPrefixOfTheSecond_whenMismatch_thenFirstArrayLength() { + int[] firstArray = {2, 3, 4, 5, 4, 3, 2}; + int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + assertEquals(4, Arrays.mismatch(firstArray, 0, 4, secondArray, 2, 9)); + } + + @Test + void givenNoCommonPrefixForSubArrays_whenMismatch_thenZero() { + int[] firstArray = {0, 0, 0, 0, 0}; + int[] secondArray = {9, 8, 7, 6, 5}; + assertEquals(0, Arrays.mismatch(firstArray, 1, 2, secondArray, 1, 2)); + } + + @Test + void givenAtLeastANullSubArray_whenMismatch_thenThrowsNullPointerException() { + int[] firstArray = null; + int[] secondArray = {1, 2, 3, 4, 5}; + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, secondArray, 0, 1)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, firstArray, 0, 1)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, firstArray, 0, 1)); + } + + @Test + void givenExactlyOneEmptySubArray_whenMismatch_thenZero() { + int[] firstArray = {1}; + int[] secondArray = {1, 2, 3}; + assertEquals(0, Arrays.mismatch(firstArray, 0, 0, secondArray, 0, 2)); + assertEquals(0, Arrays.mismatch(firstArray, 0, 1, secondArray, 2, 2)); + } + + @Test + void givenTwoEmptySubArrays_whenMismatch_thenMinusOne() { + int[] firstArray = {1}; + int[] secondArray = {1, 2, 3}; + assertEquals(-1, Arrays.mismatch(firstArray, 0, 0, secondArray, 2, 2)); + } + + @Test + void givenToIndexGreaterThanFromIndex_whenMismatch_thenThrowsIllegalArgumentException() { + int[] firstArray = {2, 3, 4, 5, 4, 3, 2}; + int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 4, 2, secondArray, 0, 6)); + assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 6, 0)); + } + + @Test + void givenIllegalIndexes_whenMismatch_thenThrowsArrayIndexOutOfBoundsException() { + int[] firstArray = {2, 3, 4, 5, 4, 3, 2}; + int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, -1, 2, secondArray, 0, 6)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 0, 8, secondArray, 0, 6)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, -5, 0)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 11, 12)); + } + + @Test + void givenTwoStringArraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() { + String[] firstArray = {"one", "two", "three"}; + String[] secondArray = {"ONE", "TWO", "FOUR"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(2, Arrays.mismatch(firstArray, secondArray, comparator)); + } + + @Test + void givenTwoIdenticalStringArraysForTheComparator_whenMismatch_thenMinusOne() { + String[] firstArray = {"one", "two", "three"}; + String[] secondArray = {"ONE", "TWO", "THREE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(-1, Arrays.mismatch(firstArray, secondArray, comparator)); + } + + @Test + void givenFirstStringArrayIsAPrefixOfTheSecondForTheComparator_whenMismatch_thenFirstArrayLength() { + String[] firstArray = {"one", "two", "three"}; + String[] secondArray = {"ONE", "TWO", "THREE", "FOUR", "FIVE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(firstArray.length, Arrays.mismatch(firstArray, secondArray, comparator)); + } + + @Test + void givenNoCommonPrefixForTheComparator_whenMismatch_thenZero() { + String[] firstArray = {"one", "two", "three"}; + String[] secondArray = {"six", "seven", "eight"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(0, Arrays.mismatch(firstArray, secondArray, comparator)); + } + + @Test + void givenAtLeastANullArrayOrNullComparator_whenMismatch_thenThrowsNullPointerException() { + String[] firstArray = null; + String[] secondArray = {"one"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray, comparator)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, firstArray, comparator)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, secondArray, null)); + } + + @Test + void givenExactlyOneAnEmptyArrayAndAComparator_whenMismatch_thenZero() { + String[] firstArray = {}; + String[] secondArray = {"one"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(0, Arrays.mismatch(firstArray, secondArray, comparator)); + assertEquals(0, Arrays.mismatch(secondArray, firstArray, comparator)); + } + + @Test + void givenTwoEmptyStringArraysForTheComparator_whenMismatch_thenMinusOne() { + assertEquals(-1, Arrays.mismatch(new String[] {}, new String[] {}, String.CASE_INSENSITIVE_ORDER)); + } + + @Test + void givenTwoStringSubarraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() { + String[] firstArray = {"one", "two", "three", "four"}; + String[] secondArray = {"ZERO", "ONE", "TWO", "FOUR", "EIGHT", "SIXTEEN"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(2, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 3, comparator)); + } + + @Test + void givenTwoIdenticalStringSubArraysForTheComparator_whenMismatch_thenMinusOne() { + String[] firstArray = {"zero", "zero", "one", "two"}; + String[] secondArray = {"zero", "one", "two", "three", "four"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(-1, Arrays.mismatch(firstArray, 2, 4, secondArray, 1, 3, comparator)); + } + + @Test + void givenFirstSubArrayIsAPrefixOfTheSecondForTheComparator_whenMismatch_thenFirstArrayLength() { + String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"}; + String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(4, Arrays.mismatch(firstArray, 0, 4, secondArray, 2, 9, comparator)); + } + + @Test + void givenNoCommonPrefixForSubArraysForTheComparator_whenMismatch_thenZero() { + String[] firstArray = {"zero", "one"}; + String[] secondArray = {"TEN", "ELEVEN", "TWELVE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(0, Arrays.mismatch(firstArray, 1, 2, secondArray, 1, 2, comparator)); + } + + @Test + void givenAtLeastANullSubArrayOrNullComparator_whenMismatch_thenThrowsNullPointerException() { + String[] firstArray = null; + String[] secondArray = {"ONE", "TWO", "THREE", "FOUR", "FIVE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, secondArray, 0, 1, comparator)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, firstArray, 0, 1, comparator)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, firstArray, 0, 1, comparator)); + assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, secondArray, 0, 1, null)); + } + + @Test + void givenExactlyOneEmptySubArrayAndAComparator_whenMismatch_thenZero() { + String[] firstArray = {"one"}; + String[] secondArray = {"ONE", "TWO", "THREE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(0, Arrays.mismatch(firstArray, 0, 0, secondArray, 0, 2, comparator)); + assertEquals(0, Arrays.mismatch(firstArray, 0, 1, secondArray, 2, 2, comparator)); + } + + @Test + void givenTwoEmptySubArraysAndAComparator_whenMismatch_thenMinusOne() { + String[] firstArray = {"one"}; + String[] secondArray = {"ONE", "TWO", "THREE"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertEquals(-1, Arrays.mismatch(firstArray, 0, 0, secondArray, 2, 2, comparator)); + } + + @Test + void givenToIndexGreaterThanFromIndexAndAComparator_whenMismatch_thenThrowsIllegalArgumentException() { + String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"}; + String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 4, 2, secondArray, 0, 6, comparator)); + assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 6, 0, comparator)); + } + + @Test + void givenIllegalIndexesAndAComparator_whenMismatch_thenThrowsArrayIndexOutOfBoundsException() { + String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"}; + String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"}; + Comparator comparator = String.CASE_INSENSITIVE_ORDER; + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, -1, 2, secondArray, 0, 6, comparator)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 0, 8, secondArray, 0, 6, comparator)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, -5, 0, comparator)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 11, 12, comparator)); + } + +} diff --git a/core-java-modules/core-java-char/README.md b/core-java-modules/core-java-char/README.md index e4af3121c5..56040a3ea5 100644 --- a/core-java-modules/core-java-char/README.md +++ b/core-java-modules/core-java-char/README.md @@ -5,3 +5,4 @@ This module contains articles about Java Character Class ### Relevant Articles: - [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic) - [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string) +- [Increment Character in Java](https://www.baeldung.com/java-char-sequence) diff --git a/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java b/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java new file mode 100644 index 0000000000..7621e85762 --- /dev/null +++ b/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.incrementchar; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +class IncrementCharUnitTest { + @Test + void whenUsingForLoop_thenGenerateCharacters(){ + final List allCapitalCharacters = Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); + List characters = new ArrayList<>(); + for (char character = 'A'; character <= 'Z'; character++) { + characters.add(character); + } + Assertions.assertEquals(characters, allCapitalCharacters); + } + + @Test + void whenUsingStreams_thenGenerateCharacters() { + final List allCapitalCharacters = Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); + final List characters = IntStream.rangeClosed('A', 'Z').mapToObj(c -> (char) c).collect(Collectors.toList()); + Assertions.assertEquals(characters, allCapitalCharacters); + } +} diff --git a/core-java-modules/core-java-collections-5/README.md b/core-java-modules/core-java-collections-5/README.md index 1769d11686..1939e5ca3f 100644 --- a/core-java-modules/core-java-collections-5/README.md +++ b/core-java-modules/core-java-collections-5/README.md @@ -5,4 +5,7 @@ ### Relevant Articles: - [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro) - [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator) +- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods) +- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration) +- [Remove Elements From a Queue Using Loop](https://www.baeldung.com/java-remove-elements-queue) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java new file mode 100644 index 0000000000..cd754489a6 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java @@ -0,0 +1,26 @@ +package com.baeldung.collectionsvsarrays; + +import com.baeldung.collectionsvsarrays.sorting.Quicksort; +import java.util.Comparator; +import java.util.List; + +public class NonStableSortExample { + + + + public static void main(String[] args) { + List tasks = Tasks.supplier.get(); + Quicksort.sort(tasks, Comparator.comparingInt(Task::getPriority)); + System.out.println("After sorting by priority:"); + for (Task task : tasks) { + System.out.println(task); + } + Quicksort.sort(tasks, Comparator.comparing(Task::getDueDate)); + System.out.println("\nAfter sorting by due date:"); + for (Task task : tasks) { + System.out.println(task); + } + } + + +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java new file mode 100644 index 0000000000..9a8adff507 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java @@ -0,0 +1,56 @@ +package com.baeldung.collectionsvsarrays; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.MINUTES) +@Warmup(iterations = 5, time = 10) +@Fork(value = 2) +public class ObjectOverheadBenchmark { + + private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current(); + + @State(Scope.Benchmark) + public static class Input { + public Supplier> randomNumbers = () -> RANDOM.ints().limit(10000).boxed().collect(Collectors.toList()); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingPrimitiveArray(Input input, Blackhole blackhole) { + final int[] array = input.randomNumbers.get().stream().mapToInt(Integer::intValue).toArray(); + Arrays.sort(array); + final List result = Arrays.stream(array).boxed().collect(Collectors.toList()); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingObjectArray(Input input, Blackhole blackhole) { + final Integer[] array = input.randomNumbers.get().toArray(new Integer[0]); + Arrays.sort(array); + blackhole.consume(array); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingObjects(Input input, Blackhole blackhole) { + final List list = input.randomNumbers.get(); + Collections.sort(list); + blackhole.consume(list); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java new file mode 100644 index 0000000000..6e645b0fb9 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java @@ -0,0 +1,51 @@ +package com.baeldung.collectionsvsarrays; + +import com.baeldung.collectionsvsarrays.sorting.MergeSort; +import com.baeldung.collectionsvsarrays.sorting.Quicksort; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; + +@Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.MINUTES) +@Warmup(iterations = 5, time = 10) +public class PerformanceBenchmark { + + private static final Random RANDOM = new Random(); + private static final int ARRAY_SIZE = 10000; + private static final int[] randomNumbers = RANDOM.ints(ARRAY_SIZE).toArray(); + private static final int[] sameNumbers = IntStream.generate(() -> 42).limit(ARRAY_SIZE).toArray(); + public static final Supplier randomNumbersSupplier = randomNumbers::clone; + public static final Supplier sameNumbersSupplier = sameNumbers::clone; + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-quick-sort-same-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void quickSortSameNumber() { + Quicksort.sort(sameNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-quick-sort-random-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void quickSortRandomNumber() { + Quicksort.sort(randomNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-merge-sort-same-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void mergeSortSameNumber() { + MergeSort.sort(sameNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-merge-sort-random-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void mergeSortRandomNumber() { + MergeSort.sort(randomNumbersSupplier.get()); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java new file mode 100644 index 0000000000..336673bac8 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java @@ -0,0 +1,23 @@ +package com.baeldung.collectionsvsarrays; + + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class StableSortExample { + + public static void main(String[] args) { + final List tasks = Tasks.supplier.get(); + Collections.sort(tasks, Comparator.comparingInt(Task::getPriority)); + System.out.println("After sorting by priority:"); + for (Task task : tasks) { + System.out.println(task); + } + Collections.sort(tasks, Comparator.comparing(Task::getDueDate)); + System.out.println("\nAfter sorting by due date:"); + for (Task task : tasks) { + System.out.println(task); + } + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java new file mode 100644 index 0000000000..133c39ccd2 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java @@ -0,0 +1,30 @@ +package com.baeldung.collectionsvsarrays; + +public class Task { + private final long id; + private final int priority; + private final String dueDate; + + public Task(final long id, int priority, String dueDate) { + this.id = id; + this.priority = priority; + this.dueDate = dueDate; + } + + @Override + public String toString() { + return String.format("Task: #%-2d | Priority: %d | Due Date: %s", getId(), getPriority(), getDueDate()); + } + + public int getPriority() { + return priority; + } + + public String getDueDate() { + return dueDate; + } + + private long getId() { + return id; + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java new file mode 100644 index 0000000000..fc413f549f --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java @@ -0,0 +1,30 @@ +package com.baeldung.collectionsvsarrays; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class Tasks { + + private static final List tasks; + public static final Supplier> supplier; + + static { + tasks = new ArrayList<>(); + tasks.add(new Task(1, 1, "2023-09-01")); + tasks.add(new Task(2, 2, "2023-08-30")); + tasks.add(new Task(3, 1, "2023-08-29")); + tasks.add(new Task(4, 2, "2023-09-02")); + tasks.add(new Task(5, 3, "2023-09-05")); + tasks.add(new Task(6, 1, "2023-09-03")); + tasks.add(new Task(7, 3, "2023-08-28")); + tasks.add(new Task(8, 2, "2023-09-01")); + tasks.add(new Task(9, 1, "2023-08-28")); + tasks.add(new Task(10, 2, "2023-09-04")); + tasks.add(new Task(11, 3, "2023-08-31")); + tasks.add(new Task(12, 1, "2023-08-30")); + tasks.add(new Task(13, 3, "2023-09-02")); + + supplier = () -> new ArrayList<>(tasks); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java new file mode 100644 index 0000000000..6078db50e0 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java @@ -0,0 +1,47 @@ +package com.baeldung.collectionsvsarrays.sorting; + +public class MergeSort { + + public static void sort(int[] a) { + sort(a, a.length); + } + public static void sort(int[] a, int n) { + if (n < 2) { + return; + } + int mid = n / 2; + int[] l = new int[mid]; + int[] r = new int[n - mid]; + + for (int i = 0; i < mid; i++) { + l[i] = a[i]; + } + for (int i = mid; i < n; i++) { + r[i - mid] = a[i]; + } + sort(l, mid); + sort(r, n - mid); + + merge(a, l, r, mid, n - mid); + } + private static void merge( + int[] a, int[] l, int[] r, int left, int right) { + + int i = 0, j = 0, k = 0; + while (i < left && j < right) { + if (l[i] <= r[j]) { + a[k++] = l[i++]; + } + else { + a[k++] = r[j++]; + } + } + while (i < left) { + a[k++] = l[i++]; + } + while (j < right) { + a[k++] = r[j++]; + } + } + +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java new file mode 100644 index 0000000000..eab47b901b --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java @@ -0,0 +1,72 @@ +package com.baeldung.collectionsvsarrays.sorting; + +import java.util.Comparator; +import java.util.List; + +public class Quicksort { + + public static void sort(int arr[]) { + sort(arr, 0, arr.length - 1); + } + public static void sort(int arr[], int begin, int end) { + if (begin < end) { + int partitionIndex = partition(arr, begin, end); + + sort(arr, begin, partitionIndex-1); + sort(arr, partitionIndex+1, end); + } + } + private static int partition(int arr[], int begin, int end) { + int pivot = arr[end]; + int i = (begin-1); + + for (int j = begin; j < end; j++) { + if (arr[j] <= pivot) { + i++; + + int swapTemp = arr[i]; + arr[i] = arr[j]; + arr[j] = swapTemp; + } + } + + int swapTemp = arr[i+1]; + arr[i+1] = arr[end]; + arr[end] = swapTemp; + + return i+1; + } + + public static void sort(List list, Comparator comparator) { + sort(list, 0, list.size() - 1, comparator); + } + public static void sort(List list, int low, int high, Comparator comparator) { + if (low < high) { + int partitionIndex = partition(list, low, high, comparator); + + sort(list, low, partitionIndex - 1, comparator); + sort(list, partitionIndex + 1, high, comparator); + } + } + + private static int partition(List list, int begin, int end, Comparator comparator) { + T pivot = list.get(end); + int i = (begin-1); + + for (int j = begin; j < end; j++) { + if (comparator.compare(list.get(j), pivot) <= 0) { + i++; + + T swapTemp = list.get(i); + list.set(i, list.get(j)); + list.set(j, swapTemp); + } + } + + T swapTemp = list.get(i+1); + list.set(i+1,list.get(end)); + list.set(end, swapTemp); + + return i+1; + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java new file mode 100644 index 0000000000..86982486fa --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java @@ -0,0 +1,126 @@ +package com.baeldung.skippingfirstelement; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class SkipFirstElementExample { + + private final List stringList = new ArrayList<>(); + private final Set stringSet = new HashSet<>(); + private final Map stringMap = new HashMap<>(); + + public SkipFirstElementExample() { + // Initializing a List + stringList.add("Monday"); + stringList.add("Tuesday"); + stringList.add("Wednesday"); + stringList.add("Thursday"); + stringList.add("Friday"); + stringList.add("Saturday"); + stringList.add("Sunday"); + // Initializing a Set + stringSet.add("Monday"); + stringSet.add("Tuesday"); + stringSet.add("Wednesday"); + stringSet.add("Thursday"); + stringSet.add("Friday"); + stringSet.add("Saturday"); + stringSet.add("Sunday"); + // Initializing a Map + stringMap.put("Monday", "The day when coffee is a life support system."); + stringMap.put("Tuesday", "The day you realize that Monday's optimism was a lie."); + stringMap.put("Wednesday", "Hump Day, or as it's known, the 'Is it Friday yet?' day."); + stringMap.put("Thursday", "The day that says, 'Hold my beer, Friday is coming!'"); + stringMap.put("Friday", "The golden child of the weekdays. The superhero of the workweek."); + stringMap.put("Saturday", "The day of rest? More like the day of 'What can I binge-watch next?'"); + stringMap.put("Sunday", "The day before you have to adult again."); + } + + void skippingFirstElementInListWithForLoop(List stringList) { + for (int i = 1; i < stringList.size(); i++) { + process(stringList.get(i)); + } + } + + void skippingFirstElementInListWithWhileLoop(List stringList) { + final Iterator iterator = stringList.iterator(); + if (iterator.hasNext()) { + iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + } + } + + void skippingFirstElementInSetWithWhileLoop(Set stringSet) { + final Iterator iterator = stringSet.iterator(); + if (iterator.hasNext()) { + iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + } + } + + void skippingFirstElementInListWithWhileLoopStoringFirstElement(List stringList) { + final Iterator iterator = stringList.iterator(); + String firstElement = null; + if (iterator.hasNext()) { + firstElement = iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + // additional logic using fistElement + } + } + + void skippingFirstElementInMapWithStreamSkip(Map stringMap) { + stringMap.entrySet().stream().skip(1).forEach(this::process); + } + + void skippingFirstElementInListWithSubList(List stringList) { + for (final String element : stringList.subList(1, stringList.size())) { + process(element); + } + } + + void skippingFirstElementInListWithForLoopWithAdditionalCheck(List stringList) { + for (int i = 0; i < stringList.size(); i++) { + if (i == 0) { + // do something else + } else { + process(stringList.get(i)); + } + } + } + + void skippingFirstElementInListWithWhileLoopWithCounter(List stringList) { + int counter = 0; + while (counter < stringList.size()) { + if (counter != 0) { + process(stringList.get(counter)); + } + ++counter; + } + } + + void skippingFirstElementInListWithReduce(List stringList) { + stringList.stream().reduce((skip, element) -> { + process(element); + return element; + }); + } + + protected void process(String string) { + System.out.println(string); + } + protected void process(Entry mapEntry) { + System.out.println(mapEntry); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/removequeueelements/RemoveQueueElementsUnitTest.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/removequeueelements/RemoveQueueElementsUnitTest.java new file mode 100644 index 0000000000..38fdc58099 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/removequeueelements/RemoveQueueElementsUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.removequeueelements; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RemoveQueueElementsUnitTest { + @Test + public void givenQueueWithEvenAndOddNumbers_whenRemovingEvenNumbers_thenOddNumbersRemain() { + Queue queue = new LinkedList<>(); + Queue oddElementsQueue = new LinkedList<>(); + queue.add(1); + queue.add(2); + queue.add(3); + queue.add(4); + queue.add(5); + + while (queue.peek() != null) { + int element = queue.remove(); + if (element % 2 != 0) { + oddElementsQueue.add(element); + } + } + + assertEquals(3, oddElementsQueue.size()); + assertTrue(oddElementsQueue.contains(1)); + assertTrue(oddElementsQueue.contains(3)); + assertTrue(oddElementsQueue.contains(5)); + } + + @Test + public void givenStringQueue_whenRemovingStringsThatStartWithA_thenStringElementsRemain() { + Queue queue = new LinkedList<>(); + Queue stringElementsQueue = new LinkedList<>(); + queue.add("Apple"); + queue.add("Banana"); + queue.add("Orange"); + queue.add("Grape"); + queue.add("Mango"); + + + while (queue.peek() != null) { + String element = queue.remove(); + if (!element.startsWith("A")) { + stringElementsQueue.add(element); + } + } + + assertEquals(4, stringElementsQueue.size()); + assertTrue(stringElementsQueue.contains("Banana")); + assertTrue(stringElementsQueue.contains("Orange")); + assertTrue(stringElementsQueue.contains("Grape")); + assertTrue(stringElementsQueue.contains("Mango")); + } + +} diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java new file mode 100644 index 0000000000..9821b22ac7 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java @@ -0,0 +1,122 @@ +package com.baeldung.skippingfirstelement; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@EnabledForJreRange(min = JRE.JAVA_9) +class SkipFirstElementExampleUnitTest { + + private static TestableSkipFirstElement testableSkip = new TestableSkipFirstElement(); + + @BeforeEach + void setup() { + testableSkip.reset(); + } + + private static Stream listProvider() { + return Stream.of( + Arguments.of( + List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + List.of("Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")) + ); + } + + private static Stream mapProvider() { + return Stream.of( + Arguments.of( + Map.of( + "Monday", "The day when coffee is a life support system.", + "Tuesday", "The day you realize that Monday's optimism was a lie.", + "Wednesday", "Hump Day, or as it's known, the 'Is it Friday yet?' day.", + "Thursday", "The day that says, 'Hold my beer, Friday is coming!'", + "Friday", "The golden child of the weekdays. The superhero of the workweek.", + "Saturday", "The day of rest? More like the day of 'What can I binge-watch next?'", + "Sunday", "The day before you have to adult again." + ) + ) + ); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithForLoop(List input, List expected) { + testableSkip.skippingFirstElementInListWithForLoop(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoop(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoop(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInSetWithWhileLoop(List input) { + testableSkip.skippingFirstElementInSetWithWhileLoop(new HashSet<>(input)); + Set actual = new HashSet<>(testableSkip.getResult()); + assertEquals(actual.size(), input.size() - 1); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoopStoringFirstElement(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoopStoringFirstElement(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("mapProvider") + void skippingFirstElementInMapWithStreamSkip(Map input) { + testableSkip.skippingFirstElementInMapWithStreamSkip(input); + List actual = testableSkip.getResult(); + assertEquals(actual.size(), input.size() - 1); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithSubList(List input, List expected) { + testableSkip.skippingFirstElementInListWithSubList(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithForLoopWithAdditionalCheck(List input, List expected) { + testableSkip.skippingFirstElementInListWithForLoopWithAdditionalCheck(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoopWithCounter(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoopWithCounter(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithReduce(List input, List expected) { + testableSkip.skippingFirstElementInListWithReduce(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java new file mode 100644 index 0000000000..0e2f340485 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java @@ -0,0 +1,10 @@ +package com.baeldung.skippingfirstelement; + +import java.util.List; + +public interface TestableSkip { + + void reset(); + + List getResult(); +} diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java new file mode 100644 index 0000000000..99facb73ad --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java @@ -0,0 +1,37 @@ +package com.baeldung.skippingfirstelement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +public class TestableSkipFirstElement extends SkipFirstElementExample implements TestableSkip { + + + private List processedList = new ArrayList<>(); + private List> processedEntryList = new ArrayList<>(); + + @Override + public void process(String string) { + processedList.add(string); + } + + @Override + public void process(Entry stringEntry) { + processedEntryList.add(stringEntry); + } + + @Override + public void reset() { + processedList.clear(); + processedEntryList.clear(); + } + + @Override + public List getResult() { + if (!processedList.isEmpty()) + return processedList; + return processedEntryList; + } + + +} diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md new file mode 100644 index 0000000000..575e0dbb07 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -0,0 +1,6 @@ +## Core Java Collections ArrayList + +This module contains articles about the Java ArrayList collection + +### Relevant Articles: +- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/java-arraylist-multiple-object-types) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml new file mode 100644 index 0000000000..901a4f5c75 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + core-java-collections-array-list-2 + core-java-collections-array-list-2 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + + + + 17 + 17 + + diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java new file mode 100644 index 0000000000..5315147dff --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java @@ -0,0 +1,51 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Predicate; + +public class AlternativeMultipeTypeList { + + public static void main(String[] args) { + // List of Parent Class + ArrayList myList = new ArrayList<>(); + myList.add(1.2); + myList.add(2); + myList.add(-3.5); + + // List of Interface type + ArrayList diffMapList = new ArrayList<>(); + diffMapList.add(new HashMap<>()); + diffMapList.add(new TreeMap<>()); + diffMapList.add(new LinkedHashMap<>()); + + // List of Custom Object + ArrayList objList = new ArrayList<>(); + objList.add(new CustomObject("String")); + objList.add(new CustomObject(2)); + + // List via Functional Interface + List dataList = new ArrayList<>(); + + Predicate myPredicate = inputData -> (inputData instanceof String || inputData instanceof Integer); + + UserFunctionalInterface myInterface = (listObj, data) -> { + if (myPredicate.test(data)) + listObj.add(data); + else + System.out.println("Skipping input as data not allowed for class: " + data.getClass() + .getSimpleName()); + return listObj; + }; + + myInterface.addToList(dataList, Integer.valueOf(2)); + myInterface.addToList(dataList, Double.valueOf(3.33)); + myInterface.addToList(dataList, "String Value"); + myInterface.printList(dataList); + } + +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java new file mode 100644 index 0000000000..b3ac4ffddb --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java @@ -0,0 +1,22 @@ +package com.baeldung.list.multipleobjecttypes; + +public class CustomObject { + String classData; + Integer intData; + + CustomObject(String classData) { + this.classData = classData; + } + + CustomObject(Integer intData) { + this.intData = intData; + } + + public String getClassData() { + return this.classData; + } + + public Integer getIntData() { + return this.intData; + } +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java new file mode 100644 index 0000000000..c5740c5cf8 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java @@ -0,0 +1,40 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.math.BigInteger; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MultipleObjectTypeArrayList { + + public static void main(String[] args) { + + ArrayList multiTypeList = new ArrayList<>(); + + multiTypeList.add(Integer.valueOf(10)); + multiTypeList.add(Double.valueOf(11.5)); + multiTypeList.add("String Data"); + multiTypeList.add(Arrays.asList(1, 2, 3)); + multiTypeList.add(new CustomObject("Class Data")); + multiTypeList.add(BigInteger.valueOf(123456789)); + multiTypeList.add(LocalDate.of(2023, 9, 19)); + + for (Object dataObj : multiTypeList) { + if (dataObj instanceof Integer intData) + System.out.println("Integer Data : " + intData); + else if (dataObj instanceof Double doubleData) + System.out.println("Double Data : " + doubleData); + else if (dataObj instanceof String stringData) + System.out.println("String Data : " + stringData); + else if (dataObj instanceof List intList) + System.out.println("List Data : " + intList); + else if (dataObj instanceof CustomObject customObj) + System.out.println("CustomObject Data : " + customObj.getClassData()); + else if (dataObj instanceof BigInteger bigIntData) + System.out.println("BigInteger Data : " + bigIntData); + else if (dataObj instanceof LocalDate localDate) + System.out.println("LocalDate Data : " + localDate.toString()); + } + } +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java new file mode 100644 index 0000000000..6c0f8451da --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java @@ -0,0 +1,18 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.util.List; + +@FunctionalInterface +public interface UserFunctionalInterface { + + List addToList(List list, Object data); + + default void printList(List dataList) { + for (Object data : dataList) { + if (data instanceof String stringData) + System.out.println("String Data: " + stringData); + if (data instanceof Integer intData) + System.out.println("Integer Data: " + intData); + } + } +} diff --git a/core-java-modules/core-java-collections-conversions-2/README.md b/core-java-modules/core-java-collections-conversions-2/README.md index fe17af0a7a..e8d008104c 100644 --- a/core-java-modules/core-java-collections-conversions-2/README.md +++ b/core-java-modules/core-java-collections-conversions-2/README.md @@ -12,4 +12,6 @@ This module contains articles about conversions among Collection types and array - [Convert a List of Integers to a List of Strings](https://www.baeldung.com/java-convert-list-integers-to-list-strings) - [Combining Two Lists Into a Map in Java](https://www.baeldung.com/java-combine-two-lists-into-map) - [Convert a List of Strings to a List of Integers](https://www.baeldung.com/java-convert-list-strings-to-integers) +- [Convert List to Long[] Array in Java](https://www.baeldung.com/java-convert-list-object-to-long-array) +- [Get the First n Elements of a List Into an Array](https://www.baeldung.com/java-take-start-elements-list-array) - More articles: [[<-- prev]](../core-java-collections-conversions) diff --git a/core-java-modules/core-java-collections-conversions-2/pom.xml b/core-java-modules/core-java-collections-conversions-2/pom.xml index 8cd0a6932b..7b7533fc39 100644 --- a/core-java-modules/core-java-collections-conversions-2/pom.xml +++ b/core-java-modules/core-java-collections-conversions-2/pom.xml @@ -43,6 +43,7 @@ 0.10.3 + 11 + 3.1.1 - \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java new file mode 100644 index 0000000000..63cdf22f3a --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.arrayconversion; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ArrayListToArrayUnitTest { + private static final List INPUT_LIST = Lists.newArrayList("Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply"); + private static final String[] EXPECTED_ARRAY = new String[] { "Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply" }; + + @Test + void whenUsingForLoop_thenGetExpectedResult() { + String[] result = new String[INPUT_LIST.size()]; + for (int i = 0; i < INPUT_LIST.size(); i++) { + result[i] = INPUT_LIST.get(i); + } + assertArrayEquals(EXPECTED_ARRAY, result); + } + + @Test + void whenUsingListToArray_thenGetExpectedResult() { + String[] result = new String[INPUT_LIST.size()]; + INPUT_LIST.toArray(result); + assertArrayEquals(EXPECTED_ARRAY, result); + + String[] result2 = INPUT_LIST.toArray(new String[0]); + assertArrayEquals(EXPECTED_ARRAY, result2); + } + + @Test + void whenUsingStreamApi_thenGetExpectedResult() { + String[] result = INPUT_LIST.stream() + .toArray(String[]::new); + assertArrayEquals(EXPECTED_ARRAY, result); + } + + @Test + void whenUsingListToArrayInJava11_thenGetExpectedResult() { + String[] result = INPUT_LIST.toArray(String[]::new); + assertArrayEquals(EXPECTED_ARRAY, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java new file mode 100644 index 0000000000..c9818613fe --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.arrayconversion; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.Iterator; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ListToArrayFirstNElementsUnitTest { + private static final List INPUT_LIST = Lists.newArrayList("one", "two", "three", "four", "five", "six", "seven"); + private static final int n = 5; + + @Test + void whenUsingForLoop_thenGetExpectedArray() { + String[] result = new String[n]; + for (int i = 0; i < n; i++) { + result[i] = INPUT_LIST.get(i); + } + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + + String[] result2 = new String[n]; + Iterator iterator = INPUT_LIST.iterator(); + for (int i = 0; i < n && iterator.hasNext(); i++) { + result2[i] = iterator.next(); + } + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2); + } + + @Test + void whenUsingSubList_thenGetExpectedArray() { + String[] result = new String[n]; + INPUT_LIST.subList(0, n) + .toArray(result); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + + String[] result2 = INPUT_LIST.subList(0, n) + .toArray(new String[0]); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2); + + // available only for java 11+ + String[] result3 = INPUT_LIST.subList(0, n) + .toArray(String[]::new); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result3); + } + + @Test + void whenUsingStream_thenGetExpectedArray() { + String[] result = INPUT_LIST.stream() + .limit(n) + .toArray(String[]::new); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-3/README.md b/core-java-modules/core-java-collections-conversions-3/README.md new file mode 100644 index 0000000000..959e4e8160 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-3/README.md @@ -0,0 +1,7 @@ +## Java Collections Cookbooks and Examples + +This module contains articles about conversions among Collection types in Java. + +### Relevant Articles: +- [Converting HashMap Values to an ArrayList in Java](https://www.baeldung.com/java-hashmap-arraylist) +- [Joining a List in Java With Commas and “and”](https://www.baeldung.com/java-string-concatenation-natural-language) diff --git a/core-java-modules/core-java-collections-conversions-3/pom.xml b/core-java-modules/core-java-collections-conversions-3/pom.xml new file mode 100644 index 0000000000..4813d33713 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-3/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + core-java-collections-conversions-3 + core-java-collections-conversions-3 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + core-java-collections-conversions-3 + + + src/main/resources + true + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-3/src/main/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtils.java b/core-java-modules/core-java-collections-conversions-3/src/main/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtils.java new file mode 100644 index 0000000000..dd5cc1fe47 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-3/src/main/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtils.java @@ -0,0 +1,66 @@ +package com.baeldung.hashmaptoarraylist; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Maps.EntryTransformer; + +public class HashMapToArrayListConverterUtils { + + static ArrayList convertUsingConstructor(HashMap hashMap) { + if (hashMap == null) { + return null; + } + return new ArrayList(hashMap.values()); + } + + static ArrayList convertUsingAddAllMethod(HashMap hashMap) { + if (hashMap == null) { + return null; + } + + ArrayList arrayList = new ArrayList(hashMap.size()); + arrayList.addAll(hashMap.values()); + + return arrayList; + } + + static ArrayList convertUsingStreamApi(HashMap hashMap) { + if (hashMap == null) { + return null; + } + + return hashMap.values() + .stream() + .collect(Collectors.toCollection(ArrayList::new)); + } + + static ArrayList convertUsingForLoop(HashMap hashMap) { + if (hashMap == null) { + return null; + } + + ArrayList arrayList = new ArrayList(hashMap.size()); + for (Map.Entry entry : hashMap.entrySet()) { + arrayList.add(entry.getValue()); + } + + return arrayList; + } + + static public ArrayList convertUsingGuava(HashMap hashMap) { + if (hashMap == null) { + return null; + } + + EntryTransformer entryMapTransformer = (key, value) -> value; + + return Lists.newArrayList(Maps.transformEntries(hashMap, entryMapTransformer) + .values()); + } + +} diff --git a/core-java-modules/core-java-collections-conversions-3/src/test/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtilsUnitTest.java b/core-java-modules/core-java-collections-conversions-3/src/test/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtilsUnitTest.java new file mode 100644 index 0000000000..26a42e77c0 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-3/src/test/java/com/baeldung/hashmaptoarraylist/HashMapToArrayListConverterUtilsUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.hashmaptoarraylist; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.junit.Before; +import org.junit.Test; + +public class HashMapToArrayListConverterUtilsUnitTest { + + private HashMap hashMap; + + @Before + public void beforeEach() { + hashMap = new HashMap<>(); + hashMap.put(1, "AAA"); + hashMap.put(2, "BBB"); + hashMap.put(3, "CCC"); + hashMap.put(4, "DDD"); + } + + @Test + public void givenAHashMap_whenConvertUsingConstructor_thenReturnArrayList() { + ArrayList myList = HashMapToArrayListConverterUtils.convertUsingConstructor(hashMap); + + assertThat(hashMap.values(), containsInAnyOrder(myList.toArray())); + } + + @Test + public void givenAHashMap_whenConvertUsingAddAllMethod_thenReturnArrayList() { + ArrayList myList = HashMapToArrayListConverterUtils.convertUsingAddAllMethod(hashMap); + + assertThat(hashMap.values(), containsInAnyOrder(myList.toArray())); + } + + @Test + public void givenAHashMap_whenConvertUsingForLoop_thenReturnArrayList() { + ArrayList myList = HashMapToArrayListConverterUtils.convertUsingForLoop(hashMap); + + assertThat(hashMap.values(), containsInAnyOrder(myList.toArray())); + } + + @Test + public void givenAHashMap_whenConvertUsingStreamApi_thenReturnArrayList() { + ArrayList myList = HashMapToArrayListConverterUtils.convertUsingStreamApi(hashMap); + + assertThat(hashMap.values(), containsInAnyOrder(myList.toArray())); + } + + @Test + public void givenAHashMap_whenConvertUsingGuava_thenReturnArrayList() { + ArrayList myList = HashMapToArrayListConverterUtils.convertUsingGuava(hashMap); + + assertThat(hashMap.values(), containsInAnyOrder(myList.toArray())); + } + +} diff --git a/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/listoflists/ListOfListsUnitTest.java b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/listoflists/ListOfListsUnitTest.java index 321fa475f6..f75ca453ea 100644 --- a/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/listoflists/ListOfListsUnitTest.java +++ b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/listoflists/ListOfListsUnitTest.java @@ -71,4 +71,15 @@ public class ListOfListsUnitTest { assertThat(listOfLists.get(2)).containsExactly("Slack", "Zoom", "Microsoft Teams", "Telegram"); printListOfLists(listOfLists); } -} + + @Test + void givenListOfLists_whenGettingSizeOfSubListsAndSizeOfElements_thenGetExpectedResults() throws URISyntaxException, IOException { + List> listOfLists = getListOfListsFromCsv(); + // size of inner lists + assertThat(listOfLists).hasSize(3); + + // size of all elements in subLists + int totalElements = listOfLists.stream().mapToInt(List::size).sum(); + assertThat(totalElements).isEqualTo(12); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-5/README.md b/core-java-modules/core-java-collections-list-5/README.md index d734cf7364..42f878ad70 100644 --- a/core-java-modules/core-java-collections-list-5/README.md +++ b/core-java-modules/core-java-collections-list-5/README.md @@ -12,3 +12,4 @@ This module contains articles about the Java List collection - [Get Unique Values From an ArrayList in Java](https://www.baeldung.com/java-unique-values-arraylist) - [Converting a Java List to a Json Array](https://www.baeldung.com/java-converting-list-to-json-array) - [What’s the Difference Between Iterator and ListIterator?](https://www.baeldung.com/java-iterator-vs-listiterator) +- [Create List of Object From Another Type Using Java 8](https://www.baeldung.com/java-generate-list-different-type) diff --git a/core-java-modules/core-java-collections-list-5/pom.xml b/core-java-modules/core-java-collections-list-5/pom.xml index bcdb6824ed..2b4b0041b3 100644 --- a/core-java-modules/core-java-collections-list-5/pom.xml +++ b/core-java-modules/core-java-collections-list-5/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-collections-list-5 core-java-collections-list-5 diff --git a/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/streamtoanotherlist/CreateListOfDifferentTypeUsingStreamUnitTest.java b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/streamtoanotherlist/CreateListOfDifferentTypeUsingStreamUnitTest.java new file mode 100644 index 0000000000..c2d74dd726 --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/streamtoanotherlist/CreateListOfDifferentTypeUsingStreamUnitTest.java @@ -0,0 +1,114 @@ +package com.baeldung.java.streamtoanotherlist; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; + +import lombok.Getter; + +@Getter +class Employee { + private final String name; + private final Set hobbies = new HashSet<>(); + private final String email; + private String department; + + public Employee(String name, String email, Collection hobbies) { + this.name = name; + this.email = email; + this.hobbies.addAll(hobbies); + } +} + +class TennisPlayerCandidate { + private final String name; + private final String email; + private final Boolean confirmed = Boolean.FALSE; + + public TennisPlayerCandidate(String name, String email) { + this.name = name; + this.email = email; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof TennisPlayerCandidate)) + return false; + + TennisPlayerCandidate that = (TennisPlayerCandidate) o; + + if (!Objects.equals(name, that.name)) + return false; + return Objects.equals(email, that.email); + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (email != null ? email.hashCode() : 0); + return result; + } +} + +public class CreateListOfDifferentTypeUsingStreamUnitTest { + private final static List EMPLOYEES = Lists.newArrayList( + // @formatter:off + new Employee("Kai", "kai@company.com", Lists.newArrayList("Football", "Reading", "Chess")), + new Employee("Eric", "eric@company.com", Lists.newArrayList("Tennis", "Baseball", "Singing")), + new Employee("Saajan", "saajan@company.com", Lists.newArrayList("Tennis", "Baseball", "Singing")), + new Employee("Kevin", "kevin@company.com", Lists.newArrayList("Dancing", "Computer Games", "Tennis")), + new Employee("Amanda", "amanda@company.com", Lists.newArrayList("Painting", "Yoga", "Dancing")) + //@formatter:on + ); + + private final static List EXPECTED = Lists.newArrayList( + // @formatter:off + new TennisPlayerCandidate("Eric", "eric@company.com"), + new TennisPlayerCandidate("Saajan", "saajan@company.com"), + new TennisPlayerCandidate("Kevin", "kevin@company.com") + //@formatter:on + ); + + @Test + void whenUsingStreamForEachFillingAnotherList_thenGetExpectedResult() { + List result = new ArrayList<>(); + EMPLOYEES.forEach(e -> { + if (e.getHobbies() + .contains("Tennis")) { + result.add(new TennisPlayerCandidate(e.getName(), e.getEmail())); + } + }); + + assertEquals(EXPECTED, result); + } + + @Test + void whenUsingStreamMap_thenGetExpectedResult() { + List result = EMPLOYEES.stream() + .filter(e -> e.getHobbies() + .contains("Tennis")) + .map(e -> new TennisPlayerCandidate(e.getName(), e.getEmail())) + .collect(Collectors.toList()); + assertEquals(EXPECTED, result); + } + + @Test + void whenUsingCollectorMapping_thenGetExpectedResult() { + List result = EMPLOYEES.stream() + .filter(e -> e.getHobbies() + .contains("Tennis")) + .collect(Collectors.mapping(e -> new TennisPlayerCandidate(e.getName(), e.getEmail()), Collectors.toList())); + assertEquals(EXPECTED, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-6/README.md b/core-java-modules/core-java-collections-list-6/README.md new file mode 100644 index 0000000000..fd162743dc --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Check if a List Contains a String Element While Ignoring Case](https://www.baeldung.com/java-list-search-case-insensitive) diff --git a/core-java-modules/core-java-collections-list-6/pom.xml b/core-java-modules/core-java-collections-list-6/pom.xml new file mode 100644 index 0000000000..46ef4ff4c9 --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + core-java-collections-list-6 + core-java-collections-list-6 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java new file mode 100644 index 0000000000..51fafcca6b --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.lists; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class StringListCaseInsensitiveContainsUnitTest { + private final static List THE_LIST = List.of("Game of Thrones", "Forrest Gump", "American Beauty", "Pretty Woman", "Catch Me If You Can"); + + @Test + void whenUsingContains_thenGetExpectedResult() { + assertFalse(THE_LIST.contains("catch me if you can")); + } + + boolean ignoreCaseContainsForLoop(List list, String value) { + for (String e : list) { + if (value.equalsIgnoreCase(e)) + return true; + } + return false; + } + + @Test + void whenUsingIgnoreCaseContainsForLoop_thenGetExpectedResult() { + assertTrue(ignoreCaseContainsForLoop(THE_LIST, "CATCH me if you CAN")); + assertTrue(ignoreCaseContainsForLoop(THE_LIST, "game of thrones")); + assertFalse(ignoreCaseContainsForLoop(THE_LIST, "The Godfather")); + } + + @Test + void whenUsingIgnoreCaseContainsStream_thenGetExpectedResult() { + assertTrue(THE_LIST.stream() + .anyMatch(e -> e.equalsIgnoreCase("CATCH me if you CAN"))); + + assertTrue(THE_LIST.stream() + .anyMatch("game of thrones"::equalsIgnoreCase)); + + assertFalse(THE_LIST.stream() + .anyMatch("The Godfather"::equalsIgnoreCase)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-3/README.md b/core-java-modules/core-java-collections-maps-3/README.md index 68df2b9556..0d07bde8c1 100644 --- a/core-java-modules/core-java-collections-maps-3/README.md +++ b/core-java-modules/core-java-collections-maps-3/README.md @@ -9,4 +9,5 @@ This module contains articles about Map data structures in Java. - [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap) - [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor) - [Converting Java Properties to HashMap](https://www.baeldung.com/java-convert-properties-to-hashmap) +- [Get Values and Keys as ArrayList From a HashMap](https://www.baeldung.com/java-values-keys-arraylists-hashmap) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2) diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java new file mode 100644 index 0000000000..39c537bac2 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.map.hashmap.kvtolist; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public class MapKeysValuesToListUnitTest { + private static final HashMap DEV_MAP; + + static { + DEV_MAP = new HashMap<>(); + DEV_MAP.put("Kent", "Linux"); + DEV_MAP.put("Eric", "MacOS"); + DEV_MAP.put("Kevin", "Windows"); + DEV_MAP.put("Michal", "MacOS"); + DEV_MAP.put("Saajan", "Linux"); + } + + @Test + void whenUsingKeySet_thenGetExpectedResult() { + List keyList = new ArrayList<>(DEV_MAP.keySet()); + // this assertion may fail, since hashMap doesn't preserve the insertion order + // assertEquals(Lists.newArrayList("Kent", "Eric", "Kevin", "Michal", "Saajan"), keyList); + + assertThat(keyList).containsExactlyInAnyOrder("Kent", "Eric", "Kevin", "Michal", "Saajan"); + + } + + @Test + void whenUsingValues_thenGetExpectedResult() { + List valueList = new ArrayList<>(DEV_MAP.values()); + assertThat(valueList).containsExactlyInAnyOrder("Linux", "MacOS", "Windows", "MacOS", "Linux"); + } + + @Test + void whenLoopingEntries_thenGetExpectedResult() { + List keyList = new ArrayList<>(); + List valueList = new ArrayList<>(); + for (Map.Entry entry : DEV_MAP.entrySet()) { + keyList.add(entry.getKey()); + valueList.add(entry.getValue()); + } + + assertKeyAndValueList(keyList, valueList); + + } + + @Test + void whenUsingForEach_thenGetExpectedResult() { + List keyList = new ArrayList<>(); + List valueList = new ArrayList<>(); + DEV_MAP.forEach((k, v) -> { + keyList.add(k); + valueList.add(v); + }); + + assertKeyAndValueList(keyList, valueList); + } + + private void assertKeyAndValueList(List keyList, List valueList) { + assertThat(keyList).containsExactlyInAnyOrder("Kent", "Eric", "Kevin", "Michal", "Saajan"); + assertThat(valueList).containsExactlyInAnyOrder("Linux", "MacOS", "Windows", "MacOS", "Linux"); + for (int i = 0; i < keyList.size(); i++) { + assertThat(DEV_MAP).containsEntry(keyList.get(i), valueList.get(i)); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/identity/IdentityHashMapDemonstrator.java b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/identity/IdentityHashMapDemonstrator.java index 3cbe09b93f..3b98423120 100644 --- a/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/identity/IdentityHashMapDemonstrator.java +++ b/core-java-modules/core-java-collections-maps-5/src/main/java/com/baeldung/map/identity/IdentityHashMapDemonstrator.java @@ -53,7 +53,7 @@ public class IdentityHashMapDemonstrator { } } - private static class Book { + static class Book { String title; int year; diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/identity/IdentityHashMapDemonstratorUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/identity/IdentityHashMapDemonstratorUnitTest.java index cc74ce4dd6..388338c3ab 100644 --- a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/identity/IdentityHashMapDemonstratorUnitTest.java +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/identity/IdentityHashMapDemonstratorUnitTest.java @@ -1,8 +1,11 @@ package com.baeldung.map.identity; +import com.baeldung.map.identity.IdentityHashMapDemonstrator.Book; import org.junit.jupiter.api.Test; import java.util.IdentityHashMap; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -18,4 +21,44 @@ public class IdentityHashMapDemonstratorUnitTest { assertEquals("Fantasy", identityHashMap.get("genre")); assertEquals("Drama", identityHashMap.get(newGenreKey)); } + + @Test + @EnabledForJreRange(max = JRE.JAVA_19) + public void removeEntryComparingValueByEquality() { + Book book = new Book("A Passage to India", 1924); + IdentityHashMap identityHashMap = new IdentityHashMap<>(10); + identityHashMap.put(book, "A great work of fiction"); + identityHashMap.remove(book, new String("A great work of fiction")); + assertEquals(null, identityHashMap.get(book)); + } + + @Test + @EnabledForJreRange(max = JRE.JAVA_19) + public void replaceEntryComparingValueByEquality() { + Book book = new Book("A Passage to India", 1924); + IdentityHashMap identityHashMap = new IdentityHashMap<>(10); + identityHashMap.put(book, "A great work of fiction"); + identityHashMap.replace(book, new String("A great work of fiction"), "One of the greatest books"); + assertEquals("One of the greatest books", identityHashMap.get(book)); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_20) + public void dontRemoveEntryComparingValueByEquality() { + Book book = new Book("A Passage to India", 1924); + IdentityHashMap identityHashMap = new IdentityHashMap<>(10); + identityHashMap.put(book, "A great work of fiction"); + identityHashMap.remove(book, new String("A great work of fiction")); + assertEquals("A great work of fiction", identityHashMap.get(book)); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_20) + public void dontReplaceEntryComparingValueByEquality() { + Book book = new Book("A Passage to India", 1924); + IdentityHashMap identityHashMap = new IdentityHashMap<>(10); + identityHashMap.put(book, "A great work of fiction"); + identityHashMap.replace(book, new String("A great work of fiction"), "One of the greatest books"); + assertEquals("A great work of fiction", identityHashMap.get(book)); + } } diff --git a/core-java-modules/core-java-collections-maps-6/README.md b/core-java-modules/core-java-collections-maps-6/README.md index bebcdea82b..f116d0315e 100644 --- a/core-java-modules/core-java-collections-maps-6/README.md +++ b/core-java-modules/core-java-collections-maps-6/README.md @@ -8,3 +8,5 @@ - [How to Modify a Key in a HashMap?](https://www.baeldung.com/java-hashmap-modify-key) - [Converting String or String Array to Map in Java](https://www.baeldung.com/java-convert-string-to-map) - [Remove Duplicate Values From HashMap in Java](https://www.baeldung.com/java-hashmap-delete-duplicates) +- [Sorting Java Map in Descending Order](https://www.baeldung.com/java-sort-map-descending) +- [Convert HashMap.toString() to HashMap in Java](https://www.baeldung.com/hashmap-from-tostring) diff --git a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java deleted file mode 100644 index 52c2fb2bea..0000000000 --- a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package java.com.baeldung.objecttomap; -import com.google.gson.Gson; -import org.junit.Assert; -import org.junit.Test; -import wiremock.com.fasterxml.jackson.core.type.TypeReference; -import wiremock.com.fasterxml.jackson.databind.ObjectMapper; -import wiremock.com.google.common.reflect.TypeToken; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - -public class ObjectToMapUnitTest { - Employee employee = new Employee("John", 3000.0); - - @Test - public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { - Map map = convertUsingReflection(employee); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private Map convertUsingReflection(Object object) throws IllegalAccessException { - Map map = new HashMap<>(); - Field[] fields = object.getClass().getDeclaredFields(); - - for (Field field : fields) { - field.setAccessible(true); - map.put(field.getName(), field.get(object)); - } - - return map; - } - - @Test - public void givenJavaObject_whenUsingJackson_thenConvertToMap() { - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.convertValue(employee, new TypeReference>() {}); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - @Test - public void givenJavaObject_whenUsingGson_thenConvertToMap() { - Gson gson = new Gson(); - String json = gson.toJson(employee); - Map map = gson.fromJson(json, new TypeToken>() {}.getType()); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private static class Employee { - private String name; - private Double salary; - - public Employee(String name, Double salary) { - this.name = name; - this.salary = salary; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Double getSalary() { - return salary; - } - - public void setSalary(Double age) { - this.salary = salary; - } - } -} diff --git a/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java new file mode 100644 index 0000000000..e232121048 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.objecttomap; + +import static org.junit.Assert.assertEquals; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import org.junit.Test; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public class ObjectToMapUnitTest { + Employee employee = new Employee("John", 3000.0); + + @Test + public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { + Map map = convertUsingReflection(employee); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + private Map convertUsingReflection(Object object) throws IllegalAccessException { + Map map = new HashMap<>(); + Field[] fields = object.getClass().getDeclaredFields(); + + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(object)); + } + + return map; + } + + @Test + public void givenJavaObject_whenUsingJackson_thenConvertToMap() { + ObjectMapper objectMapper = new ObjectMapper(); + Map map = objectMapper.convertValue(employee, new TypeReference>() {}); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void givenJavaObject_whenUsingGson_thenConvertToMap() { + Gson gson = new Gson(); + String json = gson.toJson(employee); + Map map = gson.fromJson(json, new TypeToken>() {}.getType()); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void given_UnsortedMap_whenSortingByValueDescending_thenValuesAreInDescendingOrder() { + Map unsortedMap = new HashMap<>(); + unsortedMap.put("one", 1); + unsortedMap.put("three", 3); + unsortedMap.put("five", 5); + unsortedMap.put("two", 2); + unsortedMap.put("four", 4); + + Map sortedMap = sortMapByValueDescending(unsortedMap); + + assertEquals(5, sortedMap.size()); + final Iterator iterator = sortedMap.values().iterator(); + assertEquals(5, (int) iterator.next()); + assertEquals(4, (int) iterator.next()); + assertEquals(3, (int) iterator.next()); + assertEquals(2, (int) iterator.next()); + assertEquals(1, (int) iterator.next()); + } + + @Test + public void given_UnsortedMap_whenUsingTreeMap_thenKeysAreInDescendingOrder() { + SortedMap treeMap = new TreeMap<>(Comparator.reverseOrder()); + treeMap.put("one", 1); + treeMap.put("three", 3); + treeMap.put("five", 5); + treeMap.put("two", 2); + treeMap.put("four", 4); + + assertEquals(5, treeMap.size()); + final Iterator iterator = treeMap.keySet().iterator(); + assertEquals("two", iterator.next()); + assertEquals("three", iterator.next()); + assertEquals("one", iterator.next()); + assertEquals("four", iterator.next()); + assertEquals("five", iterator.next()); + } + + private static class Employee { + private String name; + private Double salary; + + public Employee(String name, Double salary) { + this.name = name; + this.salary = salary; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getSalary() { + return salary; + } + + public void setSalary(Double age) { + this.salary = salary; + } + } + + public static > Map sortMapByValueDescending(Map map) { + return map.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } +} diff --git a/core-java-modules/core-java-collections-maps-7/README.md b/core-java-modules/core-java-collections-maps-7/README.md new file mode 100644 index 0000000000..5599187cd8 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [Difference Between putIfAbsent() and computeIfAbsent() in Java’s Map](https://www.baeldung.com/java-map-putifabsent-computeifabsent) +- [How to Write Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv) diff --git a/core-java-modules/core-java-collections-maps-7/pom.xml b/core-java-modules/core-java-collections-maps-7/pom.xml new file mode 100644 index 0000000000..cefee201cc --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + core-java-collections-maps-7 + core-java-collections-maps-7 + jar + + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + + + 5.2.5.RELEASE + + + + com.fasterxml.jackson.core + jackson-databind + 2.12.4 + + + org.openjdk.jmh + jmh-core + 1.36 + + + com.google.code.gson + gson + 2.8.9 + + + org.json + json + 20230227 + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + org.apache.commons + commons-csv + 1.5 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + + diff --git a/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java new file mode 100644 index 0000000000..2b3d6db89c --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java @@ -0,0 +1,60 @@ +package com.baeldung.map; + +import java.util.HashMap; +import java.util.Map; + +public class ConvertHashMapStringToHashMapObjectUsingtoString { + public String name; + public int age; + + public ConvertHashMapStringToHashMapObjectUsingtoString(String name, int age) { + this.name = name; + this.age = age; + } + + public static ConvertHashMapStringToHashMapObjectUsingtoString deserializeCustomObject(String valueString) { + if (valueString.startsWith("{") && valueString.endsWith("}")) { + valueString = valueString.substring(1, valueString.length() - 1); + String[] parts = valueString.split(","); + String name = null; + int age = -1; + for (String part : parts) { + String[] keyValue = part.split("="); + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String val = keyValue[1].trim(); + if (key.equals("name")) { + name = val; + } else if (key.equals("age")) { + age = Integer.parseInt(val); + } + } + } + if (name != null && age >= 0) { + return new ConvertHashMapStringToHashMapObjectUsingtoString(name, age); + } + } + return new ConvertHashMapStringToHashMapObjectUsingtoString("", -1); + } + + public static void main(String[] args) { + String hashMapString = "{key1={name=John, age=30}, key2={name=Alice, age=25}}"; + String keyValuePairs = hashMapString.replaceAll("[{}\\s]", ""); + String[] pairs = keyValuePairs.split(","); + Map actualHashMap = new HashMap<>(); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + String key = keyValue[0]; + ConvertHashMapStringToHashMapObjectUsingtoString value = deserializeCustomObject(keyValue[1]); + actualHashMap.put(key, value); + } + } + System.out.println(actualHashMap); + } + + @Override + public String toString() { + return "{name=" + name + ", age=" + age + "}"; + } +} diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java new file mode 100644 index 0000000000..7d31402131 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.map; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest { + + @Test + void givenValidCustomObject_whenSerializing_thenSerializedStringIsCorrect() { + ConvertHashMapStringToHashMapObjectUsingtoString customObject = new ConvertHashMapStringToHashMapObjectUsingtoString("John", 30); + String expectedSerializedString = "{name=John, age=30}"; + assertEquals(expectedSerializedString, customObject.toString()); + } + + @Test + void givenValidSerializedString_whenDeserializing_thenCustomObjectIsCorrect() { + String serializedString = "{name=Alice, age=25}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(serializedString); + assertEquals("Alice", customObject.name); + assertEquals(25, customObject.age); + } + + @Test + void givenInvalidSerializedString_whenDeserializing_thenDefaultCustomObjectIsCreated() { + String invalidSerializedString = "{invalidString}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(invalidSerializedString); + assertEquals("", customObject.name); + assertEquals(-1, customObject.age); + } +} diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/PutIfAbsentVsComputeIfAbsentUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/PutIfAbsentVsComputeIfAbsentUnitTest.java new file mode 100644 index 0000000000..304045ab9d --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/PutIfAbsentVsComputeIfAbsentUnitTest.java @@ -0,0 +1,98 @@ +package com.baeldung.map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +class Magic { + public String nullFunc() { + return null; + } + + public String strFunc(String input) { + return input + ": A nice string"; + } +} + +public class PutIfAbsentVsComputeIfAbsentUnitTest { + + private static final Map MY_MAP = new HashMap<>(); + private Magic magic = new Magic(); + + @BeforeEach + void resetTheMap() { + MY_MAP.clear(); + MY_MAP.put("Key A", "value A"); + MY_MAP.put("Key B", "value B"); + MY_MAP.put("Key C", "value C"); + MY_MAP.put("Key Null", null); + } + + @Test + void whenCallingPutIfAbsentWithAbsentKey_thenGetNull() { + String putResult = MY_MAP.putIfAbsent("new key1", magic.nullFunc()); + assertNull(putResult); + + putResult = MY_MAP.putIfAbsent("new key2", magic.strFunc("new key2")); + assertNull(putResult); + + putResult = MY_MAP.putIfAbsent("Key Null", magic.strFunc("Key Null")); + assertNull(putResult); + } + + @Test + void whenCallingComputeIfAbsentWithAbsentKey_thenGetExpectedResult() { + String computeResult = MY_MAP.computeIfAbsent("new key1", k -> magic.nullFunc()); + assertNull(computeResult); + + computeResult = MY_MAP.computeIfAbsent("new key2", k -> magic.strFunc(k)); + assertEquals("new key2: A nice string", computeResult); + + computeResult = MY_MAP.computeIfAbsent("Key Null", k -> magic.strFunc(k)); + assertEquals("Key Null: A nice string", computeResult); + } + + @Test + void whenCallingPutIfAbsentWithAbsentKey_thenNullIsPut() { + assertEquals(4, MY_MAP.size()); // initial: 4 entries + MY_MAP.putIfAbsent("new key", magic.nullFunc()); + assertEquals(5, MY_MAP.size()); + assertTrue(MY_MAP.containsKey("new key")); // new entry has been added to the map + assertNull(MY_MAP.get("new key")); + } + + @Test + void whenCallingComputeIfAbsentWithAbsentKey_thenNullIsNotPut() { + assertEquals(4, MY_MAP.size()); // initial: 4 entries + MY_MAP.computeIfAbsent("new key", k -> magic.nullFunc()); + assertEquals(4, MY_MAP.size()); + assertFalse(MY_MAP.containsKey("new key")); // <- no new entry added + } + + @Test + void whenCallingPutIfAbsent_thenFunctionIsAlwaysCalled() { + Magic spyMagic = spy(magic); + MY_MAP.putIfAbsent("Key A", spyMagic.strFunc("Key A")); + verify(spyMagic, times(1)).strFunc(anyString()); + + MY_MAP.putIfAbsent("new key", spyMagic.strFunc("new key")); + verify(spyMagic, times(2)).strFunc(anyString()); + } + + @Test + void whenCallingComputeIfAbsent_thenFunctionIsCalledOnDemand() { + Magic spyMagic = spy(magic); + MY_MAP.computeIfAbsent("Key A", k -> spyMagic.strFunc(k)); + verify(spyMagic, never()).strFunc(anyString()); + + MY_MAP.computeIfAbsent("new key", k -> spyMagic.strFunc(k)); + verify(spyMagic, times(1)).strFunc(anyString()); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/linkedhashmapfirstandlastentry/GetFirstAndLastEntryFromLinkedHashMapUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/linkedhashmapfirstandlastentry/GetFirstAndLastEntryFromLinkedHashMapUnitTest.java new file mode 100644 index 0000000000..b872e8bdda --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/linkedhashmapfirstandlastentry/GetFirstAndLastEntryFromLinkedHashMapUnitTest.java @@ -0,0 +1,85 @@ +package com.baeldung.map.linkedhashmapfirstandlastentry; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class GetFirstAndLastEntryFromLinkedHashMapUnitTest { + private static final LinkedHashMap THE_MAP = new LinkedHashMap<>(); + + static { + THE_MAP.put("key one", "a1 b1 c1"); + THE_MAP.put("key two", "a2 b2 c2"); + THE_MAP.put("key three", "a3 b3 c3"); + THE_MAP.put("key four", "a4 b4 c4"); + } + + @Test + void whenIteratingEntrySet_thenGetExpectedResult() { + Entry firstEntry = THE_MAP.entrySet().iterator().next(); + assertEquals("key one", firstEntry.getKey()); + assertEquals("a1 b1 c1", firstEntry.getValue()); + + Entry lastEntry = null; + Iterator> it = THE_MAP.entrySet().iterator(); + while (it.hasNext()) { + lastEntry = it.next(); + } + + assertNotNull(lastEntry); + assertEquals("key four", lastEntry.getKey()); + assertEquals("a4 b4 c4", lastEntry.getValue()); + + } + + @Test + void whenConvertingEntriesToArray_thenGetExpectedResult() { + + Entry[] theArray = new Entry[THE_MAP.size()]; + THE_MAP.entrySet().toArray(theArray); + + Entry firstEntry = theArray[0]; + assertEquals("key one", firstEntry.getKey()); + assertEquals("a1 b1 c1", firstEntry.getValue()); + + Entry lastEntry = theArray[THE_MAP.size() - 1]; + assertEquals("key four", lastEntry.getKey()); + assertEquals("a4 b4 c4", lastEntry.getValue()); + } + + @Test + void whenUsingStreamAPI_thenGetExpectedResult() { + Entry firstEntry = THE_MAP.entrySet().stream().findFirst().get(); + assertEquals("key one", firstEntry.getKey()); + assertEquals("a1 b1 c1", firstEntry.getValue()); + + Entry lastEntry = THE_MAP.entrySet().stream().skip(THE_MAP.size() - 1).findFirst().get(); + + assertNotNull(lastEntry); + assertEquals("key four", lastEntry.getKey()); + assertEquals("a4 b4 c4", lastEntry.getValue()); + } + + @Test + void whenUsingReflection_thenGetExpectedResult() throws NoSuchFieldException, IllegalAccessException { + Field head = THE_MAP.getClass().getDeclaredField("head"); + head.setAccessible(true); + Entry firstEntry = (Entry) head.get(THE_MAP); + assertEquals("key one", firstEntry.getKey()); + assertEquals("a1 b1 c1", firstEntry.getValue()); + + Field tail = THE_MAP.getClass().getDeclaredField("tail"); + tail.setAccessible(true); + Entry lastEntry = (Entry) tail.get(THE_MAP); + assertEquals("key four", lastEntry.getKey()); + assertEquals("a4 b4 c4", lastEntry.getValue()); + } + + +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/writehashmaptocsvfile/WriteHashmaptoCVSFileUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/writehashmaptocsvfile/WriteHashmaptoCVSFileUnitTest.java new file mode 100644 index 0000000000..e23a5da8ff --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/writehashmaptocsvfile/WriteHashmaptoCVSFileUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.writehashmaptocsvfile; + +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class WriteHashmaptoCVSFileUnitTest { + public Map employeeData; + + public WriteHashmaptoCVSFileUnitTest() { + employeeData = new HashMap<>(); + employeeData.put("Name", "John Doe"); + employeeData.put("Title", "Software Engineer"); + employeeData.put("Department", "Engineering"); + employeeData.put("Salary", "75000"); + } + + @Test + public void givenEmployeeData_whenWriteToCSVUsingFileWriter_thenCSVFileIsCreated() { + + try (FileWriter csvWriter = new FileWriter("employee_data.csv")) { + // Write header row + csvWriter.append("Name,Title,Department,Salary\n"); + + // Write data row + csvWriter.append(employeeData.get("Name")).append(","); + csvWriter.append(employeeData.get("Title")).append(","); + csvWriter.append(employeeData.get("Department")).append(","); + csvWriter.append(employeeData.get("Salary")).append("\n"); + } catch (IOException e) { + e.printStackTrace(); + } + // Ensure the CSV file exists + assertTrue(new File("employee_data.csv").exists(), "CSV file does not exist!"); + + } + + @Test + public void givenCSVFile_whenWriteToCSVUsingApacheCommons_thenContentsMatchExpected() { + + try (CSVPrinter csvPrinter = new CSVPrinter(new FileWriter("employee_data2.csv"), CSVFormat.DEFAULT)) { + // Write header row + csvPrinter.printRecord("Name", "Title", "Department", "Salary"); + + // Write data row + csvPrinter.printRecord(employeeData.get("Name"), employeeData.get("Title"), employeeData.get("Department"), employeeData.get("Salary")); + } catch (IOException e) { + e.printStackTrace(); + } + + // Ensure the CSV file exists + assertTrue(new File("employee_data2.csv").exists()); + } +} diff --git a/core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/MapClear.java b/core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/MapClear.java new file mode 100644 index 0000000000..9e16b742cf --- /dev/null +++ b/core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/MapClear.java @@ -0,0 +1,49 @@ +package com.baeldung.map; + +import java.util.HashMap; +import java.util.Map; + +public class MapClear { + public static Map returnCopyAndClearMap() { + // Create a HashMap + Map scores = new HashMap<>(); + Map scores_copy; + + // Add some key-value pairs + scores.put("Alice", 90); + scores.put("Bob", 85); + scores.put("Charlie", 95); + + scores_copy = scores; + + System.out.println("Before clearing: " + scores); + + // Clear the map + scores.clear(); + + System.out.println("After clearing: " + scores); + return scores_copy; + } + + public static Map returnCopyAndRewriteMap() { + // Create a HashMap + Map scores = new HashMap<>(); + Map scores_copy; + + // Add some key-value pairs + scores.put("Alice", 90); + scores.put("Bob", 85); + scores.put("Charlie", 95); + + scores_copy = scores; + + System.out.println("Before clearing: " + scores); + + // Create a new map + scores = new HashMap<>(); + + System.out.println("After clearing: " + scores); + + return scores_copy; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/MapClearUnitTest.java b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/MapClearUnitTest.java new file mode 100644 index 0000000000..a6d10f2707 --- /dev/null +++ b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/MapClearUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.map; + +import java.util.Map; + +import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MapClearUnitTest { + @Test + public void givenMap_returnEntryAndClearContent() { + Map entry = MapClear.returnCopyAndClearMap(); + assertTrue(entry.isEmpty()); + } + + @Test public void givenMap_returnEntryAndRewriteContent() { + Map entry = MapClear.returnCopyAndRewriteMap(); + assertTrue(!entry.isEmpty()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/UsingtoStringUnitTest.java b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/UsingtoStringUnitTest.java new file mode 100644 index 0000000000..4af6b72a4e --- /dev/null +++ b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/UsingtoStringUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.map; + +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; + +public class UsingtoStringUnitTest { + + @Test + public void given_HashMapString_whenUsingtoString_thenConvertToHashMapObject() { + // Example string representation of a HashMap + String hashMapString = "{key1=value1, key2=value2, key3=value3}"; + + // Remove unnecessary characters + String keyValuePairs = hashMapString.replaceAll("[{}\\s]", ""); + + // Split into individual key-value pairs + String[] pairs = keyValuePairs.split(","); + + // Create a new HashMap + HashMap expectedHashMap = new HashMap<>(); + expectedHashMap.put("key1", "value1"); + expectedHashMap.put("key2", "value2"); + expectedHashMap.put("key3", "value3"); + + HashMap actualHashMap = new HashMap<>(); + + // Parse and populate the HashMap + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + actualHashMap.put(keyValue[0], keyValue[1]); + } + } + + // Assert that the converted HashMap matches the expected one + assertEquals(expectedHashMap, actualHashMap); + } + +} diff --git a/core-java-modules/core-java-collections-set-2/README.md b/core-java-modules/core-java-collections-set-2/README.md index 33f20d60af..ee41908faf 100644 --- a/core-java-modules/core-java-collections-set-2/README.md +++ b/core-java-modules/core-java-collections-set-2/README.md @@ -4,4 +4,6 @@ - [A Guide to LinkedHashSet in Java](https://www.baeldung.com/java-linkedhashset) - [Sorting a HashSet in Java](https://www.baeldung.com/java-sort-hashset) - [How to Get First Item From a Java Set](https://www.baeldung.com/first-item-set) +- [Cartesian Product of Any Number of Sets in Java](https://www.baeldung.com/java-cartesian-product-sets) +- [How to Get Index of an Item in Java Set](https://www.baeldung.com/java-set-element-find-index) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-set) diff --git a/core-java-modules/core-java-collections-set-2/pom.xml b/core-java-modules/core-java-collections-set-2/pom.xml index 680c01d8ca..7274f1861b 100644 --- a/core-java-modules/core-java-collections-set-2/pom.xml +++ b/core-java-modules/core-java-collections-set-2/pom.xml @@ -20,6 +20,23 @@ ${junit-platform.version} test + + org.apache.commons + commons-collections4 + 4.4 + + + + org.testng + testng + 7.7.0 + test + + + com.google.guava + guava + 32.1.1-jre + diff --git a/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java new file mode 100644 index 0000000000..d4725d74f1 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java @@ -0,0 +1,75 @@ +package com.baeldung.cartesianproduct; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.Sets; + +public class CartesianProduct { + public List> getCartesianProductIterative(List> sets) { + List> result = new ArrayList<>(); + if(sets == null || sets.isEmpty()) { + return result; + } + int totalSets = sets.size(); + int totalCombinations = 1 << totalSets; + for(int i = 0; i < totalCombinations; i++) { + List combination = new ArrayList<>(); + for(int j = 0; j < totalSets; j++) { + if (((i >> j) & 1) == 1) { + combination.add(sets.get(j).get(0)); + } else { + combination.add(sets.get(j).get(1)); + } + } + result.add(combination); + } + return result; + } + + public List> getCartesianProductRecursive(List> sets) { + List> result = new ArrayList<>(); + getCartesianProductRecursiveHelper(sets, 0, new ArrayList<>(), result); + return result; + } + + private void getCartesianProductRecursiveHelper(List> sets, int index, List current, List> result) { + if(index == sets.size()) { + result.add(new ArrayList<>(current)); + return; + } + List currentSet = sets.get(index); + for(Object element: currentSet) { + current.add(element); + getCartesianProductRecursiveHelper(sets, index+1, current, result); + current.remove(current.size() - 1); + } + } + + public List> getCartesianProductUsingStreams(List> sets) { + return cartesianProduct(sets,0).collect(Collectors.toList()); + } + + public Stream> cartesianProduct(List> sets, int index) { + if(index == sets.size()) { + List emptyList = new ArrayList<>(); + return Stream.of(emptyList); + } + List currentSet = sets.get(index); + return currentSet.stream().flatMap(element -> cartesianProduct(sets, index+1) + .map(list -> { + List newList = new ArrayList<>(list); + newList.add(0, element); return newList; + })); + } + + public List> getCartesianProductUsingGuava(List> sets) { + Set> cartesianProduct = Sets.cartesianProduct(sets); + List> cartesianList = new ArrayList<>(cartesianProduct); + return cartesianList; + } + +} diff --git a/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/IndexOfElementsInSet.java b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/IndexOfElementsInSet.java new file mode 100644 index 0000000000..abedf147a3 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/IndexOfElementsInSet.java @@ -0,0 +1,29 @@ +package com.baeldung.indexawareset; + +import java.util.Iterator; +import java.util.Set; + +public class IndexOfElementsInSet { + public int getIndexUsingIterator(Set set, E element) { + Iterator iterator = set.iterator(); + int index = 0; + while (iterator.hasNext()) { + if (element.equals(iterator.next())) { + return index; + } + index++; + } + return -1; + } + + public int getIndexUsingForEach(Set set, E element) { + int index = 0; + for (E current : set) { + if (element.equals(current)) { + return index; + } + index++; + } + return -1; + } +} diff --git a/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/InsertionIndexAwareSet.java b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/InsertionIndexAwareSet.java new file mode 100644 index 0000000000..de2a739186 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/indexawareset/InsertionIndexAwareSet.java @@ -0,0 +1,20 @@ +package com.baeldung.indexawareset; + +import java.util.LinkedHashSet; + +public class InsertionIndexAwareSet extends LinkedHashSet { + public InsertionIndexAwareSet() { + super(); + } + + public int getIndexOf(E element) { + int index = 0; + for (E current : this) { + if (current.equals(element)) { + return index; + } + index++; + } + return -1; + } +} diff --git a/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java new file mode 100644 index 0000000000..cc9c01fb5f --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.cartesianproduct; + +import static org.testng.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.testng.annotations.Test; + +public class CartesianProductUnitTest { + private CartesianProduct cp = new CartesianProduct(); + List> sets = Arrays.asList( + Arrays.asList(10, 20), + Arrays.asList("John", "Jack"), + Arrays.asList('I', 'J') + ); + + @Test + public void whenUsingStreams_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingStreams(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingRecursion_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductRecursive(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingIterativeApproach_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(10, "John", 'I') + ); + List> cartesianProduct = cp.getCartesianProductIterative(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingGuava_thenCalculateCartesianProduct() { + List> sets = new ArrayList<>(); + sets.add(new HashSet<>(Arrays.asList(10, 20))); + sets.add(new HashSet<>(Arrays.asList("John", "Jack"))); + sets.add(new HashSet<>(Arrays.asList('I', 'J'))); + + List> expected = Arrays.asList( + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingGuava(sets); + + assertEquals(expected, cartesianProduct); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/indexawareset/IndexOfSetElementsUsingListUnitTest.java b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/indexawareset/IndexOfSetElementsUsingListUnitTest.java new file mode 100644 index 0000000000..a1f961a5a4 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/indexawareset/IndexOfSetElementsUsingListUnitTest.java @@ -0,0 +1,108 @@ +package com.baeldung.indexawareset; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.collections4.set.ListOrderedSet; +import org.junit.Assert; +import org.junit.Test; + +public class IndexOfSetElementsUsingListUnitTest { + @Test + public void givenHashSet_whenIndexOfElement_thenGivesIndex() { + Set set = new HashSet<>(); + set.add(100); + set.add(20); + set.add(300); + set.add(0); + set.add(-1); + set.add(300); + + IndexOfElementsInSet integerIndexOfElementsInSet = new IndexOfElementsInSet<>(); + int index100 = integerIndexOfElementsInSet.getIndexUsingIterator(set, 100); + Assert.assertEquals(index100, integerIndexOfElementsInSet.getIndexUsingIterator(set, 100)); + + Assert.assertEquals(-1, integerIndexOfElementsInSet.getIndexUsingIterator(set, 12)); + } + + @Test + public void givenLinkedHashSet_whenIndexOfElement_thenGivesIndex() { + Set set = new LinkedHashSet<>(); + set.add(100); + set.add(20); + set.add(300); + set.add(0); + set.add(-1); + set.add(300); + + IndexOfElementsInSet integerIndexOfElementsInSet = new IndexOfElementsInSet<>(); + Assert.assertEquals(0, integerIndexOfElementsInSet.getIndexUsingIterator(set, 100)); + } + + @Test + public void givenTreeSet_whenIndexOfElement_thenGivesIndex() { + Set set = new TreeSet<>(); + set.add(100); + set.add(20); + set.add(300); + set.add(0); + set.add(-1); + set.add(300); + + IndexOfElementsInSet integerIndexOfElementsInSet = new IndexOfElementsInSet<>(); + Assert.assertEquals(0, integerIndexOfElementsInSet.getIndexUsingIterator(set, -1)); + Assert.assertEquals(3, integerIndexOfElementsInSet.getIndexUsingIterator(set, 100)); + } + + @Test + public void givenIndexAwareSet_whenIndexOfElement_thenGivesIndex() { + InsertionIndexAwareSet set = new InsertionIndexAwareSet<>(); + set.add(100); + set.add(20); + set.add(300); + Assert.assertEquals(0, set.getIndexOf(100)); + Assert.assertEquals(2, set.getIndexOf(300)); + Assert.assertEquals(-1, set.getIndexOf(0)); + } + + @Test + public void givenIndexAwareSetWithStrings_whenIndexOfElement_thenGivesIndex() { + InsertionIndexAwareSet set = new InsertionIndexAwareSet<>(); + set.add("Go"); + set.add("Java"); + set.add("Scala"); + set.add("Python"); + Assert.assertEquals(0, set.getIndexOf("Go")); + Assert.assertEquals(2, set.getIndexOf("Scala")); + Assert.assertEquals(-1, set.getIndexOf("C++")); + } + + @Test + public void givenListOrderedSet_whenIndexOfElement_thenGivesIndex() { + ListOrderedSet set = new ListOrderedSet<>(); + set.add(12); + set.add(0); + set.add(-1); + set.add(50); + + Assert.assertEquals(0, set.indexOf(12)); + Assert.assertEquals(2, set.indexOf(-1)); + Assert.assertEquals(-1, set.indexOf(100)); + } + + @Test + public void givenLinkedHashSet_whenIndexUsingUtilityMethod_thenReturnsIndex() { + Set set = new LinkedHashSet<>(); + set.add(100); + set.add(20); + set.add(300); + set.add(0); + set.add(-1); + set.add(300); + + IndexOfElementsInSet integerIndexOfElementsInSet = new IndexOfElementsInSet<>(); + Assert.assertEquals(-1, integerIndexOfElementsInSet.getIndexUsingForEach(set, 150)); + } +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Consumer.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Consumer.java index 9c880025f7..de350a40c4 100644 --- a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Consumer.java +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Consumer.java @@ -4,6 +4,7 @@ import java.util.logging.Logger; public class Consumer implements Runnable { private static final Logger log = Logger.getLogger(Consumer.class.getCanonicalName()); + private boolean running = false; private final DataQueue dataQueue; public Consumer(DataQueue dataQueue) { @@ -12,26 +13,36 @@ public class Consumer implements Runnable { @Override public void run() { + running = true; consume(); } + public void stop() { + running = false; + } + public void consume() { - while (dataQueue.runFlag) { - while (dataQueue.isEmpty() && dataQueue.runFlag) { + while (running) { + + if (dataQueue.isEmpty()) { try { - dataQueue.waitOnEmpty(); + dataQueue.waitIsNotEmpty(); } catch (InterruptedException e) { - e.printStackTrace(); + log.severe("Error while waiting to Consume messages."); break; } } - if (!dataQueue.runFlag) { + + // avoid spurious wake-up + if (!running) { break; } - Message message = dataQueue.remove(); - dataQueue.notifyAllForFull(); + + Message message = dataQueue.poll(); useMessage(message); + //Sleeping on random time to make it realistic + ThreadUtil.sleep((long) (Math.random() * 100)); } log.info("Consumer Stopped"); } @@ -40,14 +51,7 @@ public class Consumer implements Runnable { if (message != null) { log.info(String.format("[%s] Consuming Message. Id: %d, Data: %f%n", Thread.currentThread().getName(), message.getId(), message.getData())); - - //Sleeping on random time to make it realistic - ThreadUtil.sleep((long) (message.getData() * 100)); } } - public void stop() { - dataQueue.runFlag = false; - dataQueue.notifyAllForEmpty(); - } } diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/DataQueue.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/DataQueue.java index 8867ddeb63..7286ed8af8 100644 --- a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/DataQueue.java +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/DataQueue.java @@ -6,10 +6,8 @@ import java.util.Queue; public class DataQueue { private final Queue queue = new LinkedList<>(); private final int maxSize; - private final Object FULL_QUEUE = new Object(); - private final Object EMPTY_QUEUE = new Object(); - - public boolean runFlag = true; + private final Object IS_NOT_FULL = new Object(); + private final Object IS_NOT_EMPTY = new Object(); DataQueue(int maxSize) { this.maxSize = maxSize; @@ -23,39 +21,42 @@ public class DataQueue { return queue.isEmpty(); } - public void waitOnFull() throws InterruptedException { - synchronized (FULL_QUEUE) { - FULL_QUEUE.wait(); + public void waitIsNotFull() throws InterruptedException { + synchronized (IS_NOT_FULL) { + IS_NOT_FULL.wait(); } } - public void waitOnEmpty() throws InterruptedException { - synchronized (EMPTY_QUEUE) { - EMPTY_QUEUE.wait(); - } - } - - public void notifyAllForFull() { - synchronized (FULL_QUEUE) { - FULL_QUEUE.notifyAll(); - } - } - - public void notifyAllForEmpty() { - synchronized (EMPTY_QUEUE) { - EMPTY_QUEUE.notifyAll(); + public void waitIsNotEmpty() throws InterruptedException { + synchronized (IS_NOT_EMPTY) { + IS_NOT_EMPTY.wait(); } } public void add(Message message) { - synchronized (queue) { - queue.add(message); + queue.add(message); + notifyIsNotEmpty(); + } + + public Message poll() { + Message mess = queue.poll(); + notifyIsNotFull(); + return mess; + } + + public Integer getSize() { + return queue.size(); + } + + private void notifyIsNotFull() { + synchronized (IS_NOT_FULL) { + IS_NOT_FULL.notify(); } } - public Message remove() { - synchronized (queue) { - return queue.poll(); + private void notifyIsNotEmpty() { + synchronized (IS_NOT_EMPTY) { + IS_NOT_EMPTY.notify(); } } } diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Producer.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Producer.java index 5ca60a29e4..4bd0e9e6d1 100644 --- a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Producer.java +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/Producer.java @@ -1,60 +1,63 @@ package com.baeldung.producerconsumer; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; public class Producer implements Runnable { private static final Logger log = Logger.getLogger(Producer.class.getCanonicalName()); + private static final AtomicInteger idSequence = new AtomicInteger(0); + private boolean running = false; private final DataQueue dataQueue; - private static int idSequence = 0; - public Producer(DataQueue dataQueue) { this.dataQueue = dataQueue; } @Override public void run() { + running = true; produce(); } + public void stop() { + running = false; + } + public void produce() { - while (dataQueue.runFlag) { - while (dataQueue.isFull() && dataQueue.runFlag) { + + while (running) { + + if (dataQueue.isFull()) { try { - dataQueue.waitOnFull(); + dataQueue.waitIsNotFull(); } catch (InterruptedException e) { - e.printStackTrace(); + log.severe("Error while waiting to Produce messages."); break; } } - if (!dataQueue.runFlag) { + + // avoid spurious wake-up + if (!running) { break; } - Message message = generateMessage(); - dataQueue.add(message); - dataQueue.notifyAllForEmpty(); + dataQueue.add(generateMessage()); + + log.info("Size of the queue is: " + dataQueue.getSize()); + + //Sleeping on random time to make it realistic + ThreadUtil.sleep((long) (Math.random() * 100)); } + log.info("Producer Stopped"); } private Message generateMessage() { - Message message = new Message(incrementAndGetId(), Math.random()); + Message message = new Message(idSequence.incrementAndGet(), Math.random()); log.info(String.format("[%s] Generated Message. Id: %d, Data: %f%n", Thread.currentThread().getName(), message.getId(), message.getData())); - //Sleeping on random time to make it realistic - ThreadUtil.sleep((long) (message.getData() * 100)); - return message; } - private static int incrementAndGetId() { - return ++idSequence; - } - - public void stop() { - dataQueue.runFlag = false; - dataQueue.notifyAllForFull(); - } } diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/ProducerConsumerDemonstrator.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/ProducerConsumerDemonstrator.java index 96d7b9f865..5e8c99fce3 100644 --- a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/ProducerConsumerDemonstrator.java +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/producerconsumer/ProducerConsumerDemonstrator.java @@ -27,7 +27,7 @@ public class ProducerConsumerDemonstrator { // let threads run for two seconds sleep(2000); - // Stop threads + // stop threads producer.stop(); consumer.stop(); @@ -36,28 +36,34 @@ public class ProducerConsumerDemonstrator { public static void demoMultipleProducersAndMultipleConsumers() { DataQueue dataQueue = new DataQueue(MAX_QUEUE_CAPACITY); - int producerCount = 3; - int consumerCount = 3; + int producerCount = 5; + int consumerCount = 5; List threads = new ArrayList<>(); - Producer producer = new Producer(dataQueue); + List producers = new ArrayList<>(); + List consumers = new ArrayList<>(); + for(int i = 0; i < producerCount; i++) { + Producer producer = new Producer(dataQueue); Thread producerThread = new Thread(producer); producerThread.start(); threads.add(producerThread); + producers.add(producer); } - Consumer consumer = new Consumer(dataQueue); + for(int i = 0; i < consumerCount; i++) { + Consumer consumer = new Consumer(dataQueue); Thread consumerThread = new Thread(consumer); consumerThread.start(); threads.add(consumerThread); + consumers.add(consumer); } - // let threads run for two seconds - sleep(2000); + // let threads run for ten seconds + sleep(10000); - // Stop threads - producer.stop(); - consumer.stop(); + // stop threads + consumers.forEach(Consumer::stop); + producers.forEach(Producer::stop); waitForAllThreadsToComplete(threads); } diff --git a/core-java-modules/core-java-concurrency-advanced-5/README.md b/core-java-modules/core-java-concurrency-advanced-5/README.md new file mode 100644 index 0000000000..ba845a7c4b --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-5/README.md @@ -0,0 +1,3 @@ + +### Relevant Articles: +- [Why wait() Requires Synchronization?](https://www.baeldung.com/java-wait-necessary-synchronization) diff --git a/core-java-modules/core-java-concurrency-advanced-5/pom.xml b/core-java-modules/core-java-concurrency-advanced-5/pom.xml new file mode 100644 index 0000000000..b84d3810bb --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-5/pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + core-java-concurrency-advanced-5 + core-java-concurrency-advanced-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + core-java-concurrency-advanced-5 + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + 1.8 + 1.8 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-5/src/main/java/com/baeldung/wait_synchronization/ConditionChecker.java b/core-java-modules/core-java-concurrency-advanced-5/src/main/java/com/baeldung/wait_synchronization/ConditionChecker.java new file mode 100644 index 0000000000..dca36fe7cb --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-5/src/main/java/com/baeldung/wait_synchronization/ConditionChecker.java @@ -0,0 +1,24 @@ +package com.baeldung.wait_synchronization; + +public class ConditionChecker { + + private volatile Boolean jobIsDone; + private final Object lock = new Object(); + + public void ensureCondition() { + synchronized (lock) { + while (!jobIsDone) { + try { + lock.wait(); + } catch (InterruptedException e) { } + } + } + } + + public void complete() { + synchronized (lock) { + jobIsDone = true; + lock.notify(); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/wait_synchronization/ConditionCheckerUnitTest.java b/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/wait_synchronization/ConditionCheckerUnitTest.java new file mode 100644 index 0000000000..2698640e6a --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/wait_synchronization/ConditionCheckerUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.wait_synchronization; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class ConditionCheckerUnitTest { + + @Test + public void givenBothMethodsAreSynchronized_whenBothMethodsAreCalled_thenNoExceptionsOrDeadlocks() { + ConditionChecker conditionChecker = new ConditionChecker(); + + ExecutorService executorService = Executors.newFixedThreadPool(2); + + Assertions.assertThatCode(() -> { + executorService.submit(conditionChecker::ensureCondition); + executorService.submit(conditionChecker::complete); + }).doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java index 44f84ad77c..093cfdbc81 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java +++ b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java @@ -7,31 +7,37 @@ import java.util.concurrent.Phaser; class LongRunningAction implements Runnable { - private static Logger log = LoggerFactory.getLogger(LongRunningAction.class); - private String threadName; - private Phaser ph; + private static final Logger log = LoggerFactory.getLogger(LongRunningAction.class); + private final String threadName; + private final Phaser ph; LongRunningAction(String threadName, Phaser ph) { this.threadName = threadName; this.ph = ph; + + this.randomWait(); + ph.register(); + log.info("Thread {} registered during phase {}", threadName, ph.getPhase()); } @Override public void run() { - log.info("This is phase {}", ph.getPhase()); - log.info("Thread {} before long running action", threadName); - + log.info("Thread {} BEFORE long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndAwaitAdvance(); + + randomWait(); + + log.info("Thread {} AFTER long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndDeregister(); + } + + // Simulating real work + private void randomWait() { try { - Thread.sleep(2000); + Thread.sleep((long) (Math.random() * 100)); } catch (InterruptedException e) { e.printStackTrace(); } - - log.debug("Thread {} action completed and waiting for others", threadName); - ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", threadName, ph.getPhase()); - - ph.arriveAndDeregister(); } } \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java index 384a1837c1..9cb863073e 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java +++ b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java @@ -7,8 +7,6 @@ import org.junit.runners.MethodSorters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Phaser; import static junit.framework.TestCase.assertEquals; @@ -16,38 +14,32 @@ import static junit.framework.TestCase.assertEquals; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class PhaserUnitTest { - private static Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); + private static final Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); @Test - public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() { - //given - ExecutorService executorService = Executors.newCachedThreadPool(); + public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() throws InterruptedException { Phaser ph = new Phaser(1); assertEquals(0, ph.getPhase()); - //when - executorService.submit(new LongRunningAction("thread-1", ph)); - executorService.submit(new LongRunningAction("thread-2", ph)); - executorService.submit(new LongRunningAction("thread-3", ph)); + new Thread(new LongRunningAction("thread-1", ph)).start(); + new Thread(new LongRunningAction("thread-2", ph)).start(); + new Thread(new LongRunningAction("thread-3", ph)).start(); - //then - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for others", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(1, ph.getPhase()); - //and - executorService.submit(new LongRunningAction("thread-4", ph)); - executorService.submit(new LongRunningAction("thread-5", ph)); + new Thread(new LongRunningAction("thread-4", ph)).start(); + new Thread(new LongRunningAction("thread-5", ph)).start(); - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for new phase", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(2, ph.getPhase()); - ph.arriveAndDeregister(); + Thread.sleep(1000); + assertEquals(true, ph.isTerminated()); } } diff --git a/core-java-modules/core-java-concurrency-basic-3/README.md b/core-java-modules/core-java-concurrency-basic-3/README.md index b9c66b279c..179a69495c 100644 --- a/core-java-modules/core-java-concurrency-basic-3/README.md +++ b/core-java-modules/core-java-concurrency-basic-3/README.md @@ -10,4 +10,5 @@ This module contains articles about basic Java concurrency. - [Returning a Value After Finishing Thread’s Job in Java](https://www.baeldung.com/java-return-value-after-thread-finish) - [CompletableFuture and ThreadPool in Java](https://www.baeldung.com/java-completablefuture-threadpool) - [CompletableFuture allOf().join() vs. CompletableFuture.join()](https://www.baeldung.com/java-completablefuture-allof-join) +- [Retry Logic with CompletableFuture](https://www.baeldung.com/java-completablefuture-retry-logic) - [[<-- Prev]](../core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFuture.java b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFuture.java new file mode 100644 index 0000000000..a3df6b3624 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFuture.java @@ -0,0 +1,63 @@ +package com.baeldung.concurrent.completablefuture.retry; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Supplier; + +public class RetryCompletableFuture { + public static CompletableFuture retryTask(Supplier supplier, int maxRetries) { + Supplier retryableSupplier = retryFunction(supplier, maxRetries); + return CompletableFuture.supplyAsync(retryableSupplier); + } + + static Supplier retryFunction(Supplier supplier, int maxRetries) { + return () -> { + int retries = 0; + while (retries < maxRetries) { + try { + return supplier.get(); + } catch (Exception e) { + retries++; + } + } + throw new IllegalStateException(String.format("Task failed after %s attempts", maxRetries)); + }; + } + + public static CompletableFuture retryUnsafe(Supplier supplier, int maxRetries) { + CompletableFuture cf = CompletableFuture.supplyAsync(supplier); + sleep(100l); + for (int i = 0; i < maxRetries; i++) { + cf = cf.exceptionally(__ -> supplier.get()); + } + return cf; + } + + public static CompletableFuture retryNesting(Supplier supplier, int maxRetries) { + CompletableFuture cf = CompletableFuture.supplyAsync(supplier); + sleep(100); + for (int i = 0; i < maxRetries; i++) { + cf = cf.thenApply(CompletableFuture::completedFuture) + .exceptionally(__ -> CompletableFuture.supplyAsync(supplier)) + .thenCompose(Function.identity()); + } + return cf; + } + + public static CompletableFuture retryExceptionallyAsync(Supplier supplier, int maxRetries) { + CompletableFuture cf = CompletableFuture.supplyAsync(supplier); + sleep(100); + for (int i = 0; i < maxRetries; i++) { + cf = cf.exceptionallyAsync(__ -> supplier.get()); + } + return cf; + } + + private static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuturelist/Application.java b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuturelist/Application.java new file mode 100644 index 0000000000..be5d9e8479 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuturelist/Application.java @@ -0,0 +1,100 @@ +package com.baeldung.concurrent.completablefuturelist; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.stream.Collectors; + +public class Application { + + ScheduledExecutorService asyncOperationEmulation; + + Application initialize() { + asyncOperationEmulation = Executors.newScheduledThreadPool(10); + return this; + } + + CompletableFuture asyncOperation(String operationId) { + CompletableFuture cf = new CompletableFuture<>(); + asyncOperationEmulation.submit(() -> { + // The following lines simulate an exception happening on the 567th operation + // if (operationId.endsWith("567")) { + // cf.completeExceptionally(new Exception("Error on operation " + operationId)); + // return; + // } + try { + Thread.sleep(100); + cf.complete(operationId); + } catch (InterruptedException e) { + System.err.println("Thread interrupted error"); + cf.completeExceptionally(e); + } + }); + return cf; + } + + void startNaive() { + List> futures = new ArrayList<>(); + for (int i = 1; i <= 1000; i++) { + String operationId = "Naive-Operation-" + i; + futures.add(asyncOperation(operationId)); + } + + CompletableFuture> aggregate = CompletableFuture.completedFuture(new ArrayList<>()); + for (CompletableFuture future : futures) { + aggregate = aggregate.thenCompose(list -> { + try { + list.add(future.get()); + return CompletableFuture.completedFuture(list); + } catch (Exception e) { + final CompletableFuture> excFuture = new CompletableFuture<>(); + excFuture.completeExceptionally(e); + return excFuture; + } + }); + } + + try { + final List results = aggregate.join(); + System.out.println("Printing first 10 results"); + for (int i = 0; i < 10; i++) { + System.out.println("Finished " + results.get(i)); + } + } finally { + close(); + } + } + + void start() { + List> futures = new ArrayList<>(); + for (int i = 1; i <= 1000; i++) { + String operationId = "Operation-" + i; + futures.add(asyncOperation(operationId)); + } + CompletableFuture[] futuresArray = futures.toArray(new CompletableFuture[0]); + CompletableFuture> listFuture = CompletableFuture.allOf(futuresArray).thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList())); + try { + final List results = listFuture.join(); + System.out.println("Printing first 10 results"); + for (int i = 0; i < 10; i++) { + System.out.println("Finished " + results.get(i)); + } + } finally { + close(); + } + } + + void close() { + asyncOperationEmulation.shutdownNow(); + } + + public static void main(String[] args) { + new Application().initialize() + // Switch between .startNaive() and .start() to test both implementations + // .startNaive(); + .start(); + } + +} diff --git a/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFutureUnitTest.java b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFutureUnitTest.java new file mode 100644 index 0000000000..ea49f0fa08 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/retry/RetryCompletableFutureUnitTest.java @@ -0,0 +1,120 @@ +package com.baeldung.concurrent.completablefuture.retry; + +import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryExceptionallyAsync; +import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryNesting; +import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryTask; +import static com.baeldung.concurrent.completablefuture.retry.RetryCompletableFuture.retryUnsafe; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class RetryCompletableFutureUnitTest { + private AtomicInteger retriesCounter = new AtomicInteger(0); + + @BeforeEach + void beforeEach() { + retriesCounter.set(0); + } + + @Test + void whenRetryingTask_thenReturnsCorrectlyAfterFourInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryTask(codeToRun, 10); + + assertThat(result.join()).isEqualTo(100); + assertThat(retriesCounter).hasValue(4); + } + + @Test + void whenRetryingTask_thenThrowsExceptionAfterThreeInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryTask(codeToRun, 3); + + assertThatThrownBy(result::join) + .isInstanceOf(CompletionException.class) + .hasMessageContaining("IllegalStateException: Task failed after 3 attempts"); + } + + @Test + void whenRetryingExceptionally_thenReturnsCorrectlyAfterFourInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryUnsafe(codeToRun, 10); + + assertThat(result.join()).isEqualTo(100); + assertThat(retriesCounter).hasValue(4); + } + + @Test + void whenRetryingExceptionally_thenThrowsExceptionAfterThreeInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryUnsafe(codeToRun, 3); + + assertThatThrownBy(result::join) + .isInstanceOf(CompletionException.class) + .hasMessageContaining("RuntimeException: task failed for 3 time(s)"); + } + + @Test + void whenRetryingExceptionallyAsync_thenReturnsCorrectlyAfterFourInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryExceptionallyAsync(codeToRun, 10); + + assertThat(result.join()).isEqualTo(100); + assertThat(retriesCounter).hasValue(4); + } + + @Test + void whenRetryingExceptionallyAsync_thenThrowsExceptionAfterThreeInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryExceptionallyAsync(codeToRun, 3); + + assertThatThrownBy(result::join) + .isInstanceOf(CompletionException.class) + .hasMessageContaining("RuntimeException: task failed for 3 time(s)"); + } + + @Test + void whenRetryingNesting_thenReturnsCorrectlyAfterFourInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryNesting(codeToRun, 10); + + assertThat(result.join()).isEqualTo(100); + assertThat(retriesCounter).hasValue(4); + } + + @Test + void whenRetryingNesting_thenThrowsExceptionAfterThreeInvocations() { + Supplier codeToRun = () -> failFourTimesThenReturn(100); + + CompletableFuture result = retryNesting(codeToRun, 3); + + assertThatThrownBy(result::join) + .isInstanceOf(CompletionException.class) + .hasMessageContaining("RuntimeException: task failed for 3 time(s)"); + } + + int failFourTimesThenReturn(int returnValue) { + int retryNr = retriesCounter.get(); + System.out.println(String.format("invocation: %s, thread: %s", retryNr, Thread.currentThread().getName())); + if (retryNr < 4) { + retriesCounter.set(retryNr + 1); + throw new RuntimeException(String.format("task failed for %s time(s)", retryNr)); + } + return returnValue; + } + +} diff --git a/core-java-modules/core-java-concurrency-basic/README.md b/core-java-modules/core-java-concurrency-basic/README.md index e5c061710c..a133beb1fe 100644 --- a/core-java-modules/core-java-concurrency-basic/README.md +++ b/core-java-modules/core-java-concurrency-basic/README.md @@ -11,4 +11,5 @@ This module contains articles about basic Java concurrency - [Runnable vs. Callable in Java](https://www.baeldung.com/java-runnable-callable) - [What Is Thread-Safety and How to Achieve It?](https://www.baeldung.com/java-thread-safety) - [How to Get Notified When a Task Completes in Java Executors](https://www.baeldung.com/java-executors-task-completed-notification) +- [Difference Between Future, CompletableFuture, and Rxjava’s Observable](https://www.baeldung.com/java-future-completablefuture-rxjavas-observable) - [[Next -->]](/core-java-modules/core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-collections-2/README.md b/core-java-modules/core-java-concurrency-collections-2/README.md index 2d65cf88e7..fdb7af5936 100644 --- a/core-java-modules/core-java-concurrency-collections-2/README.md +++ b/core-java-modules/core-java-concurrency-collections-2/README.md @@ -5,4 +5,5 @@ - [Java Concurrent HashSet Equivalent to ConcurrentHashMap](https://www.baeldung.com/java-concurrent-hashset-concurrenthashmap) - [Reading and Writing With a ConcurrentHashMap](https://www.baeldung.com/concurrenthashmap-reading-and-writing) - [ArrayBlockingQueue vs. LinkedBlockingQueue](https://www.baeldung.com/java-arrayblockingqueue-vs-linkedblockingqueue) +- [Difference Between Hashtable and ConcurrentHashMap in Java](https://www.baeldung.com/java-hashtable-vs-concurrenthashmap) - [[<-- Prev]](/core-java-modules/core-java-concurrency-collections) diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/BenchMarkRunner.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/BenchMarkRunner.java new file mode 100644 index 0000000000..3c7132ffcd --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/BenchMarkRunner.java @@ -0,0 +1,73 @@ +package com.baeldung.hashtableandconcurrenthashmap; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Hashtable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(value = 1) +@Warmup(iterations = 3) +@Measurement(iterations = 5) +@Threads(10) // 10 threads for the test +public class BenchMarkRunner { + private Hashtable hashTable; + private ConcurrentHashMap concurrentHashMap; + + @Setup(Level.Trial) + public void setup() { + hashTable = new Hashtable<>(); + concurrentHashMap = new ConcurrentHashMap<>(); + } + + @Benchmark + @Group("hashtable") + public void benchmarkHashtablePut() { + for (int i = 0; i < 10000; i++) { + hashTable.put(String.valueOf(i), i); + } + } + + @Benchmark + @Group("hashtable") + public void benchmarkHashtableGet(Blackhole blackhole) { + for (int i = 0; i < 10000; i++) { + Integer value = hashTable.get(String.valueOf(i)); + blackhole.consume(value); + } + } + + @Benchmark + @Group("concurrentHashMap") + public void benchmarkConcurrentHashMapPut() { + for (int i = 0; i < 10000; i++) { + concurrentHashMap.put(String.valueOf(i), i); + } + } + + @Benchmark + @Group("concurrentHashMap") + public void benchmarkConcurrentHashMapGet(Blackhole blackhole) { + for (int i = 0; i < 10000; i++) { + Integer value = concurrentHashMap.get(String.valueOf(i)); + blackhole.consume(value); + } + } + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(BenchMarkRunner.class.getSimpleName()) + .shouldFailOnError(true) + .shouldDoGC(true) + .jvmArgs("-server") + .build(); + new Runner(options).run(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/ConcurrentHashMapUnitTest.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/ConcurrentHashMapUnitTest.java new file mode 100644 index 0000000000..c936583abb --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/ConcurrentHashMapUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.hashtableandconcurrenthashmap; + +import org.junit.Test; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +public class ConcurrentHashMapUnitTest { + @Test + public void givenEmptyConcurrentHashMap_whenValuesAreAdded_thenValuesCanBeRetrieved() { + ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); + concurrentHashMap.put("Key1", "1"); + concurrentHashMap.put("Key2", "2"); + concurrentHashMap.putIfAbsent("Key3", "3"); + String value = concurrentHashMap.get("Key2"); + + assertEquals("1", concurrentHashMap.get("Key1")); + assertEquals("2", value); + assertEquals("3", concurrentHashMap.get("Key3")); + } + @Test + public void givenPopulatedConcurrentHashMap_whenModifiedDuringIteration_thenShouldNotThrowConcurrentModificationException() throws InterruptedException { + ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); + concurrentHashMap.put("Key1", 1); + concurrentHashMap.put("Key2", 2); + concurrentHashMap.put("Key3", 3); + AtomicBoolean exceptionCaught = new AtomicBoolean(false); + + Thread iteratorThread = new Thread(() -> { + Iterator it = concurrentHashMap.keySet().iterator(); + try { + while (it.hasNext()) { + it.next(); + Thread.sleep(100); + } + } catch (ConcurrentModificationException e) { + exceptionCaught.set(true); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + Thread modifierThread = new Thread(() -> { + try { + Thread.sleep(50); + concurrentHashMap.put("Key4", 4); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + iteratorThread.start(); + modifierThread.start(); + + iteratorThread.join(); + modifierThread.join(); + + assertFalse(exceptionCaught.get()); + } +} diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/HashtableUnitTest.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/HashtableUnitTest.java new file mode 100644 index 0000000000..8f8195fdef --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/hashtableandconcurrenthashmap/HashtableUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.hashtableandconcurrenthashmap; + +import org.junit.Test; +import java.util.ConcurrentModificationException; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +public class HashtableUnitTest { + @Test + public void givenEmptyHashtable_whenValuesAreAdded_thenValuesCanBeRetrieved() { + Hashtable hashtable = new Hashtable<>(); + hashtable.put("Key1", "1"); + hashtable.put("Key2", "2"); + hashtable.putIfAbsent("Key3", "3"); + String value = hashtable.get("Key2"); + + assertEquals("1", hashtable.get("Key1")); + assertEquals("2", value); + assertEquals("3", hashtable.get("Key3")); + } + @Test + public void givenPopulatedHashtable_whenModifiedDuringIteration_thenShouldThrowConcurrentModificationException() throws InterruptedException { + Hashtable hashtable = new Hashtable<>(); + hashtable.put("Key1", 1); + hashtable.put("Key2", 2); + hashtable.put("Key3", 3); + AtomicBoolean exceptionCaught = new AtomicBoolean(false); + + Thread iteratorThread = new Thread(() -> { + Iterator it = hashtable.keySet().iterator(); + try { + while (it.hasNext()) { + it.next(); + Thread.sleep(100); + } + } catch (ConcurrentModificationException e) { + exceptionCaught.set(true); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + Thread modifierThread = new Thread(() -> { + try { + Thread.sleep(50); + hashtable.put("Key4", 4); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + iteratorThread.start(); + modifierThread.start(); + + iteratorThread.join(); + modifierThread.join(); + + assertTrue(exceptionCaught.get()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-simple/README.md b/core-java-modules/core-java-concurrency-simple/README.md index 5cbfc67862..422d33e2c3 100644 --- a/core-java-modules/core-java-concurrency-simple/README.md +++ b/core-java-modules/core-java-concurrency-simple/README.md @@ -12,6 +12,7 @@ This module contains articles about Java Concurrency that are also part of an Eb - [Guide to the Volatile Keyword in Java](https://www.baeldung.com/java-volatile) - [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial) - [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture) +- [How To Manage Timeout for CompletableFuture](https://www.baeldung.com/java-completablefuture-timeout) ### NOTE: diff --git a/core-java-modules/core-java-concurrency-simple/pom.xml b/core-java-modules/core-java-concurrency-simple/pom.xml index a16df4fc97..720ab5a0ed 100644 --- a/core-java-modules/core-java-concurrency-simple/pom.xml +++ b/core-java-modules/core-java-concurrency-simple/pom.xml @@ -12,6 +12,15 @@ 0.0.1-SNAPSHOT + + + org.wiremock + wiremock + 3.1.0 + test + + + core-java-concurrency-simple diff --git a/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/completablefuture/CompletableFutureTimeoutUnitTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/completablefuture/CompletableFutureTimeoutUnitTest.java new file mode 100644 index 0000000000..d04865026b --- /dev/null +++ b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/completablefuture/CompletableFutureTimeoutUnitTest.java @@ -0,0 +1,182 @@ +package com.baeldung.concurrent.completablefuture; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.concurrent.*; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class CompletableFutureTimeoutUnitTest { + private WireMockServer wireMockServer; + private ScheduledExecutorService executorService; + private static final int DEFAULT_TIMEOUT = 1000; //1 seconds + private static final String DEFAULT_PRODUCT = """ + { + "products": [ + { + "id": 2, + "title": "iPhone X", + "description": "SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...", + "price": 899, + "discountPercentage": 0.0, + "rating": 4.44, + "stock": 34, + "brand": "Apple", + "category": "smartphones" + }, + { + "id": 3, + "title": "Samsung Universe 9", + "description": "Samsung's new variant which goes beyond Galaxy to the Universe", + "price": 1249, + "discountPercentage": 0.0, + "rating": 4.09, + "stock": 36, + "brand": "Samsung", + "category": "smartphones" + } + ], + "total": 2 + }"""; + private static final String PRODUCT_OFFERS = """ + { + "products": [ + { + "id": 1, + "title": "iPhone 9", + "description": "An apple mobile which is nothing like apple", + "price": 549, + "discountPercentage": 12.96, + "rating": 4.69, + "stock": 94, + "brand": "Apple", + "category": "smartphones" + }, + { + "id": 2, + "title": "iPhone X", + "description": "SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...", + "price": 899, + "discountPercentage": 17.94, + "rating": 4.44, + "stock": 34, + "brand": "Apple", + "category": "smartphones" + }, + { + "id": 3, + "title": "Samsung Universe 9", + "description": "Samsung's new variant which goes beyond Galaxy to the Universe", + "price": 1249, + "discountPercentage": 15.46, + "rating": 4.09, + "stock": 36, + "brand": "Samsung", + "category": "smartphones" + }, + { + "id": 4, + "title": "OPPOF19", + "description": "OPPO F19 is officially announced on April 2021.", + "price": 280, + "discountPercentage": 17.91, + "rating": 4.3, + "stock": 123, + "brand": "OPPO", + "category": "smartphones" + }, + { + "id": 5, + "title": "Huawei P30", + "description": "Huawei’s re-badged P30 Pro New Edition was officially unveiled yesterday in Germany and now the device has made its way to the UK.", + "price": 499, + "discountPercentage": 10.58, + "rating": 4.09, + "stock": 32, + "brand": "Huawei", + "category": "smartphones" + } + ], + "total": 5 + }"""; + + @BeforeAll + void setUp() { + wireMockServer = new WireMockServer(8080); + wireMockServer.start(); + WireMock.configureFor("localhost", 8080); + + stubFor(get(urlEqualTo("/api/dummy")) + .willReturn(aResponse() + .withFixedDelay(5000) // must be > DEFAULT_TIMEOUT for a timeout to occur. + .withBody(PRODUCT_OFFERS))); + + executorService = Executors.newScheduledThreadPool(1); + } + + @AfterAll + void tearDown() { + executorService.shutdown(); + wireMockServer.stop(); + } + + private CompletableFuture fetchProductData() { + return CompletableFuture.supplyAsync(() -> { + try { + URL url = new URL("http://localhost:8080/api/dummy"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + + return response.toString(); + } finally { + connection.disconnect(); + } + } catch (IOException e) { + return ""; + } + }); + } + + + @Test + void whenorTimeout_thenGetThrow() { + CompletableFuture productDataFuture = fetchProductData(); + productDataFuture.orTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + assertThrows(ExecutionException.class, productDataFuture::get); + } + + @Test + void whencompleteOnTimeout_thenReturnValue() throws ExecutionException, InterruptedException { + CompletableFuture productDataFuture = fetchProductData(); + productDataFuture.completeOnTimeout(DEFAULT_PRODUCT, DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + assertEquals(DEFAULT_PRODUCT, productDataFuture.get()); + } + + @Test + void whencompleteExceptionally_thenGetThrow() { + CompletableFuture productDataFuture = fetchProductData(); + executorService.schedule(() -> productDataFuture + .completeExceptionally(new TimeoutException("Timeout occurred")), DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + assertThrows(ExecutionException.class, productDataFuture::get); + } +} diff --git a/core-java-modules/core-java-conditionals/README.md b/core-java-modules/core-java-conditionals/README.md index ae5694c3ba..828f3484f1 100644 --- a/core-java-modules/core-java-conditionals/README.md +++ b/core-java-modules/core-java-conditionals/README.md @@ -3,3 +3,4 @@ This module contains articles about Java Conditionals. ### Relevant articles: +- [Guide to the yield Keyword in Java](https://www.baeldung.com/java-yield-switch) diff --git a/core-java-modules/core-java-conditionals/pom.xml b/core-java-modules/core-java-conditionals/pom.xml index 2a1290c98e..811f183e99 100644 --- a/core-java-modules/core-java-conditionals/pom.xml +++ b/core-java-modules/core-java-conditionals/pom.xml @@ -37,20 +37,19 @@ --enable-preview - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire.plugin.version} - - --enable-preview - - + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + --enable-preview + + 14 - 3.8.1 14 3.0.0-M3 diff --git a/core-java-modules/core-java-date-operations-3/README.md b/core-java-modules/core-java-date-operations-3/README.md index e3f0cfa3dc..9d16d1f71c 100644 --- a/core-java-modules/core-java-date-operations-3/README.md +++ b/core-java-modules/core-java-date-operations-3/README.md @@ -10,4 +10,5 @@ This module contains articles about date operations in Java. - [How to Get Last Day of a Month in Java](https://www.baeldung.com/java-last-day-month) - [Getting Yesterday’s Date in Java](https://www.baeldung.com/java-find-yesterdays-date) - [How to Get the Start and End Dates of a Year Using Java](https://www.baeldung.com/java-date-year-start-end) +- [Convert Between Java LocalDate and Epoch](https://www.baeldung.com/java-localdate-epoch) - [[<-- Prev]](/core-java-modules/core-java-date-operations-2) diff --git a/core-java-modules/core-java-date-operations-3/pom.xml b/core-java-modules/core-java-date-operations-3/pom.xml index 19760ca357..9b7be18b85 100644 --- a/core-java-modules/core-java-date-operations-3/pom.xml +++ b/core-java-modules/core-java-date-operations-3/pom.xml @@ -12,7 +12,7 @@ core-java-modules 0.0.1-SNAPSHOT - + joda-time @@ -25,7 +25,7 @@ ${commons-lang3.version} - + 2.12.5 3.12.0 diff --git a/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/EpochToLocalDate.java b/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/EpochToLocalDate.java new file mode 100644 index 0000000000..574693355d --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/EpochToLocalDate.java @@ -0,0 +1,24 @@ +package com.baeldung.epochconversion; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; + +public class EpochToLocalDate { + + public static void main(String[] args) { + long millisSinceEpoch = 2131242L; + ZoneId zoneId = ZoneId.of("Europe/Amsterdam"); // or: ZoneId.systemDefault(); + // to get All Zone Ids available, we can use the function below + // Set allZoneIds = ZoneId.getAvailableZoneIds(); + LocalDate date = + Instant.ofEpochMilli(millisSinceEpoch) + .atZone(zoneId) + .toLocalDate(); + LocalDateTime time = + Instant.ofEpochMilli(millisSinceEpoch) + .atZone(zoneId) + .toLocalDateTime(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/LocalDateToEpoch.java b/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/LocalDateToEpoch.java new file mode 100644 index 0000000000..b84cd5c1a7 --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/main/java/com/baeldung/epochconversion/LocalDateToEpoch.java @@ -0,0 +1,18 @@ +package com.baeldung.epochconversion; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; + +public class LocalDateToEpoch { + + public static void main(String[] args) { + ZoneId zoneId = ZoneId.of("Europe/Amsterdam"); // or: ZoneId.systemDefault() + LocalDate date = LocalDate.now(); + long epochMilliSecondsAtDate = date.atStartOfDay(zoneId).toInstant().toEpochMilli(); + + // epoch for time + LocalDateTime time = LocalDateTime.parse("2019-11-15T13:15:30"); + long epochMilliSecondsAtTime = time.atZone(zoneId).toInstant().toEpochMilli(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/EpochToLocalDateUnitTest.java b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/EpochToLocalDateUnitTest.java new file mode 100644 index 0000000000..90ab056511 --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/EpochToLocalDateUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.epochconversion; + +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EpochToLocalDateUnitTest { + + @Test + void givenEpoch_thenComputeLocalDateCorrectly() { + ZoneId zoneId = ZoneId.systemDefault(); + LocalDate expectedDate = LocalDate.of(1995, 4, 15); + long date = expectedDate.atStartOfDay(zoneId).toInstant().toEpochMilli(); + + LocalDate actualDate = + Instant.ofEpochMilli(date) + .atZone(zoneId) + .toLocalDate(); + assertEquals(expectedDate, actualDate); + } + + @Test + void givenEpoch_thenComputeLocalDateTimeCorrectly() { + ZoneId zoneId = ZoneId.systemDefault(); + LocalDateTime expectedTime = LocalDateTime.parse("2019-11-15T13:15:30"); + long time = expectedTime.atZone(zoneId).toInstant().toEpochMilli(); + + LocalDateTime actualTime = + Instant.ofEpochMilli(time) + .atZone(zoneId) + .toLocalDateTime(); + assertEquals(expectedTime, actualTime); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/LocalDateTimeToEpochUnitTest.java b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/LocalDateTimeToEpochUnitTest.java new file mode 100644 index 0000000000..8e9a4b01d0 --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/epochconversion/LocalDateTimeToEpochUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.epochconversion; + +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class LocalDateTimeToEpochUnitTest { + + @Test + void givenDate_thenComputeEpochCorrectly() { + ZoneId zoneId = ZoneId.of("Europe/Tallinn"); + long expectedEpoch = LocalDate.now().toEpochDay(); + LocalDateTime givenDate = Instant.ofEpochMilli(expectedEpoch) + .atZone(zoneId) + .toLocalDateTime(); + + long actualEpoch = givenDate.atZone(zoneId).toInstant().toEpochMilli(); + assertEquals(expectedEpoch, actualEpoch); + } + + @Test + void givenTime_thenComputeEpochCorrectly() { + ZoneId zoneId = ZoneId.of("Europe/Amsterdam"); + long expectedEpoch = Instant.now().toEpochMilli(); + LocalDateTime givenTime = Instant.ofEpochMilli(expectedEpoch) + .atZone(zoneId) + .toLocalDateTime(); + + long actualEpoch = givenTime.atZone(zoneId).toInstant().toEpochMilli(); + assertEquals(expectedEpoch, actualEpoch); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstdaymonth/FirstDayOfMonthUnitTest.java b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstdaymonth/FirstDayOfMonthUnitTest.java new file mode 100644 index 0000000000..9edc3e4a8d --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstdaymonth/FirstDayOfMonthUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.firstdaymonth; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.temporal.TemporalAdjusters; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.junit.jupiter.api.Test; + +public class FirstDayOfMonthUnitTest { + + @Test + void givenMonth_whenUsingCalendar_thenReturnFirstDay() { + Date currentDate = new GregorianCalendar(2023, Calendar.NOVEMBER, 23).getTime(); + Date expectedDate = new GregorianCalendar(2023, Calendar.NOVEMBER, 1).getTime(); + + Calendar cal = Calendar.getInstance(); + cal.setTime(currentDate); + cal.set(Calendar.DAY_OF_MONTH, 1); + + assertEquals(expectedDate, cal.getTime()); + } + + @Test + void givenMonth_whenUsingLocalDate_thenReturnFirstDay() { + LocalDate currentDate = LocalDate.of(2023, 9, 6); + LocalDate expectedDate = LocalDate.of(2023, 9, 1); + + assertEquals(expectedDate, currentDate.withDayOfMonth(1)); + } + + @Test + void givenMonth_whenUsingTemporalAdjusters_thenReturnFirstDay() { + LocalDate currentDate = LocalDate.of(2023, 7, 19); + LocalDate expectedDate = LocalDate.of(2023, 7, 1); + + assertEquals(expectedDate, currentDate.with(TemporalAdjusters.firstDayOfMonth())); + } + + @Test + void givenMonth_whenUsingYearMonth_thenReturnFirstDay() { + YearMonth currentDate = YearMonth.of(2023, 4); + LocalDate expectedDate = LocalDate.of(2023, 4, 1); + + assertEquals(expectedDate, currentDate.atDay(1)); + } + + @Test + void givenMonth_whenUsingJodaTime_thenReturnFirstDay() { + org.joda.time.LocalDate currentDate = org.joda.time.LocalDate.parse("2023-5-10"); + org.joda.time.LocalDate expectedDate = org.joda.time.LocalDate.parse("2023-5-1"); + + assertEquals(expectedDate, currentDate.dayOfMonth() + .withMinimumValue()); + } + +} diff --git a/core-java-modules/core-java-datetime-conversion/README.md b/core-java-modules/core-java-datetime-conversion/README.md index 11e4348838..d3a3dae728 100644 --- a/core-java-modules/core-java-datetime-conversion/README.md +++ b/core-java-modules/core-java-datetime-conversion/README.md @@ -8,3 +8,5 @@ This module contains articles about converting between Java date and time object - [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime) - [Convert Between java.time.Instant and java.sql.Timestamp](https://www.baeldung.com/java-time-instant-to-java-sql-timestamp) - [Convert Between LocalDateTime and ZonedDateTime](https://www.baeldung.com/java-localdatetime-zoneddatetime) +- [Conversion From 12-Hour Time to 24-Hour Time in Java](https://www.baeldung.com/java-convert-time-format) +- [Convert Epoch Time to LocalDate and LocalDateTime](https://www.baeldung.com/java-convert-epoch-localdate) diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java index 6e3b250938..80c403bb4e 100644 --- a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java @@ -12,10 +12,10 @@ public class EpochTimeToLocalDateTimeConverterUnitTest { @Test public void testConvertEpochTimeToLocalDateTime() { long epochTimeMillis = 1624962431000L; // Example epoch time in milliseconds - LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 12, 13, 51); + LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 10, 27, 11); Instant instant = Instant.ofEpochMilli(epochTimeMillis); - ZoneId zoneId = ZoneId.systemDefault(); + ZoneId zoneId = ZoneId.of("UTC"); LocalDateTime actualDateTime = instant.atZone(zoneId).toLocalDateTime(); assertEquals(expectedDateTime, actualDateTime); diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java new file mode 100644 index 0000000000..e82af6dd19 --- /dev/null +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.twelvehourstotwentyhours; + +import static org.junit.jupiter.api.Assertions.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Locale; +import org.junit.jupiter.api.Test; + +public class TimeConversionUnitTest { + + @Test + public void givenTimeInTwelveHours_whenConvertingToTwentyHours_thenConverted() throws ParseException { + SimpleDateFormat displayFormat = new SimpleDateFormat("HH:mm"); + SimpleDateFormat parseFormat = new SimpleDateFormat("hh:mm a"); + Date date = parseFormat.parse("06:00 PM"); + assertEquals("18:00", displayFormat.format(date)); + } + + @Test + public void givenTimeInTwelveHours_whenConvertingToTwentyHoursWithDateTimeFormatter_thenConverted() throws ParseException { + String time = LocalTime.parse("06:00 PM", DateTimeFormatter.ofPattern("hh:mm a", Locale.US)) + .format(DateTimeFormatter.ofPattern("HH:mm")); + assertEquals("18:00", time); + } + +} diff --git a/core-java-modules/core-java-datetime-string/pom.xml b/core-java-modules/core-java-datetime-string/pom.xml index 3efb2fe728..a33114852c 100644 --- a/core-java-modules/core-java-datetime-string/pom.xml +++ b/core-java-modules/core-java-datetime-string/pom.xml @@ -65,7 +65,7 @@ 1.6 - 2.10.10 + 2.12.5 RELEASE 1.9 1.9 diff --git a/core-java-modules/core-java-datetime-string/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java b/core-java-modules/core-java-datetime-string/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java index 172882af2c..d5128c522e 100644 --- a/core-java-modules/core-java-datetime-string/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java +++ b/core-java-modules/core-java-datetime-string/src/test/java/com/baeldung/datetime/DateTimeFormatterUnitTest.java @@ -96,7 +96,8 @@ public class DateTimeFormatterUnitTest { String newYorkDateTimePattern = "dd.MM.yyyy HH:mm z"; DateTimeFormatter newYorkDateFormatter = DateTimeFormatter.ofPattern(newYorkDateTimePattern); LocalDateTime summerDay = LocalDateTime.of(2016, 7, 31, 14, 15); - Assert.assertEquals("31.07.2016 14:15 EDT", newYorkDateFormatter.format(ZonedDateTime.of(summerDay, ZoneId.of("America/New_York")))); + Assert.assertEquals("31.07.2016 14:15 EDT", + newYorkDateFormatter.format(ZonedDateTime.of(summerDay, ZoneId.of("America/New_York")))); } @Test @@ -121,8 +122,10 @@ public class DateTimeFormatterUnitTest { @Test public void shouldPrintFormattedDateTimeWithPredefined() { Assert.assertEquals("2018-03-09", DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.of(2018, 3, 9))); - Assert.assertEquals("2018-03-09-03:00", DateTimeFormatter.ISO_OFFSET_DATE.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3")))); - Assert.assertEquals("Fri, 9 Mar 2018 00:00:00 -0300", DateTimeFormatter.RFC_1123_DATE_TIME.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3")))); + Assert.assertEquals("2018-03-09-03:00", + DateTimeFormatter.ISO_OFFSET_DATE.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3")))); + Assert.assertEquals("Fri, 9 Mar 2018 00:00:00 -0300", + DateTimeFormatter.RFC_1123_DATE_TIME.format(LocalDate.of(2018, 3, 9).atStartOfDay(ZoneId.of("UTC-3")))); } @Test @@ -165,30 +168,62 @@ public class DateTimeFormatterUnitTest { public void shouldPrintFormattedZonedDateTime() { ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 02, 15, 0, 0, 0, 0, ZoneId.of("Europe/Paris")); String formattedZonedDateTime = DateTimeFormatter.ISO_INSTANT.format(zonedDateTime); - + Assert.assertEquals("2021-02-14T23:00:00Z", formattedZonedDateTime); } - + @Test(expected = UnsupportedTemporalTypeException.class) public void shouldExpectAnExceptionIfInputIsLocalDateTime() { DateTimeFormatter.ISO_INSTANT.format(LocalDate.now()); } - + @Test public void shouldParseZonedDateTime() { DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.systemDefault()); ZonedDateTime zonedDateTime = ZonedDateTime.parse("2021-10-01T05:06:20Z", formatter); - + Assert.assertEquals("2021-10-01T05:06:20Z", DateTimeFormatter.ISO_INSTANT.format(zonedDateTime)); } - + @Test(expected = DateTimeParseException.class) public void shouldExpectAnExceptionIfTimeZoneIsMissing() { ZonedDateTime zonedDateTime = ZonedDateTime.parse("2021-11-01T05:06:20Z", DateTimeFormatter.ISO_INSTANT); } - + @Test(expected = DateTimeParseException.class) public void shouldExpectAnExceptionIfSecondIsMissing() { ZonedDateTime zonedDateTime = ZonedDateTime.parse("2021-12-02T08:06Z", DateTimeFormatter.ISO_INSTANT); } + + @Test + public void testUSShortFormatting() { + LocalDate date = LocalDate.of(2023, 9, 18); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yy: EEE").withLocale(Locale.US); + String formattedDate = date.format(formatter); + Assert.assertEquals("Sep 18, 23: Mon", formattedDate); + } + + @Test + public void testUSFullFormatting() { + LocalDate date = LocalDate.of(2023, 9, 18); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy: EEEE").withLocale(Locale.US); + String formattedDate = date.format(formatter); + Assert.assertEquals("September 18, 2023: Monday", formattedDate); + } + + @Test + public void testKoreanShortFormatting() { + LocalDate date = LocalDate.of(2023, 9, 18); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yy: EEE").withLocale(Locale.KOREA); + String formattedDate = date.format(formatter); + Assert.assertEquals("9월 18, 23: 월", formattedDate); + } + + @Test + public void testKoreanFullFormatting() { + LocalDate date = LocalDate.of(2023, 9, 18); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy: EEEE").withLocale(Locale.KOREA); + String formattedDate = date.format(formatter); + Assert.assertEquals("9월 18, 2023: 월요일", formattedDate); + } } diff --git a/core-java-modules/core-java-documentation/README.md b/core-java-modules/core-java-documentation/README.md index b66b9e8c05..972e76c165 100644 --- a/core-java-modules/core-java-documentation/README.md +++ b/core-java-modules/core-java-documentation/README.md @@ -3,4 +3,4 @@ ### Relevant Articles: - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - +- [Code Snippets in Java API Documentation](https://www.baeldung.com/java-doc-code-snippets) diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/generictype/Pair.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/generictype/Pair.java new file mode 100644 index 0000000000..f85adcfdab --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/generictype/Pair.java @@ -0,0 +1,23 @@ +package com.baeldung.generictype; + +/** + * @param The type of the first value in the {@code Pair}. + * @param The type of the second value in the {@code Pair}. + */ + +public class Pair { + public T first; + public S second; + + /** + * Constructs a new Pair object with the specified values. + * + * @param a The first value. + * @param b The second value. + */ + + public Pair(T a, S b) { + first = a; + second = b; + } +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java new file mode 100644 index 0000000000..6cf27b7acc --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java @@ -0,0 +1,18 @@ +package com.baeldung.snippettag; + +/** + * + * External code snippet showing the loop process in binary search method. + * {@snippet class="BinarySearch" region="binary"} + * + * Time Zone + * {@snippet file="application.properties" region="zone"} + * + */ + +public class GreetingsExternalSnippet { + public void helloBinarySearch() { + System.out.println("Hi, it's great knowing that binary search uses a loop under the hood"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java new file mode 100644 index 0000000000..03f30e1ad2 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java @@ -0,0 +1,35 @@ +package com.baeldung.snippettag; + + +/** + * The code below shows a full highlighted line + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight + * } + * } + * + * highlighting a substring + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight substring="println" + * } + * } + * + * highlighting texts on multiple lines + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight region substring="println" + * String country = "USA"; + * System.out.println("Hello From Team " + country); // @end + * } + * } + * + */ + +public class GreetingsHighlightTag { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java new file mode 100644 index 0000000000..71876eecf6 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java @@ -0,0 +1,17 @@ +package com.baeldung.snippettag; + +/** + * The code below shows the content of {@code helloBaeldung()} method + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); + * } + * } + */ + +public class GreetingsInlineSnippet { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java new file mode 100644 index 0000000000..7f6f1b72f7 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java @@ -0,0 +1,24 @@ +package com.baeldung.snippettag; + +/** + * + * Using the replace tag + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @replace regex='".*"' replacement="..." + * } + * } + * Using the link tag + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @link substring="System.out" target="System#out" + * } + * } + * + */ + +public class GreetingsReplaceAndLinkTag { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } +} diff --git a/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java b/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java new file mode 100644 index 0000000000..a5f6e565ac --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java @@ -0,0 +1,27 @@ + +public class BinarySearch { + + public int search(int[] list, int item) { + int index = Integer.MAX_VALUE; + int low = 0; + int high = list.length - 1; + // @start region="binary" + while (low <= high) { + int mid = high - low; + int guess = list[mid]; + if (guess == item) { + index = mid; + break; + } else if (guess > item) { + low = mid - 1; + } else { + low = mid + 1; + } + low++; + } + // @end region="binary" + + return index; + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties b/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties new file mode 100644 index 0000000000..a2aeefdb89 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties @@ -0,0 +1,4 @@ +# @start region="zone" +local.timezone = GMT+1 +local.zip = 94123 +# @end region="zone" \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java new file mode 100644 index 0000000000..ae783fa8bd --- /dev/null +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java @@ -0,0 +1,32 @@ +package com.baeldung.socketexception; + +import java.io.IOException; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +public class SslServer { + + public static void createSSLSocketWithEnabledProtocols(SSLServerSocketFactory socketFactory, int port, String[] enabledProtocols) { + SSLServerSocket serverSocket = null; + + try { + serverSocket = (SSLServerSocket) socketFactory.createServerSocket(port); + // Set the enabled protocols + serverSocket.setEnabledProtocols(enabledProtocols); + System.out.println("Server is running on port " + port); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java index 08b21c6299..197046d273 100644 --- a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java +++ b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java @@ -1,25 +1,33 @@ package com.baeldung.socketexception; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.net.SocketException; import java.util.concurrent.Executors; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + import org.junit.BeforeClass; import org.junit.Test; public class SocketExceptionHandlingUnitTest { + private static final int PORT = 6699; @BeforeClass public static void runServer() throws IOException, InterruptedException { Executors.newSingleThreadExecutor() - .submit(() -> new SocketServer().start(6699)); + .submit(() -> new SocketServer().start(PORT)); Thread.sleep(100); } @Test public void givenRunningServer_whenConnectToClosedSocket_thenHandleException() throws IOException { SocketClient client = new SocketClient(); - client.startConnection("127.0.0.1", 6699); + client.startConnection("127.0.0.1", PORT); try { client.sendMessage("hi"); client.sendMessage("hi again"); @@ -28,4 +36,22 @@ public class SocketExceptionHandlingUnitTest { } } + @Test + public void givenRunningServer_whenConnectToSocket_thenHandleConnectionResetException() throws IOException { + // Enable multiple SSL/TLS protocols + String[] enabledProtocols = { "TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1", "SSLv3", "SSLv3" }; + SSLServerSocketFactory mockFactory = mock(SSLServerSocketFactory.class); + SSLServerSocket mockServerSocket = mock(SSLServerSocket.class); + + // Set up the mock factory to return the mock server socket + when(mockFactory.createServerSocket(PORT)).thenReturn(mockServerSocket); + + // Call the method being tested + SslServer.createSSLSocketWithEnabledProtocols(mockFactory, PORT, enabledProtocols); + + // Verify that setEnabledProtocols and close were called + verify(mockServerSocket).setEnabledProtocols(enabledProtocols); + verify(mockServerSocket).close(); + } + } diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/Main.java b/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/Main.java index dfe8fcbd5a..b693bb1219 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/Main.java +++ b/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/Main.java @@ -20,8 +20,9 @@ public class Main { System.out.println("General exception"); } - checkedException(); + checkedExceptionWithTryCatch(); checkedExceptionWithThrows(); + divideByZero(); } private static void checkedExceptionWithThrows() throws FileNotFoundException { @@ -29,7 +30,7 @@ public class Main { FileInputStream stream = new FileInputStream(file); } - private static void checkedException() { + private static void checkedExceptionWithTryCatch() { File file = new File("not_existing_file.txt"); try { FileInputStream stream = new FileInputStream(file); @@ -37,5 +38,11 @@ public class Main { e.printStackTrace(); } } + + private static void divideByZero() { + int numerator = 1; + int denominator = 0; + int result = numerator / denominator; + } } diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/NullOrEmptyException.java b/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/NullOrEmptyException.java new file mode 100644 index 0000000000..419fb438f2 --- /dev/null +++ b/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/throwvsthrows/NullOrEmptyException.java @@ -0,0 +1,8 @@ +package com.baeldung.exceptions.throwvsthrows; + +public class NullOrEmptyException extends RuntimeException { + + public NullOrEmptyException(String errorMessage) { + super(errorMessage); + } +} diff --git a/core-java-modules/core-java-httpclient/src/main/java/com/baeldung/httpclient/HttpClientPost.java b/core-java-modules/core-java-httpclient/src/main/java/com/baeldung/httpclient/HttpClientPost.java index d08a7bf183..5c62bf73d9 100644 --- a/core-java-modules/core-java-httpclient/src/main/java/com/baeldung/httpclient/HttpClientPost.java +++ b/core-java-modules/core-java-httpclient/src/main/java/com/baeldung/httpclient/HttpClientPost.java @@ -123,6 +123,7 @@ public class HttpClientPost { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(serviceUrl)) + .header("Content-Type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString(getFormDataAsString(formData))) .build(); diff --git a/core-java-modules/core-java-io-5/.gitignore b/core-java-modules/core-java-io-5/.gitignore new file mode 100644 index 0000000000..0c0cd871c5 --- /dev/null +++ b/core-java-modules/core-java-io-5/.gitignore @@ -0,0 +1,2 @@ +test-link* +0.* \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/README.md b/core-java-modules/core-java-io-5/README.md new file mode 100644 index 0000000000..3cc514e087 --- /dev/null +++ b/core-java-modules/core-java-io-5/README.md @@ -0,0 +1,9 @@ +## Core Java IO + +This module contains articles about core Java input and output (IO) + +### Relevant Articles: +- [Get File Extension From MIME Type in Java](https://www.baeldung.com/java-mime-type-file-extension) +- [How to Remove Line Breaks From a File in Java](https://www.baeldung.com/java-file-remove-line-breaks) +- [[<-- Prev]](/core-java-modules/core-java-io-4) + diff --git a/core-java-modules/core-java-io-5/pom.xml b/core-java-modules/core-java-io-5/pom.xml new file mode 100644 index 0000000000..5c987a82e1 --- /dev/null +++ b/core-java-modules/core-java-io-5/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + core-java-io-5 + core-java-io-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.tika + tika-core + ${tika.version} + + + net.sf.jmimemagic + jmimemagic + ${jmime-magic.version} + + + org.jodd + jodd-util + ${jodd-util.version} + + + com.j256.simplemagic + simplemagic + ${simplemagic.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + core-java-io-5 + + + src/main/resources + true + + + + + maven-compiler-plugin + + 11 + 11 + + + + + + + + 2.8.0 + 0.1.5 + 6.2.1 + 1.17 + 1.37 + + \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipBenchmark.java b/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipBenchmark.java new file mode 100644 index 0000000000..30ec1522a2 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipBenchmark.java @@ -0,0 +1,112 @@ +package com.baeldung.zip; + +import java.io.*; +import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.zip.*; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 1, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 1) +public class ZipBenchmark { + + public static final int NUM_OF_FILES = 10; + public static final int DATA_SIZE = 204800; + + @State(Scope.Thread) + public static class SourceState { + + public File compressedFile; + + @Setup(Level.Trial) + public void setup() throws IOException { + ZipSampleFileStore sampleFileStore = new ZipSampleFileStore(NUM_OF_FILES, DATA_SIZE); + compressedFile = sampleFileStore.getFile(); + } + + @TearDown(Level.Trial) + public void cleanup() { + if (compressedFile.exists()) { + compressedFile.delete(); + } + } + } + + @Benchmark + public static void readAllEntriesByZipFile(SourceState sourceState, Blackhole blackhole) throws IOException { + + try (ZipFile zipFile = new ZipFile(sourceState.compressedFile)) { + Enumeration zipEntries = zipFile.entries(); + while (zipEntries.hasMoreElements()) { + ZipEntry zipEntry = zipEntries.nextElement(); + try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) { + blackhole.consume(ZipSampleFileStore.getString(inputStream)); + } + } + } + } + + @Benchmark + public static void readAllEntriesByZipInputStream(SourceState sourceState, Blackhole blackhole) throws IOException { + + try ( + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceState.compressedFile)); + ZipInputStream zipInputStream = new ZipInputStream(bis) + ) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + blackhole.consume(ZipSampleFileStore.getString(zipInputStream)); + } + } + } + + @Benchmark + public static void readLastEntryByZipFile(SourceState sourceState, Blackhole blackhole) throws IOException { + + try (ZipFile zipFile = new ZipFile(sourceState.compressedFile)) { + ZipEntry zipEntry = zipFile.getEntry(getLastEntryName()); + try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) { + blackhole.consume(ZipSampleFileStore.getString(inputStream)); + } + } + } + + @Benchmark + public static void readLastEntryByZipInputStream(SourceState sourceState, Blackhole blackhole) throws IOException { + + try ( + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceState.compressedFile)); + ZipInputStream zipInputStream = new ZipInputStream(bis) + ) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + if (Objects.equals(entry.getName(), getLastEntryName())){ + blackhole.consume(ZipSampleFileStore.getString(zipInputStream)); + } + } + } + } + + private static String getLastEntryName() { + return String.format(ZipSampleFileStore.ENTRY_NAME_PATTERN, NUM_OF_FILES); + } + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(ZipBenchmark.class.getSimpleName()).threads(1) + .shouldFailOnError(true) + .shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipSampleFileStore.java b/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipSampleFileStore.java new file mode 100644 index 0000000000..389f082ff1 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/main/java/com/baeldung/zip/ZipSampleFileStore.java @@ -0,0 +1,70 @@ +package com.baeldung.zip; + +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.io.IOUtils; + +public class ZipSampleFileStore { + + public static final String ENTRY_NAME_PATTERN = "str-data-%s.txt"; + private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; + + private final File file; + private final List dataList; + + public ZipSampleFileStore(int numOfFiles, int fileSize) throws IOException { + + dataList = new ArrayList<>(numOfFiles); + file = File.createTempFile("zip-sample", ""); + + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file))) { + + for (int idx=0; idx<=numOfFiles; idx++) { + + byte[] data = createRandomStringInByte(fileSize); + dataList.add(new String(data, DEFAULT_ENCODING)); + + ZipEntry entry = new ZipEntry(String.format(ENTRY_NAME_PATTERN, idx)); + zos.putNextEntry(entry); + zos.write(data); + zos.closeEntry(); + } + } + } + + public static byte[] createRandomStringInByte(int size) { + Random random = new Random(); + byte[] data = new byte[size]; + for (int n = 0; n < data.length; n++) { + char randomChar; + int choice = random.nextInt(2); // 0 for uppercase, 1 for lowercase + if (choice == 0) { + randomChar = (char) ('A' + random.nextInt(26)); // 'A' to 'Z' + } else { + randomChar = (char) ('a' + random.nextInt(26)); // 'a' to 'z' + } + data[n] = (byte) randomChar; + } + return data; + } + + public File getFile() { + return file; + } + + public List getDataList() { + return dataList; + } + + public static String getString(InputStream inputStream) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + IOUtils.copy(inputStream, byteArrayOutputStream); + return byteArrayOutputStream.toString(DEFAULT_ENCODING); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java new file mode 100644 index 0000000000..6b1fd490a8 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.extension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tika.mime.MimeTypeException; +import com.j256.simplemagic.ContentType; +import org.junit.Test; + +public class ExtensionFromMimeTypeUnitTest { + private static final String IMAGE_JPEG_MIME_TYPE = "image/jpeg"; + @Test + public void whenUsingTika_thenGetFileExtension() throws MimeTypeException { + List expectedExtensions = Arrays.asList(".jpg", ".jpeg", ".jpe", ".jif", ".jfif", ".jfi"); + org.apache.tika.mime.MimeTypes allTypes = org.apache.tika.mime.MimeTypes.getDefaultMimeTypes(); + org.apache.tika.mime.MimeType type = allTypes.forName(IMAGE_JPEG_MIME_TYPE); + String primaryExtension = type.getExtension(); + assertEquals(".jpg", primaryExtension); + List detectedExtensions = type.getExtensions(); + assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); + } + + @Test + public void whenUsingJodd_thenGetFileExtension() { + List expectedExtensions = Arrays.asList("jpeg", "jpg", "jpe"); + String[] detectedExtensions = jodd.net.MimeTypes.findExtensionsByMimeTypes(IMAGE_JPEG_MIME_TYPE, false); + assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); + } + + @Test + public void whenUsingSimpleMagic_thenGetFileExtension() { + List expectedExtensions = Arrays.asList("jpeg", "jpg", "jpe"); + String[] detectedExtensions = ContentType.fromMimeType(IMAGE_JPEG_MIME_TYPE).getFileExtensions(); + assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); + } + + @Test + public void whenUsingCustomMap_thenGetFileExtension() { + Map> mimeExtensionsMap = new HashMap<>(); + List expectedExtensions = Arrays.asList(".jpg", ".jpe", ".jpeg"); + addMimeExtensions(mimeExtensionsMap, "image/jpeg", ".jpg"); + addMimeExtensions(mimeExtensionsMap, "image/jpeg", ".jpe"); + addMimeExtensions(mimeExtensionsMap, "image/jpeg", ".jpeg"); + + Set detectedExtensions = mimeExtensionsMap.get(IMAGE_JPEG_MIME_TYPE); + assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); + } + + private void addMimeExtensions(Map> map, String mimeType, String extension) { + map.computeIfAbsent(mimeType, k -> new HashSet<>()).add(extension); + } +} diff --git a/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java new file mode 100644 index 0000000000..7cfc7ede79 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.rmlinebreaks; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class RemoveLinebreaksUnitTest { + + private Path file1Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-1.txt").toURI()); + } + + private Path file2Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-2.txt").toURI()); + } + + @Test + void whenRemovingLineSeparatorFromFile1_thenGetTheExpectedResult() throws Exception { + String content = Files.readString(file1Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertEquals("A, B, C, D, E, F", result); + } + + @Test + void whenRemovingLineSeparatorFromFile2_thenNotGetTheExpectedResult() throws Exception { + String content = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertNotEquals("A, B, C, D, E, F", result); // <-- NOT equals assertion! + } + + @Test + void whenRemovingAllLinebreaks_thenGetTheExpectedResult() throws Exception { + String content1 = Files.readString(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + String content2 = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result1 = content1.replace("\r", "").replace("\n", ""); + String result2 = content2.replace("\r", "").replace("\n", ""); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + + String resultReplaceAll = content2.replaceAll("[\\n\\r]", ""); + assertEquals("A, B, C, D, E, F", resultReplaceAll); + + } + + @Test + void whenUsingReadAllLinesAndJoin_thenGetExpectedResult() throws Exception { + List lines1 = Files.readAllLines(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + List lines2 = Files.readAllLines(file2Path(), StandardCharsets.UTF_8); + + String result1 = String.join("", lines1); + String result2 = String.join("", lines2); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/test/java/com/baeldung/zip/ZipUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/zip/ZipUnitTest.java new file mode 100644 index 0000000000..1d4d76dc41 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/zip/ZipUnitTest.java @@ -0,0 +1,83 @@ +package com.baeldung.zip; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +import org.junit.*; + +public class ZipUnitTest { + + private static File compressedFile; + private static List dataList = new ArrayList<>(); + + @BeforeClass + public static void prepareData() throws IOException { + ZipSampleFileStore sampleFileStore = new ZipSampleFileStore(ZipBenchmark.NUM_OF_FILES, ZipBenchmark.DATA_SIZE); + compressedFile = sampleFileStore.getFile(); + dataList = sampleFileStore.getDataList(); + } + + @Test + public void whenCreateZipFile_thenCompressedSizeShouldBeLessThanOriginal() throws IOException { + byte[] data = ZipSampleFileStore.createRandomStringInByte(10240); + File file = File.createTempFile("zip-temp", ""); + + try ( + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); + ZipOutputStream zos = new ZipOutputStream(bos) + ) { + ZipEntry zipEntry = new ZipEntry("zip-entry.txt"); + zos.putNextEntry(zipEntry); + zos.write(data); + zos.closeEntry(); + + assertThat(file.length()).isLessThan(data.length); + } + finally { + file.delete(); + } + } + + @Test + public void whenReadAllEntriesViaZipFile_thenDataIsEqualtoTheSource() throws IOException { + + try (ZipFile zipFile = new ZipFile(compressedFile)) { + Enumeration entries = zipFile.entries(); + List entryList = Collections.list(entries); + + for (int idx=0; idx]](/core-java-modules/core-java-io-2) diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index a59ac619bd..faeddafd81 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -38,9 +38,9 @@ ${fscontext.version} - javax.activation - activation - 1.1 + org.eclipse.angus + angus-activation + ${angus-activation.version} test @@ -54,6 +54,13 @@ + + maven-compiler-plugin + + 11 + 11 + + org.codehaus.mojo exec-maven-plugin @@ -73,10 +80,6 @@ org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - @@ -131,13 +134,14 @@ - 3.0.0-M1 - 2.4.0 + 3.5.0 + 2.7.1 - 1.18 + 2.8.0 0.1.5 - 3.1.0 4.4.2 + 2.1.2 + 2.0.1 \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/main/java/com/baeldung/sizebenchmark/FileSizeBenchmark.java b/core-java-modules/core-java-io/src/main/java/com/baeldung/sizebenchmark/FileSizeBenchmark.java new file mode 100644 index 0000000000..5998b0be73 --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/baeldung/sizebenchmark/FileSizeBenchmark.java @@ -0,0 +1,67 @@ +package com.baeldung.sizebenchmark; + +import org.apache.commons.io.FileUtils; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 3, time = 10, timeUnit = TimeUnit.NANOSECONDS) +@Measurement(iterations = 3, time = 10, timeUnit = TimeUnit.NANOSECONDS) +public class FileSizeBenchmark { + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @Benchmark + public void getFileSizeUsingLengthMethod(Blackhole blackhole) throws Exception { + File file = new File("src/test/resources/size/sample_file_1.in"); + blackhole.consume(file.length()); + } + + @Benchmark + public void getFileSizeUsingFileInputStream(Blackhole blackhole) throws Exception { + try (FileInputStream fis = new FileInputStream("src/test/resources/size/sample_file_1.in")) { + long result = fis.getChannel().size(); + blackhole.consume(result); + } + + } + + @Benchmark + public void getFileSizeUsingInputStreamAndUrl(Blackhole blackhole) throws Exception { + File me = new File("src/test/resources/size/sample_file_1.in"); + URL url = me.toURI().toURL(); + + try (InputStream stream = url.openStream()) { + blackhole.consume(stream.available()); + } + } + + @Benchmark + public void getFileSizeUsingApacheCommon(Blackhole blackhole) { + File imageFile = new File("src/test/resources/size/sample_file_1.in"); + long size = FileUtils.sizeOf(imageFile); + blackhole.consume(size); + } + + @Benchmark + public void getFileSizeUsingFileChannel(Blackhole blackhole) throws IOException { + Path imageFilePath = Paths.get("src/test/resources/size/sample_file_1.in"); + try (FileChannel imageFileChannel = FileChannel.open(imageFilePath)) { + long imageFileSize = imageFileChannel.size(); + blackhole.consume(imageFileSize); + } + } +} diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/close/StreamCloseUnitTest.java b/core-java-modules/core-java-io/src/test/java/com/baeldung/close/StreamCloseUnitTest.java new file mode 100644 index 0000000000..aa462ba984 --- /dev/null +++ b/core-java-modules/core-java-io/src/test/java/com/baeldung/close/StreamCloseUnitTest.java @@ -0,0 +1,118 @@ +package com.baeldung.close; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.*; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.AutoCloseInputStream; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.class) +public class StreamCloseUnitTest { + + private static final Logger log = LoggerFactory.getLogger(StreamCloseUnitTest.class); + + @Mock + private OutputStream wrappedOutputStream; + + @Mock + private InputStream wrappedInputStream; + + @Test + public void whenStreamClosedByFinally_thenIOStreamsCloseCalled() throws IOException { + + InputStream inputStream = null; + OutputStream outputStream = null; + + try { + inputStream = new BufferedInputStream(wrappedInputStream); + outputStream = new BufferedOutputStream(wrappedOutputStream); + } + finally { + try { + if (inputStream != null) + inputStream.close(); + } + catch (IOException ioe1) { + log.error("Cannot close InputStream"); + } + try { + if (outputStream != null) + outputStream.close(); + } + catch (IOException ioe2) { + log.error("Cannot close OutputStream"); + } + } + + verify(wrappedInputStream).close(); + verify(wrappedOutputStream).close(); + } + + @Test + public void whenStreamClosedByCloseQuietly_thenIOStreamsCloseCalled() throws IOException { + + InputStream inputStream = null; + OutputStream outputStream = null; + + try { + inputStream = new BufferedInputStream(wrappedInputStream); + outputStream = new BufferedOutputStream(wrappedOutputStream); + } + finally { + IOUtils.closeQuietly(inputStream); + IOUtils.closeQuietly(outputStream); + } + + verify(wrappedInputStream).close(); + verify(wrappedOutputStream).close(); + } + + @Test + public void whenFinishReadOnAutoCloseInputStream_thenInputStreamsCloseCalled() throws IOException { + + // Mimic no more data in the InputStream + when(wrappedInputStream.read(any(byte[].class))).thenReturn(-1); + + InputStream inputStream = AutoCloseInputStream.builder().setInputStream(wrappedInputStream).get(); + + byte[] buffer = new byte[256]; + while (inputStream.read(buffer) != -1) { + } + + verify(wrappedInputStream).close(); + } + + @Test + public void whenStreamClosedByWithResources_thenIOStreamsCloseCalled() throws IOException { + + try (BufferedInputStream inputStream = new BufferedInputStream(wrappedInputStream); + BufferedOutputStream outputStream = new BufferedOutputStream(wrappedOutputStream)) { + } + + verify(wrappedInputStream).close(); + verify(wrappedOutputStream).close(); + } + + @Test + public void whenStreamClosedByWithResourcesJava9_thenIOStreamsCloseCalled() throws IOException { + + InputStream inputStream = new BufferedInputStream(wrappedInputStream); + OutputStream outputStream = new BufferedOutputStream(wrappedOutputStream); + + try (inputStream; outputStream) { + } + + verify(wrappedInputStream).close(); + verify(wrappedOutputStream).close(); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java index bf916e39e7..4c382d07a6 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java +++ b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java @@ -10,7 +10,7 @@ import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; -import javax.activation.MimetypesFileTypeMap; +import jakarta.activation.MimetypesFileTypeMap; import org.apache.tika.Tika; import org.junit.Test; diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/size/JavaFileSizeUnitTest.java b/core-java-modules/core-java-io/src/test/java/com/baeldung/size/JavaFileSizeUnitTest.java index 6b6197c7ce..d015f2602e 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/size/JavaFileSizeUnitTest.java +++ b/core-java-modules/core-java-io/src/test/java/com/baeldung/size/JavaFileSizeUnitTest.java @@ -3,7 +3,10 @@ package com.baeldung.size; import static org.junit.Assert.assertEquals; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.Paths; @@ -62,4 +65,24 @@ public class JavaFileSizeUnitTest { final long length = file.length(); return length; } + + @Test + public void whenGetFileSizeUsingFileInputStream_thenCorrect() throws IOException { + + try (FileInputStream fis = new FileInputStream(filePath)) { + long result = fis.getChannel().size(); + assertEquals(EXPECTED_FILE_SIZE_IN_BYTES, result); + } + } + + @Test + public void whenGetFileSizeUsingUrlAndInputStream_thenCorrect() throws IOException { + + File file = new File(filePath); + URL url = file.toURI().toURL(); + + try (InputStream stream = url.openStream()) { + assertEquals(EXPECTED_FILE_SIZE_IN_BYTES, stream.available()); + } + } } \ No newline at end of file diff --git a/core-java-modules/core-java-jar/pom.xml b/core-java-modules/core-java-jar/pom.xml index ec88abe444..a46299c669 100644 --- a/core-java-modules/core-java-jar/pom.xml +++ b/core-java-modules/core-java-jar/pom.xml @@ -275,7 +275,6 @@ 1.1 3.0.0-M1 - 3.0.2 1.4.4 3.1.1 3.3.0 diff --git a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java index 707ce79624..fc40aa01c5 100644 --- a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java +++ b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java @@ -3,10 +3,14 @@ package com.baeldung.jar; import org.junit.Assert; import org.junit.jupiter.api.Test; +import java.util.regex.Pattern; + public class JarAppUnitTest { @Test public void findClassTest(){ - Assert.assertTrue(JarApp.findObjectMapperClass().endsWith("jackson-databind-2.13.3.jar")); + Pattern databindPattern = Pattern.compile(".*jackson-databind-(\\d)+\\.(\\d)+\\.(\\d)\\.jar$"); + + Assert.assertTrue(databindPattern.matcher(JarApp.findObjectMapperClass()).matches()); } } diff --git a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppnUnitTest.java b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppManualTest.java similarity index 69% rename from core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppnUnitTest.java rename to core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppManualTest.java index 106531008c..240c5be58d 100644 --- a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppnUnitTest.java +++ b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/MySampleGUIAppManualTest.java @@ -1,15 +1,15 @@ package com.baeldung.jar; -import java.io.IOException; - import org.junit.jupiter.api.Test; -class MySampleGUIAppnUnitTest { +class MySampleGUIAppManualTest { + @Test - void testMain() throws IOException { + void testMain() { System.setProperty("java.awt.headless", "true"); String [] args = null; System.exit(0); MySampleGUIAppn.main(args); } + } \ No newline at end of file diff --git a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiNamingUnitTest.java b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiNamingUnitTest.java new file mode 100644 index 0000000000..66d8d57d4e --- /dev/null +++ b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiNamingUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.jndi; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jndi.JndiTemplate; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +import javax.naming.*; +import javax.sql.DataSource; + +import java.util.Enumeration; + +import static org.junit.jupiter.api.Assertions.*; + +class JndiNamingUnitTest { + + private static InitialContext context; + private static DriverManagerDataSource dataSource; + + @BeforeAll + static void setUp() throws Exception { + SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); + dataSource = new DriverManagerDataSource("jdbc:h2:mem:mydb"); + builder.activate(); + + JndiTemplate jndiTemplate = new JndiTemplate(); + context = (InitialContext) jndiTemplate.getContext(); + + dataSource.setDriverClassName("org.h2.Driver"); + context.bind("java:comp/env/jdbc/datasource", dataSource); + } + + @Test + void givenACompositeName_whenAddingAnElement_thenNameIsAdded() throws Exception { + Name objectName = new CompositeName("java:comp/env/jdbc"); + + Enumeration items = objectName.getAll(); + while(items.hasMoreElements()) { + System.out.println(items.nextElement()); + } + + objectName.add("New Name"); + + assertEquals("env", objectName.get(1)); + assertEquals("New Name", objectName.get(objectName.size() - 1)); + } + + @Test + void givenContext_whenLookupByName_thenReturnsValidObject() throws Exception { + DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/datasource"); + + assertNotNull(ds); + assertNotNull(ds.getConnection()); + } + + @Test + void givenSubContext_whenLookupByName_thenReturnsValidObject() throws Exception { + Context subContext = (Context) context.lookup("java:comp/env"); + DataSource ds = (DataSource) subContext.lookup("jdbc/datasource"); + + assertNotNull(ds); + assertNotNull(ds.getConnection()); + } + + @AfterAll + static void tearDown() throws Exception { + context.close(); + } + +} diff --git a/core-java-modules/core-java-lang-6/README.md b/core-java-modules/core-java-lang-6/README.md index 515e29bedd..91c0e5212c 100644 --- a/core-java-modules/core-java-lang-6/README.md +++ b/core-java-modules/core-java-lang-6/README.md @@ -6,3 +6,6 @@ This module contains articles about core features in the Java language - [Convert One Enum to Another Enum in Java](https://www.baeldung.com/java-convert-enums) - [What Is the Maximum Depth of the Java Call Stack?](https://www.baeldung.com/java-call-stack-max-depth) +- [Get a Random Element From a Set in Java](https://www.baeldung.com/java-set-draw-sample) +- [Stop Executing Further Code in Java](https://www.baeldung.com/java-stop-running-code) +- [Using the Apache Commons Lang 3 for Comparing Objects in Java](https://www.baeldung.com/java-apache-commons-lang-3-compare-objects) diff --git a/core-java-modules/core-java-lang-6/pom.xml b/core-java-modules/core-java-lang-6/pom.xml index 86121e0a7f..6561c4fdcc 100644 --- a/core-java-modules/core-java-lang-6/pom.xml +++ b/core-java-modules/core-java-lang-6/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.core-java-modules @@ -18,7 +18,11 @@ mapstruct ${mapstruct.version} - + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java new file mode 100644 index 0000000000..e82a1018ce --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java @@ -0,0 +1,47 @@ +package com.baeldung.compareobjects; + +import java.util.Objects; + +public class Address { + private String streetAddress; + private String city; + private String postalCode; + + public Address(String streetAddress, String city, String postalCode) { + this.streetAddress = streetAddress; + this.city = city; + this.postalCode = postalCode; + } + + public String getStreetAddress() { + return streetAddress; + } + + public String getCity() { + return city; + } + + public String getPostalCode() { + return postalCode; + } + + @Override + public String toString() { + return "Address{" + "streetAddress='" + streetAddress + '\'' + ", city='" + city + '\'' + ", postalCode='" + postalCode + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Address address = (Address) o; + return Objects.equals(streetAddress, address.streetAddress) && Objects.equals(city, address.city) && Objects.equals(postalCode, address.postalCode); + } + + @Override + public int hashCode() { + return Objects.hash(streetAddress, city, postalCode); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java new file mode 100644 index 0000000000..6ba244ff17 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java @@ -0,0 +1,58 @@ +package com.baeldung.compareobjects; + +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.builder.DiffExclude; + +public class Person { + private String firstName; + private String lastName; + private int age; + private List phoneNumbers; + @DiffExclude + private Address address; + + public Person(String firstName, String lastName, int age, List phoneNumbers, Address address) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.phoneNumbers = phoneNumbers; + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public int getAge() { + return age; + } + + public List getPhoneNumbers() { + return phoneNumbers; + } + + public Address getAddress() { + return address; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Person person = (Person) o; + return age == person.age && Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName) && Objects.equals(phoneNumbers, person.phoneNumbers) && Objects.equals(address, person.address); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, age, phoneNumbers, address); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java new file mode 100644 index 0000000000..9e21f5d7c3 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java @@ -0,0 +1,32 @@ +package com.baeldung.compareobjects; + +import org.apache.commons.lang3.builder.DiffBuilder; +import org.apache.commons.lang3.builder.DiffResult; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class PersonDiffBuilder { + public static DiffResult compare(Person first, Person second) { + DiffBuilder diffBuilder = new DiffBuilder(first, second, ToStringStyle.DEFAULT_STYLE).append("person", first.getFirstName(), second.getFirstName()) + .append("lastName", first.getLastName(), second.getLastName()) + .append("streetAddress", first.getAddress() + .getStreetAddress(), second.getAddress() + .getStreetAddress()) + .append("city", first.getAddress() + .getCity(), second.getAddress() + .getCity()) + .append("postalCode", first.getAddress() + .getPostalCode(), second.getAddress() + .getPostalCode()) + .append("age", first.getAge(), second.getAge()); + + for (int i = 0; i < first.getPhoneNumbers() + .size(); i++) { + diffBuilder.append("phoneNumbers[" + i + "].number", first.getPhoneNumbers() + .get(i) + .getNumber(), second.getPhoneNumbers() + .get(i) + .getNumber()); + } + return diffBuilder.build(); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java new file mode 100644 index 0000000000..82081e7282 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java @@ -0,0 +1,11 @@ +package com.baeldung.compareobjects; + +import org.apache.commons.lang3.builder.DiffResult; +import org.apache.commons.lang3.builder.ReflectionDiffBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class PersonReflectionDiffBuilder { + public static DiffResult compare(Person first, Person second) { + return new ReflectionDiffBuilder<>(first, second, ToStringStyle.SHORT_PREFIX_STYLE).build(); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java new file mode 100644 index 0000000000..4ab2b4a4bd --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java @@ -0,0 +1,43 @@ +package com.baeldung.compareobjects; + +import java.util.Objects; + +import org.apache.commons.lang3.builder.DiffExclude; + +public class PhoneNumber { + private String type; + private String number; + + public PhoneNumber(String type, String number) { + this.type = type; + this.number = number; + } + + public String getType() { + return type; + } + + public String getNumber() { + return number; + } + + @Override + public String toString() { + return "PhoneNumber{" + "type='" + type + '\'' + ", number='" + number + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + PhoneNumber that = (PhoneNumber) o; + return Objects.equals(number, that.number); + } + + @Override + public int hashCode() { + return Objects.hash(number); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java new file mode 100644 index 0000000000..5b203db515 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java @@ -0,0 +1,50 @@ +package com.baeldung.randominset; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class RandomInSetUtil { + + public static T getByRandomClass(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = new Random().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static T getByThreadLocalRandom(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = ThreadLocalRandom.current().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static void main(String[] args) { + Set animals = new HashSet<>(); + animals.add("Lion"); + animals.add("Elephant"); + animals.add("Giraffe"); + + String randomAnimal = getByThreadLocalRandom(animals); + System.out.println("Randomly picked animal: " + randomAnimal); + } + +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/InterruptThread.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/InterruptThread.java new file mode 100644 index 0000000000..7964ad9f52 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/InterruptThread.java @@ -0,0 +1,13 @@ +package com.baeldung.stopexecution; + +public class InterruptThread extends Thread { + @Override + public void run() { + while (!isInterrupted()) { + if (isInterrupted()) { + break; + } + // business logic + } + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/StopExecutionFurtherCode.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/StopExecutionFurtherCode.java new file mode 100644 index 0000000000..81abe15b5c --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/stopexecution/StopExecutionFurtherCode.java @@ -0,0 +1,87 @@ +package com.baeldung.stopexecution; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; + +public class StopExecutionFurtherCode { + + boolean shouldContinue = true; + + int performTask(int a, int b) { + if (!shouldContinue) { + System.exit(0); + } + return a + b; + } + + void stop() { + this.shouldContinue = false; + } + + int calculateFactorial(int n) { + if (n <= 1) { + return 1; // base case + } + + return n * calculateFactorial(n - 1); + } + + int calculateSum(int[] x) { + int sum = 0; + for (int i = 0; i < 10; i++) { + if (x[i] < 0) { + break; + } + sum += x[i]; + } + return sum; + } + + T stopExecutionUsingException(T object) { + if (object instanceof Number) { + throw new IllegalArgumentException("Parameter can not be number."); + } + T upperCase = (T) String.valueOf(object) + .toUpperCase(Locale.ENGLISH); + return upperCase; + } + + int processLines(String[] lines) { + int statusCode = 0; + parser: + for (String line : lines) { + System.out.println("Processing line: " + line); + if (line.equals("stop")) { + System.out.println("Stopping parsing..."); + statusCode = -1; + break parser; // Stop parsing and exit the loop + } + System.out.println("Line processed."); + } + return statusCode; + } + + void download(String fileUrl, String destinationPath) throws MalformedURLException { + if (fileUrl == null || fileUrl.isEmpty() || destinationPath == null || destinationPath.isEmpty()) { + return; + } + // execute downloading + URL url = new URL(fileUrl); + try (InputStream in = url.openStream(); FileOutputStream out = new FileOutputStream(destinationPath)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java new file mode 100644 index 0000000000..417e9da0ea --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.compareobjects; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.Diff; +import org.apache.commons.lang3.builder.DiffResult; +import org.junit.jupiter.api.Test; + +public class PersonDiffBuilderUnitTest { + + @Test + void givenTwoPeopleDifferent_whenComparingWithDiffBuilder_thenDifferencesFound() { + List phoneNumbers1 = new ArrayList<>(); + phoneNumbers1.add(new PhoneNumber("home", "123-456-7890")); + phoneNumbers1.add(new PhoneNumber("work", "987-654-3210")); + + List phoneNumbers2 = new ArrayList<>(); + phoneNumbers2.add(new PhoneNumber("mobile1", "123-456-7890")); + phoneNumbers2.add(new PhoneNumber("mobile2", "987-654-3210")); + + Address address1 = new Address("123 Main St", "London", "12345"); + Address address2 = new Address("123 Main St", "Paris", "54321"); + + Person person1 = new Person("John", "Doe", 30, phoneNumbers1, address1); + Person person2 = new Person("Jane", "Smith", 28, phoneNumbers2, address2); + + DiffResult diff = PersonDiffBuilder.compare(person1, person2); + for (Diff d : diff.getDiffs()) { + System.out.println(d.getFieldName() + ": " + d.getLeft() + " != " + d.getRight()); + } + + assertFalse(diff.getDiffs() + .isEmpty()); + } +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java new file mode 100644 index 0000000000..fffa56dccc --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.compareobjects; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.Diff; +import org.apache.commons.lang3.builder.DiffResult; +import org.junit.jupiter.api.Test; + +public class PersonReflectionDiffBuilderUnitTest { + @Test + void givenTwoPeopleDifferent_whenComparingWithReflectionDiffBuilder_thenDifferencesFound() { + List phoneNumbers1 = new ArrayList<>(); + phoneNumbers1.add(new PhoneNumber("home", "123-456-7890")); + phoneNumbers1.add(new PhoneNumber("work", "987-654-3210")); + + List phoneNumbers2 = new ArrayList<>(); + phoneNumbers2.add(new PhoneNumber("mobile1", "123-456-7890")); + phoneNumbers2.add(new PhoneNumber("mobile2", "987-654-3210")); + + Address address1 = new Address("123 Main St", "London", "12345"); + Address address2 = new Address("123 Main St", "Paris", "54321"); + + Person person1 = new Person("John", "Doe", 30, phoneNumbers1, address1); + Person person2 = new Person("Jane", "Smith", 28, phoneNumbers2, address2); + + DiffResult diff = PersonReflectionDiffBuilder.compare(person1, person2); + for (Diff d : diff.getDiffs()) { + System.out.println(d.getFieldName() + ": " + d.getLeft() + " != " + d.getRight()); + } + + assertFalse(diff.getDiffs() + .isEmpty()); + } +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/stopexecution/StopExecutionFurtherCodeUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/stopexecution/StopExecutionFurtherCodeUnitTest.java new file mode 100644 index 0000000000..9cdb1e71aa --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/stopexecution/StopExecutionFurtherCodeUnitTest.java @@ -0,0 +1,90 @@ +package com.baeldung.stopexecution; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.net.MalformedURLException; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.jupiter.api.Test; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class StopExecutionFurtherCodeUnitTest { + + + @Test + void givenExecution_whenStopIsNotCalled_thenTaskIsPerformed() { + StopExecutionFurtherCode stopExecution = new StopExecutionFurtherCode(); + int performedTask = stopExecution.performTask(10, 20); + Assert.assertEquals(30, performedTask); + } + + // This test case have been commented because, otherwise, the program will exit since System.exit(statusCode) is being used. + /*@Test + void givenExecution_whenStopIsCalled_thenTaskNotPerformed() { + StopExecutionFurtherCode stopExecution = new StopExecutionFurtherCode(); + stopExecution.stop(); + int performedTask = stopExecution.performTask(10, 20); + Assert.assertEquals(30, performedTask); + }*/ + + @Test + void givenWrongUrlAndPath_whenDownloadCalled_thenExecutionIsStopped() throws MalformedURLException { + StopExecutionFurtherCode stopExecutionFurtherCode = new StopExecutionFurtherCode(); + stopExecutionFurtherCode.download("", ""); + } + + @Test + void givenName_whenStopExecutionUsingExceptionCalled_thenNameIsConvertedToUpper() { + StopExecutionFurtherCode stopExecutionFurtherCode = new StopExecutionFurtherCode(); + String name = "John"; + String result1 = stopExecutionFurtherCode.stopExecutionUsingException(name); + Assert.assertEquals("JOHN", result1); + try { + Integer number1 = 10; + Assert.assertThrows(IllegalArgumentException.class, () -> { + int result = stopExecutionFurtherCode.stopExecutionUsingException(number1); + }); + } catch (Exception e) { + Assert.fail("Unexpected exception thrown: " + e.getMessage()); + } + } + + @Test + void givenBaseCase_whenStopExecutionWhenBaseCaseKnownCalled_thenFactorialIsCalculated() throws MalformedURLException { + StopExecutionFurtherCode stopExecutionFurtherCode = new StopExecutionFurtherCode(); + int factorial = stopExecutionFurtherCode.calculateFactorial(1); + Assert.assertEquals(1, factorial); + } + + @Test + void givenArrayWithNegative_whenStopExecutionInLoopCalled_thenSumIsCalculatedIgnoringNegatives() { + StopExecutionFurtherCode stopExecutionFurtherCode = new StopExecutionFurtherCode(); + int[] nums = { 1, 2, 3, -1, 1, 2, 3 }; + int sum = stopExecutionFurtherCode.calculateSum(nums); + Assert.assertEquals(6, sum); + } + + @Test + void givenThreadRunning_whenInterrupted_thenThreadExecutionIsStopped() throws InterruptedException { + InterruptThread stopExecution = new InterruptThread(); + stopExecution.start(); + Thread.sleep(2000); + stopExecution.interrupt(); + stopExecution.join(); + Assert.assertTrue(!stopExecution.isAlive()); + } + + @Test + void givenLinesWithStopLabel_whenStopExecutionLabeledLoopCalled_thenLoopExecutionIsStopped() { + StopExecutionFurtherCode furtherCode = new StopExecutionFurtherCode(); + final String[] lines = { "Line 1", "Line 2", "Line 3", "stop", "Line 4", "Line 5" }; + int statusCode = furtherCode.processLines(lines); + Assert.assertEquals(-1, statusCode); + } + +} diff --git a/core-java-modules/core-java-lang-math-3/README.md b/core-java-modules/core-java-lang-math-3/README.md index 847bd314a7..37027970b6 100644 --- a/core-java-modules/core-java-lang-math-3/README.md +++ b/core-java-modules/core-java-lang-math-3/README.md @@ -11,4 +11,6 @@ - [Java Program to Calculate the Standard Deviation](https://www.baeldung.com/java-calculate-standard-deviation) - [Java Program to Print Pascal’s Triangle](https://www.baeldung.com/java-pascal-triangle) - [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) +- [Clamp Function in Java](https://www.baeldung.com/java-clamp-function) +- [Creating a Magic Square in Java](https://www.baeldung.com/java-magic-square) - More articles: [[<-- Prev]](/core-java-modules/core-java-lang-math-2) diff --git a/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/clampfunction/Clamp.java b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/clampfunction/Clamp.java new file mode 100644 index 0000000000..4c62c0560e --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/clampfunction/Clamp.java @@ -0,0 +1,23 @@ +package com.baeldung.clampfunction; + +public class Clamp { + + public int clamp(int value, int min, int max) { + return Math.max(min, Math.min(max, value)); + } + + public double clamp(double value, double min, double max) { + return Math.max(min, Math.min(max, value)); + } + + public static > T clamp(T value, T min, T max) { + if (value.compareTo(min) < 0) { + return min; + } else if (value.compareTo(max) > 0) { + return max; + } else { + return value; + } + } + +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/clampfunction/ClampFunctionUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/clampfunction/ClampFunctionUnitTest.java new file mode 100644 index 0000000000..a8d40caee0 --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/clampfunction/ClampFunctionUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.clampfunction; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ClampFunctionUnitTest { + + Clamp clampValue = new Clamp(); + + @Test + public void givenValueOutsideRange_whenClamp_thenReturnLowerValue() { + assertEquals(15, clampValue.clamp(10, 15, 35)); + } + + @Test + public void givenValueWithinRange_whenClamp_thenReturnValue() { + assertEquals(20, clampValue.clamp(20, 15, 35)); + } + + @Test + public void givenValueOutsideRange_whenClamp_thenReturnMaximumValue() { + assertEquals(35, clampValue.clamp(50, 15, 35)); + } + + @Test + public void givenDoubleValueOutsideRange_whenClamp_thenReturnMaximumValue() { + assertEquals(60.5, clampValue.clamp(75.6, 25.5, 60.5)); + } + + /* + * This method uses the clamp() method introduced in Java 21 + @Test + public void givenValueWithinRange_whenClamp_thenReturnValue() { + assertEquals(20, Math.clamp(20, 17, 98)); + } + */ + +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java new file mode 100644 index 0000000000..f02200462e --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.magicsquare; + +import org.junit.jupiter.api.Test; + +public class GenerationUnitTest { + @Test + public void testGenerate3x3() { + MagicSquare magicSquare = new MagicSquare(3); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate9x9() { + MagicSquare magicSquare = new MagicSquare(9); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate12x12() { + MagicSquare magicSquare = new MagicSquare(12); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate10x10() { + MagicSquare magicSquare = new MagicSquare(10); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate18x18() { + MagicSquare magicSquare = new MagicSquare(18); + System.out.println(magicSquare); + + magicSquare.validate(); + } +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java new file mode 100644 index 0000000000..f2ddd65ff7 --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java @@ -0,0 +1,186 @@ +package com.baeldung.magicsquare; + +import java.util.stream.IntStream; + +public class MagicSquare { + private int[][] cells; + + public MagicSquare(int n) { + this.cells = new int[n][]; + + for (int i = 0; i < n; ++i) { + this.cells[i] = new int[n]; + } + + if (n % 2 == 1) { + populateOdd(); + } else if (n % 4 == 0) { + populateDoubleEven(); + } else if (n >= 6) { + populateSingleEven(); + } + } + + private void populateOdd() { + int n = getN(); + + populateOddArea(0, 0, n, 0); + } + + private void populateOddArea(int xOffset, int yOffset, int n, int numberOffset) { + int y = 0; + int x = (n - 1) / 2; + setCell(xOffset + x, yOffset + y, numberOffset + 1); + + for (int number = 2; number <= n * n; ++number) { + int nextX = x + 1; + if (nextX == n) { + nextX = 0; + } + + int nextY = y - 1; + if (nextY == -1) { + nextY = n - 1; + } + + if (getCell(xOffset + nextX, yOffset + nextY) != 0) { + nextX = x; + + nextY = y + 1; + if (nextY == n) { + nextY = 0; + } + } + + setCell(xOffset + nextX, yOffset + nextY, numberOffset + number); + + x = nextX; + y = nextY; + } + } + + private void populateDoubleEven() { + int n = getN(); + int number = 1; + + for (int y = 0; y < n; ++y) { + for (int x = 0; x < n; ++x) { + boolean highlighted = false; + + if ((y < n/4 || y >= 3*n/4) && (x >= n/4 && x < 3*n/4)) { + highlighted = true; + } else if ((x < n/4 || x >= 3*n/4) && (y >= n/4 && y < 3*n/4)) { + highlighted = true; + } + + if (highlighted) { + setCell(x, y, (n * n) - number + 1); + } else { + setCell(x, y, number); + } + + number += 1; + } + } + } + + private void populateSingleEven() { + int n = getN(); + int halfN = n/2; + int swapSize = (int) n/4; + + populateOddArea(0, 0, halfN, 0); + populateOddArea(halfN, halfN, halfN, halfN * halfN); + populateOddArea(halfN, 0, halfN, (halfN * halfN) * 2); + populateOddArea(0, halfN, halfN, (halfN * halfN) * 3); + + for (int x = 0; x < swapSize; ++x) { + swapCells(x, 0, x, halfN); + swapCells(x, halfN - 1, x, n - 1); + + for (int y = 1; y < halfN - 1; ++y) { + swapCells(x + 1, y, x + 1, y + halfN); + } + } + + for (int x = 0; x < swapSize - 1; ++x) { + for (int y = 0; y < halfN; ++y) { + swapCells(n - x - 1, y, n - x - 1, y + halfN); + } + } + + } + + private void swapCells(int x1, int y1, int x2, int y2) { + int cell1 = getCell(x1, y1); + int cell2 = getCell(x2, y2); + + setCell(x1, y1, cell2); + setCell(x2, y2, cell1); + } + + public int getN() { + return cells.length; + } + + public int getCell(int x, int y) { + return cells[x][y]; + } + + public void setCell(int x, int y, int value) { + cells[x][y] = value; + } + + public void validate() { + int n = getN(); + int expectedValue = ((n * n * n) + n) / 2; + + // Diagonals + if (IntStream.range(0, n).map(i -> getCell(i, i)).sum() != expectedValue) { + throw new IllegalStateException("Leading diagonal is not the expected value"); + } + if (IntStream.range(0, n).map(i -> getCell(i, n - i - 1)).sum() != expectedValue) { + throw new IllegalStateException("Trailing diagonal is not the expected value"); + } + + // Rows + IntStream.range(0, n).forEach(y -> { + if (IntStream.range(0, n).map(x -> getCell(x, y)).sum() != expectedValue) { + throw new IllegalStateException("Row is not the expected value"); + } + }); + + // Cols + IntStream.range(0, n).forEach(x -> { + if (IntStream.range(0, n).map(y -> getCell(x, y)).sum() != expectedValue) { + throw new IllegalStateException("Column is not the expected value"); + } + }); + } + + public String toString() { + int n = getN(); + int largestNumberLength = Integer.toString(n * n).length(); + String formatString = " %0" + largestNumberLength + "d "; + + StringBuilder sb = new StringBuilder(); + + for (int y = 0; y < n; ++y) { + for (int x = 0; x < n; ++x) { + int value = getCell(x, y); + if (value == 0) { + sb.append(" "); + for (int i = 0; i < largestNumberLength; ++i) { + sb.append("."); + } + sb.append(" "); + } else { + sb.append(String.format(formatString, value)); + } + } + sb.append("\n"); + } + + return sb.toString(); + } +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java new file mode 100644 index 0000000000..6b0ec600bb --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.magicsquare; + +import org.junit.jupiter.api.Test; + +public class ValidationUnitTest { + @Test + public void testValidate3x3() { + MagicSquare magicSquare = new MagicSquare(3); + magicSquare.setCell(0, 0, 8); + magicSquare.setCell(1, 0, 1); + magicSquare.setCell(2, 0, 6); + magicSquare.setCell(0, 1, 3); + magicSquare.setCell(1, 1, 5); + magicSquare.setCell(2, 1, 7); + magicSquare.setCell(0, 2, 4); + magicSquare.setCell(1, 2, 9); + magicSquare.setCell(2, 2, 2); + + magicSquare.validate(); + } +} diff --git a/core-java-modules/core-java-lang-oop-generics/README.md b/core-java-modules/core-java-lang-oop-generics/README.md index 720ba9dcfd..3e33ba5315 100644 --- a/core-java-modules/core-java-lang-oop-generics/README.md +++ b/core-java-modules/core-java-lang-oop-generics/README.md @@ -9,3 +9,4 @@ This module contains articles about generics in Java - [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens) - [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion) - [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast) +- [What Does the Holder Class Do in Java?](https://www.baeldung.com/java-holder-class) diff --git a/core-java-modules/core-java-lang-oop-inheritance/README.md b/core-java-modules/core-java-lang-oop-inheritance/README.md index c87bdf13d7..6091b15024 100644 --- a/core-java-modules/core-java-lang-oop-inheritance/README.md +++ b/core-java-modules/core-java-lang-oop-inheritance/README.md @@ -12,3 +12,4 @@ This module contains articles about inheritance in Java - [Guide to Inheritance in Java](https://www.baeldung.com/java-inheritance) - [Object Type Casting in Java](https://www.baeldung.com/java-type-casting) - [Variable and Method Hiding in Java](https://www.baeldung.com/java-variable-method-hiding) +- [Inner Classes vs. Subclasses in Java](https://www.baeldung.com/java-inner-classes-vs-subclasses) diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java new file mode 100644 index 0000000000..9f3e140926 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java @@ -0,0 +1,22 @@ +package com.baeldung.subclassinnerclass; + +public class EmailNotifier extends Notifier { + @Override + void notify(Message e) { + // connect to the email connector + EmailConnector emailConnector = new EmailConnector(); + emailConnector.connect(); + // send email + } + + // Inner class for email connection + static class EmailConnector { + private String emailHost; + private int emailPort; + // Getter Setters + + private void connect() { + // connect to the smtp server + } + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java new file mode 100644 index 0000000000..35d751b288 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java @@ -0,0 +1,6 @@ +package com.baeldung.subclassinnerclass; + +public class Message { + private int message; + // getter setter and other atteibutes +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java new file mode 100644 index 0000000000..2ebbbde961 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java @@ -0,0 +1,17 @@ +package com.baeldung.subclassinnerclass; + +public class NotificationService { + void notifyMessages() { + // Sending a Text Message + Message textMessage = new Message(); + Notifier textNotifier = new TextMessageNotifier(); + + textNotifier.notify(textMessage); + + // Sending an Email Message + Message emailMessage = new Message(); + Notifier emailNotifier = new EmailNotifier(); + + emailNotifier.notify(emailMessage); + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java new file mode 100644 index 0000000000..aff0372af3 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java @@ -0,0 +1,5 @@ +package com.baeldung.subclassinnerclass; + +public abstract class Notifier { + abstract void notify(Message e); +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java new file mode 100644 index 0000000000..8b64b4331d --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java @@ -0,0 +1,14 @@ +package com.baeldung.subclassinnerclass; + +public class TextMessageNotifier extends Notifier { + @Override + void notify(Message e) { + // Provide text message specific implementation here + } + + // Inner class for text message connection + private static class SMSConnector { + private String smsHost; + // Getter Setters + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java new file mode 100644 index 0000000000..27577a546f --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.subclassinnerclass; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; + +public class InnerClassUnitTest { + @Test + public void givenInnerStaticClassWhenInstantiatedThenOuterClassIsInstantiated() { + Notifier emailNotifier = new EmailNotifier(); + EmailNotifier.EmailConnector emailConnector = new EmailNotifier.EmailConnector(); + + assertThat(emailNotifier).hasSameClassAs(new EmailNotifier()); + assertThat(emailConnector).isInstanceOf(EmailNotifier.EmailConnector.class); + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java new file mode 100644 index 0000000000..25e6f5b8a4 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.subclassinnerclass; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; + +public class SubClassUnitTest { + @Test + public void givenSubclassWhenInstantiatedThenSubclassObjectIsPossible() { + Notifier emailNotifier = new EmailNotifier(); + assertThat(emailNotifier).hasSameClassAs(new EmailNotifier()); + assertThat(emailNotifier).isExactlyInstanceOf(EmailNotifier.class); + + Notifier textMessageNotifier = new TextMessageNotifier(); + assertThat(textMessageNotifier).isInstanceOf(Notifier.class); + assertThat(textMessageNotifier).isExactlyInstanceOf(TextMessageNotifier.class); + } +} diff --git a/core-java-modules/core-java-lang-oop-others/README.md b/core-java-modules/core-java-lang-oop-others/README.md index 09c1dadb8b..ffd1d47f79 100644 --- a/core-java-modules/core-java-lang-oop-others/README.md +++ b/core-java-modules/core-java-lang-oop-others/README.md @@ -8,3 +8,5 @@ This module contains articles about Object Oriented Programming (OOP) in Java - [Pass-By-Value as a Parameter Passing Mechanism in Java](https://www.baeldung.com/java-pass-by-value-or-pass-by-reference) - [Check If All the Variables of an Object Are Null](https://www.baeldung.com/java-check-all-variables-object-null) - [Law of Demeter in Java](https://www.baeldung.com/java-demeter-law) +- [Java Interface Naming Conventions](https://www.baeldung.com/java-interface-naming-conventions) +- [Difference Between Information Hiding and Encapsulation](https://www.baeldung.com/java-information-hiding-vs-encapsulation) diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/Book.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/Book.java new file mode 100644 index 0000000000..73762758e5 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/Book.java @@ -0,0 +1,7 @@ +package com.baeldung.encapsulation; + +public class Book { + public String author; + public int isbn; + +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookDetails.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookDetails.java new file mode 100644 index 0000000000..9df45b1f14 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookDetails.java @@ -0,0 +1,8 @@ +package com.baeldung.encapsulation; + +public class BookDetails { + + public String bookDetails(Book book) { + return "author name: " + book.author + " ISBN: " + book.isbn; + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookEncapsulation.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookEncapsulation.java new file mode 100644 index 0000000000..c39ca4bab4 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookEncapsulation.java @@ -0,0 +1,17 @@ +package com.baeldung.encapsulation; + +public class BookEncapsulation { + public String author; + public int isbn; + public int id = 1; + + public BookEncapsulation(String author, int isbn) { + this.author = author; + this.isbn = isbn; + } + + public String getBookDetails() { + return "author id: " + id + " author name: " + author + " ISBN: " + isbn; + } + +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookInformationHiding.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookInformationHiding.java new file mode 100644 index 0000000000..2d670a358d --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/encapsulation/BookInformationHiding.java @@ -0,0 +1,36 @@ +package com.baeldung.encapsulation; + +public class BookInformationHiding { + private String author; + private int isbn; + private int id = 1; + + public BookInformationHiding(String author, int isbn) { + setAuthor(author); + setIsbn(isbn); + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public int getIsbn() { + return isbn; + } + + public void setIsbn(int isbn) { + if (isbn < 0) { + throw new IllegalArgumentException("ISBN can't be negative"); + } + this.isbn = isbn; + } + + public String getBookDetails() { + return "author id: " + id + " author name: " + author + " ISBN: " + isbn; + } + +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/Identifiable.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/Identifiable.java new file mode 100644 index 0000000000..080f63b295 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/Identifiable.java @@ -0,0 +1,5 @@ +package com.baeldung.interfaces.namingconventions; + +public interface Identifiable { + void identify(); +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RegularUser.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RegularUser.java new file mode 100644 index 0000000000..e75d01e365 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RegularUser.java @@ -0,0 +1,13 @@ +package com.baeldung.interfaces.namingconventions; + +public class RegularUser implements User { + @Override + public void identify() { + // some implementation + } + + @Override + public void authorize() { + // some implementation + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RootUser.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RootUser.java new file mode 100644 index 0000000000..a02804d0b3 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/RootUser.java @@ -0,0 +1,13 @@ +package com.baeldung.interfaces.namingconventions; + +public class RootUser implements User { + @Override + public void identify() { + // some implementation + } + + @Override + public void authorize() { + // some implementation + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/User.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/User.java new file mode 100644 index 0000000000..2891126ddd --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/interfaces/namingconventions/User.java @@ -0,0 +1,5 @@ +package com.baeldung.interfaces.namingconventions; + +public interface User extends Identifiable { + void authorize(); +} diff --git a/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/encapsulation/EncapsulationAndInformationHidingUnitTest.java b/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/encapsulation/EncapsulationAndInformationHidingUnitTest.java new file mode 100644 index 0000000000..6106d1a406 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/encapsulation/EncapsulationAndInformationHidingUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.encapsulation; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EncapsulationAndInformationHidingUnitTest { + + @Test + public void givenUnencapsulatedClass_whenImplementationClassIsSeparate_thenReturnResult() { + Book myBook = new Book(); + myBook.author = "J.K Rowlings"; + myBook.isbn = 67890; + BookDetails details = new BookDetails(); + String result = details.bookDetails(myBook); + assertEquals("author name: " + myBook.author + " ISBN: " + myBook.isbn, result); + + } + + @Test + public void givenEncapsulatedClass_whenDataIsNotHidden_thenReturnResult() { + BookEncapsulation myBook = new BookEncapsulation("J.K Rowlings", 67890); + String result = myBook.getBookDetails(); + assertEquals("author id: " + 1 + " author name: " + myBook.author + " ISBN: " + myBook.isbn, result); + } + + @Test + public void givenEncapsulatedClass_whenDataIsHidden_thenReturnResult() { + BookInformationHiding myBook = new BookInformationHiding("J.K Rowlings", 67890); + String result = myBook.getBookDetails(); + assertEquals("author id: " + 1 + " author name: " + myBook.getAuthor() + " ISBN: " + myBook.getIsbn(), result); + } + +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java index f8367cfd50..75edca087f 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java @@ -1,6 +1,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; +import java.util.Objects; public class Course implements Serializable, Cloneable { @@ -39,4 +40,23 @@ public class Course implements Serializable, Cloneable { throw new IllegalStateException(e); } } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + Course that = (Course) o; + + return Objects.equals(courseId,that.courseId) + && Objects.equals(courseName,that.courseName); + } + + @Override + public int hashCode() { + return Objects.hash(courseId,courseName); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java index 0b3f1ba4a9..ce9f773bc7 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java @@ -2,6 +2,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.lang3.SerializationUtils; @@ -100,4 +101,23 @@ public class Student implements Serializable, Cloneable { student.course = this.course.clone(); return student; } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Student that = (Student) o; + + return Objects.equals(studentId,that.studentId) && + Objects.equals(studentName, that.studentName) && + Objects.equals(course, that.course); + } + + @Override + public int hashCode() { + return Objects.hash(studentId,studentName,course); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java index 625c7e8385..d7e4c0ff64 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java @@ -19,8 +19,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCloneable(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @@ -37,8 +39,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCopyConstructor(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -54,8 +58,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingSerialization(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -71,7 +77,9 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingJackson(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } } diff --git a/core-java-modules/core-java-lang-oop-types/pom.xml b/core-java-modules/core-java-lang-oop-types/pom.xml index a5b492f5ca..a9909598eb 100644 --- a/core-java-modules/core-java-lang-oop-types/pom.xml +++ b/core-java-modules/core-java-lang-oop-types/pom.xml @@ -27,7 +27,7 @@ - 1.15 + 1.16.0 \ No newline at end of file diff --git a/core-java-modules/core-java-lang-operators-2/README.md b/core-java-modules/core-java-lang-operators-2/README.md index 86e17a678f..e8b792e634 100644 --- a/core-java-modules/core-java-lang-operators-2/README.md +++ b/core-java-modules/core-java-lang-operators-2/README.md @@ -9,3 +9,4 @@ This module contains articles about Java operators - [Getting a Bit at a Certain Position from Integral Values](https://www.baeldung.com/java-get-bit-at-position) - [Check if at Least Two Out of Three Booleans Are True in Java](https://www.baeldung.com/java-check-two-of-three-booleans) - [Alternatives for instanceof Operator in Java](https://www.baeldung.com/java-instanceof-alternatives) +- [What Does “––>” Mean in Java?](https://www.baeldung.com/java-minus-minus-greaterthan) diff --git a/core-java-modules/core-java-lang-operators-2/src/test/java/com/baeldung/doubleminusgreaterthan/DoubleMinusAndGreaterThanUnitTest.java b/core-java-modules/core-java-lang-operators-2/src/test/java/com/baeldung/doubleminusgreaterthan/DoubleMinusAndGreaterThanUnitTest.java new file mode 100644 index 0000000000..bf3934b2de --- /dev/null +++ b/core-java-modules/core-java-lang-operators-2/src/test/java/com/baeldung/doubleminusgreaterthan/DoubleMinusAndGreaterThanUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.doubleminusgreaterthan; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class DoubleMinusAndGreaterThanUnitTest { + + @Test + void whenUsingDoubleMinusAndGreaterThan_thenGetTheExpectedResult() { + List resultWhile = new ArrayList<>(); + int i = 6; + while (i-- > 0) { + resultWhile.add(i); + } + assertEquals(Lists.newArrayList(5, 4, 3, 2, 1, 0), resultWhile); + + List resultFor = new ArrayList<>(); + for (int j = 6; j-- > 0; ) { + resultFor.add(j); + } + + assertEquals(Lists.newArrayList(5, 4, 3, 2, 1, 0), resultFor); + } + + @Test + void whenUsingOtherOperatorsSimilarly_thenGetTheExpectedResult() { + // <++ + List result = new ArrayList<>(); + int i = -1; + while (i++ < 5) { + result.add(i); + } + assertEquals(Lists.newArrayList(0, 1, 2, 3, 4, 5), result); + + // <-- + result.clear(); + int j = 10; + while (0 < --j) { + result.add(j); + } + assertEquals(Lists.newArrayList(9, 8, 7, 6, 5, 4, 3, 2, 1), result); + + // >++ + result.clear(); + int n = 0; + while (6 > ++n) { + result.add(n); + } + assertEquals(Lists.newArrayList(1, 2, 3, 4, 5), result); + + // >>>= + result.clear(); + int x = 32; + while ((x >>>= 1) > 1) { + result.add(x); + } + assertEquals(Lists.newArrayList(16, 8, 4, 2), result); + + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java index 8b3685adf3..0a9418cb17 100644 --- a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java +++ b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java @@ -1,54 +1,77 @@ package com.baeldung.modulo; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import static org.assertj.core.api.Java6Assertions.*; public class ModuloUnitTest { - @Test - public void whenIntegerDivision_thenLosesRemainder(){ - assertThat(11 / 4).isEqualTo(2); - } - - @Test - public void whenDoubleDivision_thenKeepsRemainder(){ - assertThat(11 / 4.0).isEqualTo(2.75); - } - - @Test - public void whenModulo_thenReturnsRemainder(){ - assertThat(11 % 4).isEqualTo(3); - } - - @Test(expected = ArithmeticException.class) - public void whenDivisionByZero_thenArithmeticException(){ - double result = 1 / 0; - } - - @Test(expected = ArithmeticException.class) - public void whenModuloByZero_thenArithmeticException(){ - double result = 1 % 0; - } - - @Test - public void whenDivisorIsOddAndModulusIs2_thenResultIs1(){ - assertThat(3 % 2).isEqualTo(1); - } - - @Test - public void whenDivisorIsEvenAndModulusIs2_thenResultIs0(){ - assertThat(4 % 2).isEqualTo(0); - } - - @Test - public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds(){ - int QUEUE_CAPACITY= 10; - int[] circularQueue = new int[QUEUE_CAPACITY]; - int itemsInserted = 0; - for (int value = 0; value < 1000; value++) { - int writeIndex = ++itemsInserted % QUEUE_CAPACITY; - circularQueue[writeIndex] = value; + @Test + public void whenIntegerDivision_thenLosesRemainder() { + assertThat(11 / 4).isEqualTo(2); + } + + @Test + public void whenDoubleDivision_thenKeepsRemainder() { + assertThat(11 / 4.0).isEqualTo(2.75); + } + + @Test + public void whenModulo_thenReturnsRemainder() { + assertThat(11 % 4).isEqualTo(3); + } + + @Test(expected = ArithmeticException.class) + public void whenDivisionByZero_thenArithmeticException() { + double result = 1 / 0; + } + + @Test(expected = ArithmeticException.class) + public void whenModuloByZero_thenArithmeticException() { + double result = 1 % 0; + } + + @Test + public void whenDivisorIsOddAndModulusIs2_thenResultIs1() { + assertThat(3 % 2).isEqualTo(1); + } + + @Test + public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() { + assertThat(4 % 2).isEqualTo(0); + } + + @Test + public void whenDividendIsNegativeAndModulusIs2_thenResultIsNegative() { + assertEquals(-1, -9 % 2); + } + + @Test + public void whenDividendIsNegativeAndRemainderIsCheckedForNegativeValue_thenResultIsPositive() { + int remainder = -9 % 2; + + if (remainder < 0) { + remainder += 2; + } + assertEquals(1, remainder); + } + + @Test + public void whenDividendIsNegativeAndUsesMathClass_thenResultIsPositive() { + int remainder = Math.floorMod(-9, 2); + assertEquals(1, remainder); + } + + @Test + public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds() { + int QUEUE_CAPACITY = 10; + int[] circularQueue = new int[QUEUE_CAPACITY]; + int itemsInserted = 0; + for (int value = 0; value < 1000; value++) { + int writeIndex = ++itemsInserted % QUEUE_CAPACITY; + circularQueue[writeIndex] = value; + } } - } } diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java index dac05a85b1..612fd7e097 100644 --- a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java +++ b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java @@ -30,13 +30,13 @@ public class Java8ComparatorUnitTest { System.out.println("************** Java 8 Comaparator **************"); Comparator byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking()); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); } @Test @@ -45,24 +45,24 @@ public class Java8ComparatorUnitTest { System.out.println("********* byRanking *********"); Comparator byRanking = Comparator.comparing(Player::getRanking); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); - + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); + System.out.println("********* byAge *********"); Comparator byAge = Comparator.comparing(Player::getAge); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byAge); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Roger"); - assertEquals(footballTeam.get(2) - .getRanking(), 45); + assertEquals(footballTeam.get(0).getName(), "Roger"); + assertEquals(footballTeam.get(0).getAge(), 20); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getAge(), 22); + assertEquals(footballTeam.get(2).getName(), "Steven"); + assertEquals(footballTeam.get(2).getAge(), 24); } } diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java index 87d9d7a620..5c93d955a7 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java @@ -2,14 +2,20 @@ package com.baeldung.networking.url; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import org.apache.http.client.utils.URIBuilder; import org.apache.http.message.BasicNameValuePair; +import org.junit.Assert; import org.junit.Test; import org.springframework.web.util.UriComponentsBuilder; @@ -18,95 +24,101 @@ import com.google.common.collect.ImmutableMap; public class UrlUnitTest { @Test - public void givenUrl_whenCanIdentifyProtocol_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com"); + public void givenUrl_whenCanIdentifyProtocol_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com").toURL(); assertEquals("http", url.getProtocol()); } @Test - public void givenUrl_whenCanGetHost_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com"); + public void givenUrl_whenCanGetHost_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com").toURL(); assertEquals("baeldung.com", url.getHost()); } @Test - public void givenUrl_whenCanGetFileName_thenCorrect2() throws MalformedURLException { - final URL url = new URL("http://baeldung.com/articles?topic=java&version=8"); + public void givenUrl_whenCanGetFileName_thenCorrect2() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com/articles?topic=java&version=8").toURL(); assertEquals("/articles?topic=java&version=8", url.getFile()); } @Test - public void givenUrl_whenCanGetFileName_thenCorrect1() throws MalformedURLException { - final URL url = new URL("http://baeldung.com/guidelines.txt"); + public void givenUrl_whenCanGetFileName_thenCorrect1() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com/guidelines.txt").toURL(); assertEquals("/guidelines.txt", url.getFile()); } @Test - public void givenUrl_whenCanGetPathParams_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com/articles?topic=java&version=8"); + public void givenUrl_whenCanGetPathParams_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com/articles?topic=java&version=8").toURL(); assertEquals("/articles", url.getPath()); } @Test - public void givenUrl_whenCanGetQueryParams_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com/articles?topic=java"); - assertEquals("topic=java", url.getQuery()); + public void givenUrl_whenCanGetQueryParams_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com/articles?topic=java&version=8").toURL(); + assertEquals("topic=java&version=8", url.getQuery()); } @Test - public void givenUrl_whenGetsDefaultPort_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com"); + public void givenUrl_whenGetsDefaultPort_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com").toURL(); assertEquals(-1, url.getPort()); assertEquals(80, url.getDefaultPort()); } @Test - public void givenUrl_whenGetsPort_thenCorrect() throws MalformedURLException { - final URL url = new URL("http://baeldung.com:8090"); + public void givenUrl_whenGetsPort_thenCorrect() throws MalformedURLException, URISyntaxException { + final URL url = new URI("http://baeldung.com:8090").toURL(); assertEquals(8090, url.getPort()); assertEquals(80, url.getDefaultPort()); } @Test - public void givenBaseUrl_whenCreatesRelativeUrl_thenCorrect() throws MalformedURLException { - final URL baseUrl = new URL("http://baeldung.com"); - final URL relativeUrl = new URL(baseUrl, "a-guide-to-java-sockets"); - assertEquals("http://baeldung.com/a-guide-to-java-sockets", relativeUrl.toString()); + public void givenHomeUrlAndFullUrl_whenRelativize_thenCorrect() throws MalformedURLException, URISyntaxException { + final URI homeUri = new URI("http://baeldung.com"); + final URI fullUri = new URI("http://baeldung.com" + "/a-guide-to-java-sockets"); + final URI relativeUri = homeUri.relativize(fullUri); + assertEquals("a-guide-to-java-sockets", relativeUri.toString()); } @Test - public void givenAbsoluteUrl_whenIgnoresBaseUrl_thenCorrect() throws MalformedURLException { - final URL baseUrl = new URL("http://baeldung.com"); - final URL relativeUrl = new URL(baseUrl, "http://baeldung.com/a-guide-to-java-sockets"); - assertEquals("http://baeldung.com/a-guide-to-java-sockets", relativeUrl.toString()); - } - - @Test - public void givenUrlComponents_whenConstructsCompleteUrl_thenCorrect() throws MalformedURLException { + public void givenUrlComponents_whenConstructsCompleteUrl_thenCorrect() throws MalformedURLException, URISyntaxException { final String protocol = "http"; final String host = "baeldung.com"; final String file = "/guidelines.txt"; - final URL url = new URL(protocol, host, file); - assertEquals("http://baeldung.com/guidelines.txt", url.toString()); + final String fragment = "myImage"; + final URL url = new URI(protocol, host, file, fragment).toURL(); + assertEquals("http://baeldung.com/guidelines.txt#myImage", url.toString()); } @Test - public void givenUrlComponents_whenConstructsCompleteUrl_thenCorrect2() throws MalformedURLException { + public void givenUrlComponents_whenConstructsCompleteUrl_thenCorrect2() throws MalformedURLException, URISyntaxException { final String protocol = "http"; + final String username = "admin"; final String host = "baeldung.com"; - final String file = "/articles?topic=java&version=8"; - final URL url = new URL(protocol, host, file); - assertEquals("http://baeldung.com/articles?topic=java&version=8", url.toString()); + final String file = "/articles"; + final String query = "topic=java&version=8"; + final String fragment = "myImage"; + final URL url = new URI(protocol, username, host, -1, file, query, fragment).toURL(); + assertEquals("http://admin@baeldung.com/articles?topic=java&version=8#myImage", url.toString()); } @Test - public void givenUrlComponentsWithPort_whenConstructsCompleteUrl_thenCorrect() throws MalformedURLException { + public void givenRelativeUrl_whenCreatesRelativeUrl_thenThrows() throws URISyntaxException, MalformedURLException { + final URI uri = new URI("/a-guide-to-java-sockets"); + Assert.assertThrows(IllegalArgumentException.class, () -> uri.toURL()); + } + + @Test + public void givenUrlComponentsWithPort_whenConstructsCompleteUrl_thenCorrect() throws MalformedURLException, URISyntaxException { final String protocol = "http"; + final String username = "admin"; final String host = "baeldung.com"; final int port = 9000; final String file = "/guidelines.txt"; - final URL url = new URL(protocol, host, port, file); - assertEquals("http://baeldung.com:9000/guidelines.txt", url.toString()); + final String fragment = "myImage"; + final URL url = new URI(protocol, username, host, port, file, null, fragment).toURL(); + assertEquals("http://admin@baeldung.com:9000/guidelines.txt#myImage", url.toString()); } @Test @@ -115,7 +127,8 @@ public class UrlUnitTest { uriBuilder.setPort(9090); uriBuilder.addParameter("topic", "java"); uriBuilder.addParameter("version", "8"); - URL url = uriBuilder.build().toURL(); + URL url = uriBuilder.build() + .toURL(); assertEquals("http://baeldung.com:9090/articles?topic=java&version=8", url.toString()); } @@ -125,28 +138,49 @@ public class UrlUnitTest { URIBuilder uriBuilder = new URIBuilder("http://baeldung.com/articles"); uriBuilder.setPort(9090); uriBuilder.addParameters(paramMap.entrySet() - .stream() - .map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())) - .collect(toList())); + .stream() + .map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())) + .collect(toList())); - URL url = uriBuilder.build().toURL(); + URL url = uriBuilder.build() + .toURL(); assertEquals("http://baeldung.com:9090/articles?topic=java&version=8", url.toString()); } @Test public void givenUrlParameters_whenBuildUrlWithSpringUriComponentsBuilder_thenSuccess() throws MalformedURLException { URL url = UriComponentsBuilder.newInstance() - .scheme("http") - .host("baeldung.com") - .port(9090) - .path("articles") - .queryParam("topic", "java") - .queryParam("version", "8") - .build() - .toUri() - .toURL(); + .scheme("http") + .host("baeldung.com") + .port(9090) + .path("articles") + .queryParam("topic", "java") + .queryParam("version", "8") + .build() + .toUri() + .toURL(); assertEquals("http://baeldung.com:9090/articles?topic=java&version=8", url.toString()); } + @Test + public void givenURI_whenConvertingToURL_thenCorrect() throws IOException, URISyntaxException { + String aURIString = "http://courses.baeldung.com"; + URI uri = new URI(aURIString); + URL url = uri.toURL(); + assertNotNull(url); + assertEquals(aURIString, url.toString()); + } + + @Test + public void givenPath_whenConvertingToURIAndThenURL_thenCorrect() throws IOException, URISyntaxException { + String finalPath = "file:/D:/baeldung/java-url"; + Path path = Paths.get("/baeldung/java-url"); + URI uri = path.toUri(); + URL url = uri.toURL(); + assertNotNull(url); + // Adapt the finalPath value to match your own path + // assertEquals(finalPath, url.toString()); + } + } \ No newline at end of file diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/EchoIntegrationTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/EchoIntegrationTest.java index 103824b6aa..1e85b9d6dd 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/EchoIntegrationTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/EchoIntegrationTest.java @@ -24,7 +24,7 @@ public class EchoIntegrationTest { Executors.newSingleThreadExecutor() .submit(() -> new EchoServer().start(port)); - Thread.sleep(500); + Thread.sleep(2000); } private EchoClient client = new EchoClient(); diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/GreetServerIntegrationTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/GreetServerIntegrationTest.java index 2bded156c5..09f20c970d 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/GreetServerIntegrationTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/GreetServerIntegrationTest.java @@ -27,7 +27,7 @@ public class GreetServerIntegrationTest { Executors.newSingleThreadExecutor() .submit(() -> new GreetServer().start(port)); - Thread.sleep(500); + Thread.sleep(2000); } @Before diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/SocketEchoMultiIntegrationTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/SocketEchoMultiIntegrationTest.java index 62e2dd44ae..f08542c1aa 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/SocketEchoMultiIntegrationTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/socket/SocketEchoMultiIntegrationTest.java @@ -23,7 +23,7 @@ public class SocketEchoMultiIntegrationTest { s.close(); Executors.newSingleThreadExecutor().submit(() -> new EchoMultiServer().start(port)); - Thread.sleep(500); + Thread.sleep(2000); } @Test diff --git a/core-java-modules/core-java-nio-2/pom.xml b/core-java-modules/core-java-nio-2/pom.xml index e35b70cfc7..dde708c10d 100644 --- a/core-java-modules/core-java-nio-2/pom.xml +++ b/core-java-modules/core-java-nio-2/pom.xml @@ -13,4 +13,18 @@ 0.0.1-SNAPSHOT + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.nio=ALL-UNNAMED + + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java index 38ae79f2f5..9439f012e3 100644 --- a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java +++ b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.integerToBinary; +import org.apache.commons.lang3.StringUtils; import org.junit.Test; + import static org.junit.Assert.assertEquals; public class IntegerToBinaryUnitTest { @@ -24,4 +26,18 @@ public class IntegerToBinaryUnitTest { String binaryString = Integer.toString(n, 2); assertEquals("111", binaryString); } -} + + @Test + public void givenAnInteger_whenFormatAndReplaceCalled_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = String.format("%8s", Integer.toBinaryString(n)).replace(" ", "0"); + assertEquals("00000111", binaryString); + } + + @Test + public void givenAnInteger_whenUsingApacheStringUtils_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = StringUtils.leftPad(Integer.toBinaryString(n), 8, "0"); + assertEquals("00000111", binaryString); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/README.md b/core-java-modules/core-java-numbers-6/README.md index 560a84f851..cf84e29710 100644 --- a/core-java-modules/core-java-numbers-6/README.md +++ b/core-java-modules/core-java-numbers-6/README.md @@ -1,6 +1,10 @@ ### Relevant Articles: - [Java Program to Estimate Pi](https://www.baeldung.com/java-monte-carlo-compute-pi) - [Convert Integer to Hexadecimal in Java](https://www.baeldung.com/java-convert-int-to-hex) -- [Integer.class Vs. Integer.TYPE Vs. int.class](https://www.baeldung.com/java-integer-class-vs-type-vs-int) +- [Integer.class vs Integer.TYPE vs int.class](https://www.baeldung.com/java-integer-class-vs-type-vs-int) - [Does Java Read Integers in Little Endian or Big Endian?](https://www.baeldung.com/java-integers-little-big-endian) +- [How to Split an Integer Number Into Digits in Java](https://www.baeldung.com/java-integer-individual-digits) +- [Java Double vs. BigDecimal](https://www.baeldung.com/java-double-vs-bigdecimal) +- [Finding the Square Root of a BigInteger in Java](https://www.baeldung.com/java-find-square-root-biginteger) +- [Truncate a Double to Two Decimal Places in Java](https://www.baeldung.com/java-double-round-two-decimal-places) - More articles: [[<-- prev]](../core-java-numbers-5) diff --git a/core-java-modules/core-java-numbers-6/pom.xml b/core-java-modules/core-java-numbers-6/pom.xml index 531f1293d1..7a3b3d4426 100644 --- a/core-java-modules/core-java-numbers-6/pom.xml +++ b/core-java-modules/core-java-numbers-6/pom.xml @@ -25,8 +25,12 @@ ${commons-codec} test + + com.google.guava + guava + ${guava.version} + - core-java-numbers-6 @@ -39,5 +43,6 @@ 1.15 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java new file mode 100644 index 0000000000..2ac57a9c0c --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java @@ -0,0 +1,8 @@ +package com.baeldung.bigintegerroot; + +public class BenchmarkRunner { + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +} + diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java new file mode 100644 index 0000000000..c2d2f30827 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java @@ -0,0 +1,10 @@ +package com.baeldung.bigintegerroot; + +public class BigIntegerHolder { + + private BigIntegerHolder() { + } + public static final String BIG_NUMBER = "179769313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + public static final String VERY_BIG_NUMBER = "32473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; + public static final String INSANELY_BIG_NUMBER = "3247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java new file mode 100644 index 0000000000..645e4eb2dd --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java @@ -0,0 +1,60 @@ +package com.baeldung.bigintegerroot; + +import static com.baeldung.bigintegerroot.BigIntegerHolder.*; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1) +@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES) +@Fork(1) +@State(Scope.Benchmark) +public class BigIntegerSquareRootBenchmark { + + @Param({BIG_NUMBER, VERY_BIG_NUMBER, INSANELY_BIG_NUMBER}) + public String number; + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithJava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = integer.sqrt(); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithGuava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = BigIntegerMath.sqrt(integer, RoundingMode.DOWN); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewtonPlus(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = NewtonPlus.sqrt(integer); + blackhole.consume(root); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewton(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = Newton.sqrt(integer); + blackhole.consume(root); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java new file mode 100644 index 0000000000..07acba7537 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java @@ -0,0 +1,29 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class Newton { + + private Newton() { + } + + public static BigInteger sqrt(BigInteger n) { + // Initial approximation + BigInteger x = n.divide(BigInteger.TWO); + + // Tolerance level (small positive integer) + BigInteger tolerance = BigInteger.ONE; + + while (true) { + // x_new = 0.5 * (x + n / x) + BigInteger xNew = x.add(n.divide(x)).divide(BigInteger.TWO); + + // Check for convergence within tolerance + if (x.subtract(xNew).abs().compareTo(tolerance) <= 0) { + return xNew; + } + + x = xNew; + } + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java new file mode 100644 index 0000000000..80d50c0ca5 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java @@ -0,0 +1,108 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class NewtonPlus { + + private NewtonPlus() { + } + + // A fast square root by Ryan Scott White. + public static BigInteger sqrt(BigInteger x) { + if (x.compareTo(BigInteger.valueOf(144838757784765629L)) < 0) { + long xAsLong = x.longValue(); + long vInt = (long)Math.sqrt(xAsLong); + if (vInt * vInt > xAsLong) + vInt--; + return BigInteger.valueOf(vInt); } + + double xAsDub = x.doubleValue(); + BigInteger val; + if (xAsDub < 2.1267e37) // 2.12e37 largest here + // since sqrt(long.max*long.max) > long.max + { + long vInt = (long)Math.sqrt(xAsDub); + val = BigInteger.valueOf + ((vInt + x.divide(BigInteger.valueOf(vInt)).longValue()) >> 1); + } + else if (xAsDub < 4.3322e127) { + // Convert a double to a BigInteger + long bits = Double.doubleToLongBits(Math.sqrt(xAsDub)); + int exp = ((int) (bits >> 52) & 0x7ff) - 1075; + val = BigInteger.valueOf((bits & ((1L << 52)) - 1) | (1L << 52)).shiftLeft(exp); + + val = x.divide(val).add(val).shiftRight(1); + if (xAsDub > 2e63) { + val = x.divide(val).add(val).shiftRight(1); } + } + else // handle large numbers over 4.3322e127 + { + int xLen = x.bitLength(); + int wantedPrecision = ((xLen + 1) / 2); + int xLenMod = xLen + (xLen & 1) + 1; + + //////// Do the first Sqrt on Hardware //////// + long tempX = x.shiftRight(xLenMod - 63).longValue(); + double tempSqrt1 = Math.sqrt(tempX); + long valLong = Double.doubleToLongBits(tempSqrt1) & 0x1fffffffffffffL; + + if (valLong == 0) + valLong = 1L << 53; + + //////// Classic Newton Iterations //////// + val = BigInteger.valueOf(valLong).shiftLeft(53 - 1) + .add((x.shiftRight(xLenMod - + (3 * 53))).divide(BigInteger.valueOf(valLong))); + + int size = 106; + for (; size < 256; size <<= 1) { + val = val.shiftLeft(size - 1).add(x.shiftRight + (xLenMod - (3*size)).divide(val));} + + if (xAsDub > 4e254) { // 4e254 = 1<<845.77 + int numOfNewtonSteps = 31 - + Integer.numberOfLeadingZeros(wantedPrecision / size)+1; + + ////// Apply Starting Size //////// + int wantedSize = (wantedPrecision >> numOfNewtonSteps) + 2; + int needToShiftBy = size - wantedSize; + val = val.shiftRight(needToShiftBy); + + size = wantedSize; + do { + //////// Newton Plus Iteration //////// + int shiftX = xLenMod - (3 * size); + BigInteger valSqrd = val.multiply(val).shiftLeft(size - 1); + BigInteger valSU = x.shiftRight(shiftX).subtract(valSqrd); + val = val.shiftLeft(size).add(valSU.divide(val)); + size *= 2; + } while (size < wantedPrecision); + } + val = val.shiftRight(size - wantedPrecision); + } + + // Detect a round ups. This function can be further optimized - see article. + // For a ~7% speed bump the following line can be removed but round-ups will occur. + if (val.multiply(val).compareTo(x) > 0) + val = val.subtract(BigInteger.ONE); + + // Enabling the below will guarantee an error is stopped for larger numbers. + // Note: As of this writing, there are no known errors. + BigInteger tmp = val.multiply(val); + if (tmp.compareTo(x) > 0) { + System.out.println("val^2(" + val.multiply(val).toString() + + ") ≥ x(" + x.toString()+")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too high"); + } + if (tmp.add(val.shiftLeft(1)).add(BigInteger.ONE).compareTo(x) <= 0) { + System.out.println("(val+1)^2(" + + val.add(BigInteger.ONE).multiply(val.add(BigInteger.ONE)).toString() + + ") ≥ x(" + x.toString() + ")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too low"); + } + + return val; + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java new file mode 100644 index 0000000000..edb75b16ef --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.bigintegerroot; + + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.stream.Stream; +import org.apache.commons.math3.util.Pair; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BigIntegerSquareRootUnitTest { + + @ParameterizedTest + @ValueSource(strings = { + BigIntegerHolder.BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER + }) + void squareRootTest(String number) { + final BigInteger bigInteger = new BigInteger(number); + final BigInteger javaRoot = bigInteger.sqrt(); + final BigInteger guavaRoot = BigIntegerMath.sqrt(bigInteger, RoundingMode.DOWN); + final BigInteger newtonRoot = Newton.sqrt(bigInteger); + final BigInteger newtonPlusRoot = NewtonPlus.sqrt(bigInteger); + + assertTrue(Stream.of( + new Pair<>(javaRoot, guavaRoot), + new Pair<>(guavaRoot, newtonRoot), + new Pair<>(newtonRoot, newtonPlusRoot) + ).allMatch(pair -> pair.getFirst().equals(pair.getSecond()))); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/genericnumberscomparator/GenericNumbersComparatorUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/genericnumberscomparator/GenericNumbersComparatorUnitTest.java new file mode 100644 index 0000000000..37b971b5c5 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/genericnumberscomparator/GenericNumbersComparatorUnitTest.java @@ -0,0 +1,122 @@ +package com.baeldung.genericnumberscomparator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +class GenericNumbersComparatorUnitTest { + + public int compareDouble(Number num1, Number num2) { + return Double.compare(num1.doubleValue(), num2.doubleValue()); + } + + @Test + void givenNumbers_whenUseCompareDouble_thenWillExecuteComparison() { + assertEquals(0, compareDouble(5, 5.0)); + } + + public int compareTo(Integer int1, Integer int2) { + return int1.compareTo(int2); + } + + @Test + void givenNumbers_whenUseCompareTo_thenWillExecuteComparison() { + assertEquals(-1, compareTo(5, 7)); + } + + Map, BiFunction> comparisonMap = new HashMap<>(); + + public int compareUsingMap(Number num1, Number num2) { + comparisonMap.put(Integer.class, (a, b) -> ((Integer) num1).compareTo((Integer) num2)); + + return comparisonMap.get(num1.getClass()) + .apply(num1, num2); + } + + @Test + void givenNumbers_whenUseCompareUsingMap_thenWillExecuteComparison() { + assertEquals(-1, compareUsingMap(5, 7)); + } + + public interface NumberComparator { + int compare(Number num1, Number num2); + } + + @Test + void givenNumbers_whenUseProxy_thenWillExecuteComparison() { + NumberComparator proxy = (NumberComparator) Proxy.newProxyInstance(NumberComparator.class.getClassLoader(), new Class[] { NumberComparator.class }, + (p, method, args) -> Double.compare(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue())); + assertEquals(0, proxy.compare(5, 5.0)); + } + + public int compareUsingReflection(Number num1, Number num2) throws Exception { + Method method = num1.getClass() + .getMethod("compareTo", num1.getClass()); + return (int) method.invoke(num1, num2); + } + + @Test + void givenNumbers_whenUseCompareUsingReflection_thenWillExecuteComparison() throws Exception { + assertEquals(-1, compareUsingReflection(5, 7)); + } + + interface NumberComparatorFactory { + Comparator getComparator(); + } + + class IntegerComparatorFactory implements NumberComparatorFactory { + @Override + public Comparator getComparator() { + return (num1, num2) -> ((Integer) num1).compareTo((Integer) num2); + } + } + + @Test + void givenNumbers_whenUseComparatorFactory_thenWillExecuteComparison() { + NumberComparatorFactory factory = new IntegerComparatorFactory(); + Comparator comparator = factory.getComparator(); + assertEquals(-1, comparator.compare(5, 7)); + } + + Function toDouble = Number::doubleValue; + BiPredicate isEqual = (num1, num2) -> toDouble.apply(num1) + .equals(toDouble.apply(num2)); + + @Test + void givenNumbers_whenUseIsEqual_thenWillExecuteComparison() { + assertEquals(true, isEqual.test(5, 5.0)); + } + + private Number someNumber = 5; + private Number anotherNumber = 5.0; + + Optional optNum1 = Optional.ofNullable(someNumber); + Optional optNum2 = Optional.ofNullable(anotherNumber); + int comparisonResult = optNum1.flatMap(n1 -> optNum2.map(n2 -> Double.compare(n1.doubleValue(), n2.doubleValue()))) + .orElse(0); + + @Test + void givenNumbers_whenUseComparisonResult_thenWillExecuteComparison() { + assertEquals(0, comparisonResult); + } + + private boolean someCondition = true; + Function dynamicFunction = someCondition ? Number::doubleValue : Number::intValue; + Comparator dynamicComparator = (num1, num2) -> ((Comparable) dynamicFunction.apply(num1)).compareTo(dynamicFunction.apply(num2)); + + @Test + void givenNumbers_whenUseDynamicComparator_thenWillExecuteComparison() { + assertEquals(0, dynamicComparator.compare(5, 5.0)); + } + +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integertodigits/IntegerToDigitsUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integertodigits/IntegerToDigitsUnitTest.java new file mode 100644 index 0000000000..3162fba814 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integertodigits/IntegerToDigitsUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.integertodigits; + +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IntegerToDigitsUnitTest { + private final static int THE_NUMBER = 1230456; + private final static List EXPECTED_INT_LIST = Lists.newArrayList(1, 2, 3, 0, 4, 5, 6); + private final static String[] EXPECTED_STR_ARRAY = new String[] { "1", "2", "3", "0", "4", "5", "6" }; + private final static List EXPECTED_STR_LIST = Lists.newArrayList("1", "2", "3", "0", "4", "5", "6"); + private final static char[] EXPECTED_CHAR_ARRAY = new char[] { '1', '2', '3', '0', '4', '5', '6' }; + + @Test + void whenUsingModOperator_thenGetExpectedResult() { + int number = THE_NUMBER; + LinkedList result = new LinkedList<>(); + while (number > 0) { + result.push(number % 10); + number /= 10; + } + assertEquals(EXPECTED_INT_LIST, result); + } + + + private void collectDigits(int num, List digitList) { + if (num / 10 > 0) { + collectDigits(num / 10, digitList); + } + digitList.add(num % 10); + } + + @Test + void whenUsingModOperatorAndRecursion_thenGetExpectedResult() { + List result = new ArrayList<>(); + collectDigits(THE_NUMBER, result); + assertEquals(EXPECTED_INT_LIST, result); + } + + @Test + void whenUsingIntStream_thenGetExpectedResult() { + String numStr = String.valueOf(THE_NUMBER); + List result = numStr.chars().map(Character::getNumericValue).boxed().collect(Collectors.toList()); + assertEquals(EXPECTED_INT_LIST, result); + } + + @Test + void whenUsingToCharArray_thenGetExpectedResult() { + String numStr = String.valueOf(THE_NUMBER); + char[] result = numStr.toCharArray(); + assertArrayEquals(EXPECTED_CHAR_ARRAY, result); + } + + @Test + void whenUsingSplit_thenGetExpectedResult() { + String numStr = String.valueOf(THE_NUMBER); + String[] result = numStr.split("(?<=.)"); + assertArrayEquals(EXPECTED_STR_ARRAY, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java new file mode 100644 index 0000000000..76c218d85f --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalConversionUnitTest { + + @Test + void whenConvertingDoubleToBigDecimal_thenConversionIsCorrect() { + double doubleValue = 123.456; + BigDecimal bigDecimalValue = BigDecimal.valueOf(doubleValue); + BigDecimal expected = new BigDecimal("123.456").setScale(3, RoundingMode.HALF_UP); + assertEquals(expected, bigDecimalValue.setScale(3, RoundingMode.HALF_UP)); + } + + @Test + void givenDecimalPlacesGreaterThan15_whenConvertingBigDecimalToDouble_thenPrecisionIsLost() { + BigDecimal bigDecimalValue = new BigDecimal("789.1234567890123456"); + double doubleValue = bigDecimalValue.doubleValue(); + BigDecimal convertedBackToBigDecimal = BigDecimal.valueOf(doubleValue); + assertNotEquals(bigDecimalValue, convertedBackToBigDecimal); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java new file mode 100644 index 0000000000..3ee611f315 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalUnitTest { + + private BigDecimal bigDecimal1 = new BigDecimal("124567890.0987654321"); + private BigDecimal bigDecimal2 = new BigDecimal("987654321.123456789"); + + @Test + public void givenTwoBigDecimals_whenAdd_thenCorrect() { + BigDecimal expected = new BigDecimal("1112222211.2222222211"); + BigDecimal actual = bigDecimal1.add(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenMultiply_thenCorrect() { + BigDecimal expected = new BigDecimal("123030014929277547.5030955772112635269"); + BigDecimal actual = bigDecimal1.multiply(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenSubtract_thenCorrect() { + BigDecimal expected = new BigDecimal("-863086431.0246913569"); + BigDecimal actual = bigDecimal1.subtract(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenDivide_thenCorrect() { + BigDecimal expected = new BigDecimal("0.13"); + BigDecimal actual = bigDecimal1.divide(bigDecimal2, 2, RoundingMode.HALF_UP); + assertEquals(expected, actual); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java new file mode 100644 index 0000000000..8697e1bfce --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class JavaDoubleUnitTest { + + @Test + public void givenDoubleLiteral_whenAssigningToDoubleVariable_thenValueIsNotExactlyEqual() { + double doubleValue = 0.1; + double epsilon = 0.0000000000000001; + assertEquals(0.1, doubleValue, epsilon); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/truncatedouble/TruncateDoubleUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/truncatedouble/TruncateDoubleUnitTest.java new file mode 100644 index 0000000000..1bbca4069f --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/truncatedouble/TruncateDoubleUnitTest.java @@ -0,0 +1,73 @@ +package com.baeldung.truncatedouble; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import org.junit.Test; + +public class TruncateDoubleUnitTest { + + @Test + public void givenADouble_whenUsingDecimalFormat_truncateToTwoDecimalPlaces() { + DecimalFormat df = new DecimalFormat("#.##"); + df.setRoundingMode(RoundingMode.DOWN); + + double value = 1.55555555; + String truncated = df.format(value); + assertEquals("1.55", truncated); + + double negativeValue = -1.55555555; + String negativeTruncated = df.format(negativeValue); + assertEquals("-1.55", negativeTruncated); + } + + @Test + public void givenADouble_whenUsingNumberFormat_truncateToTwoDecimalPlaces() { + NumberFormat nf = NumberFormat.getNumberInstance(); + nf.setMaximumFractionDigits(2); + nf.setRoundingMode(RoundingMode.DOWN); + + double value = 1.55555555; + String truncated = nf.format(value); + assertEquals("1.55", truncated); + + double negativeValue = -1.55555555; + String negativeTruncated = nf.format(negativeValue); + assertEquals("-1.55", negativeTruncated); + } + + @Test + public void givenADouble_whenUsingBigDecimal_truncateToTwoDecimalPlaces() { + BigDecimal positive = new BigDecimal(2.555555).setScale(2, RoundingMode.DOWN); + BigDecimal negative = new BigDecimal(-2.555555).setScale(2, RoundingMode.DOWN); + assertEquals("2.55", positive.toString()); + assertEquals("-2.55", negative.toString()); + } + + @Test + public void givenADouble_whenUsingMath_truncateToTwoDecimalPlaces() { + double positive = 1.55555555; + double truncated = Math.floor(positive * 100) / 100; + assertEquals("1.55", String.valueOf(truncated)); + + double negative = -1.55555555; + double negativeTruncated = Math.ceil(negative * 100) / 100; + assertEquals("-1.55", String.valueOf(negativeTruncated)); + } + + @Test + public void givenADouble_whenUsingStringFormat_truncateToTwoDecimalPlaces() { + double positive = 1.55555555; + String truncated = String.format("%.2f", positive); + assertEquals("1.56", truncated); + + double negative = -1.55555555; + String negativeTruncated = String.format("%.2f", negative); + assertEquals("-1.56", negativeTruncated); + } + +} diff --git a/core-java-modules/core-java-numbers-conversions/README.md b/core-java-modules/core-java-numbers-conversions/README.md index b4c593c494..dead88f025 100644 --- a/core-java-modules/core-java-numbers-conversions/README.md +++ b/core-java-modules/core-java-numbers-conversions/README.md @@ -1,3 +1,6 @@ ### Relevant Articles: - [Convert a Number to a Letter in Java](https://www.baeldung.com/java-convert-number-to-letter) - [Convert Long to BigDecimal in Java](https://www.baeldung.com/java-convert-long-bigdecimal) +- [Convert int to Long in Java](https://www.baeldung.com/java-convert-int-long) +- [How To Convert Double To Float In Java](https://www.baeldung.com/java-convert-double-float) +- [Converting from float to BigDecimal in Java](https://www.baeldung.com/java-convert-float-bigdecimal) diff --git a/core-java-modules/core-java-numbers-conversions/pom.xml b/core-java-modules/core-java-numbers-conversions/pom.xml index f745b83f8a..d014675ead 100644 --- a/core-java-modules/core-java-numbers-conversions/pom.xml +++ b/core-java-modules/core-java-numbers-conversions/pom.xml @@ -18,6 +18,18 @@ commons-lang3 ${commons-lang3.version} + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + diff --git a/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java new file mode 100644 index 0000000000..f4fd68550c --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java @@ -0,0 +1,15 @@ +package com.baeldung.floatdoubleconversions; + +public class FloatAndDoubleConversions { + public static void main(String args[]){ + float vatRate = 14.432511f; + System.out.println("vatRate:"+vatRate); + Float localTaxRate = 20.12434f; + System.out.println("localTaxRate:"+localTaxRate); + + double shootingAverage = 56.00000000000001; + System.out.println("shootingAverage:"+shootingAverage); + Double assistAverage = 81.123000000045; + System.out.println("assistAverage:"+assistAverage); + } +} diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java new file mode 100644 index 0000000000..9da50276a9 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java @@ -0,0 +1,33 @@ +package com.baeldung.floatdoubleconversions; + +import org.junit.Assert; +import org.junit.Test; + +public class FloatDoubleConversionsTest { + + @Test + public void whenDoubleType_thenFloatTypeSuccess(){ + double interestRatesYearly = 13.333333333333333; + float interest = (float) interestRatesYearly; + System.out.println(interest); //13.333333 + Assert.assertEquals(13.333333f, interest, 0.000001f); + + Double monthlyRates = 2.111111111111111; + float rates = monthlyRates.floatValue(); + System.out.println(rates); //2.1111112 + Assert.assertEquals(2.1111111f, rates, 0.0000001f); + } + @Test + public void whenFloatType_thenDoubleTypeSuccess(){ + float gradeAverage =2.05f; + double average = gradeAverage; + System.out.println(average); //2.049999952316284 + Assert.assertEquals(2.05, average, 0.01); + + Float monthlyRates = 2.1111111f; + Double rates = monthlyRates.doubleValue(); + System.out.println(rates); //2.1111111640930176 + Assert.assertEquals(2.11111111, rates, 0.0000001);//true + } + +} diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java new file mode 100644 index 0000000000..f783d00976 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.floattobigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +class FloatToBigDecimalUnitTest { + + @Test + public void whenFloatComparedWithDifferentValues_thenCouldMatch() { + assertNotEquals(1.1f, 1.09f); + assertEquals(1.1f, 1.09999999f); + } + + @Test + public void whenCreatedFromFloat_thenMatchesInternallyStoredValue() { + float floatToConvert = 1.10000002384185791015625f; + BigDecimal bdFromFloat = new BigDecimal(floatToConvert); + assertEquals("1.10000002384185791015625", bdFromFloat.toString()); + } + + @Test + public void whenCreatedFromString_thenPreservesTheOriginal() { + BigDecimal bdFromString = new BigDecimal("1.1"); + assertEquals("1.1", bdFromString.toString()); + } + + @Test + public void whenCreatedFromFloatConvertedToString_thenFloatInternalValueGetsTruncated() { + String floatValue = Float.toString(1.10000002384185791015625f); + BigDecimal bdFromString = new BigDecimal(floatValue); + assertEquals("1.1", floatValue); + assertEquals("1.1", bdFromString.toString()); + } + + @Test + public void whenCreatedByValueOf_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f).toString()); + } + + @Test + public void whenDoubleConvertsFloatToString_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", Double.toString(1.10000002384185791015625f)); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/inttolong/IntToLongUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/inttolong/IntToLongUnitTest.java new file mode 100644 index 0000000000..bc4109b42a --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/inttolong/IntToLongUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.inttolong; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class IntToLongUnitTest { + + @Test + void whenUsingTheAutoboxing_thenGetTheExpectedLong() { + int intTen = 10; + Long longTen = (long) intTen; + assertEquals(intTen, longTen); + } + + @Test + void whenUsingTheValueOf_thenGetTheExpectedLong() { + int intTen = 10; + Long longTen = Long.valueOf(intTen); + assertEquals(intTen, longTen); + } + + @Test + void whenUsingTheConstructor_thenGetTheExpectedLong() { + int intTen = 10; + Long longTen = new Long(intTen); + assertEquals(intTen, longTen); + } + + @Test + void whenUsingTheParseLong_thenGetTheExpectedLong() { + int intTen = 10; + Long longTen = Long.parseLong(String.valueOf(intTen)); + assertEquals(intTen, longTen); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/.gitignore b/core-java-modules/core-java-os-2/.gitignore new file mode 100644 index 0000000000..3de4cc647e --- /dev/null +++ b/core-java-modules/core-java-os-2/.gitignore @@ -0,0 +1,26 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/README.md b/core-java-modules/core-java-os-2/README.md new file mode 100644 index 0000000000..c2f48f2854 --- /dev/null +++ b/core-java-modules/core-java-os-2/README.md @@ -0,0 +1,7 @@ +## Core Java OS + +This module contains articles about working with the operating system (OS) in Java + +### Relevant Articles: +- [How to Detect the Username Using Java](https://www.baeldung.com/java-get-username) + diff --git a/core-java-modules/core-java-os-2/pom.xml b/core-java-modules/core-java-os-2/pom.xml new file mode 100644 index 0000000000..53fdafa7d4 --- /dev/null +++ b/core-java-modules/core-java-os-2/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + core-java-os + core-java-os + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + core-java-os + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + 1.9 + 1.9 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java new file mode 100644 index 0000000000..2557c0cfa8 --- /dev/null +++ b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java @@ -0,0 +1,9 @@ +package com.baeldung.system; + +public class EnvironmentExample { + public void getUserName() { + String username = System.getenv("USERNAME"); + System.out.println("User: " + username); + } + +} diff --git a/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java new file mode 100644 index 0000000000..cb203c40c6 --- /dev/null +++ b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java @@ -0,0 +1,19 @@ +package com.baeldung.system; + +public class PropertiesExample { + public void getUserName() { + String username = System.getProperty("user.name"); + System.out.println("User: " + username); + } + + public void getCustomProp() { + String customProperty = System.getProperty("custom.prop"); + System.out.println("Custom property: " + customProperty); + } + + public void getCustomPropWithFallback() { + String customProperty = System.getProperty("non-existent-property", "default value"); + System.out.println("Custom property: " + customProperty); + } + +} diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java deleted file mode 100644 index 27a6dd43c6..0000000000 --- a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.system; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class WhenDetectingOSUnitTest { - - private DetectOS os = new DetectOS(); - - @Test - public void whenUsingSystemProperty_shouldReturnOS() { - String expected = "Windows 10"; - String actual = os.getOperatingSystem(); - Assert.assertEquals(expected, actual); - } - - @Test - public void whenUsingSystemUtils_shouldReturnOS() { - String expected = "Windows 10"; - String actual = os.getOperatingSystemSystemUtils(); - Assert.assertEquals(expected, actual); - } -} diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java deleted file mode 100644 index 8ad3f75623..0000000000 --- a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.system.exit; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import java.security.Permission; - -import static org.junit.Assert.assertEquals; - -@Ignore("This test is ignored because it tests deprecated code") -public class SystemExitUnitTest { - - private SecurityManager securityManager; - private SystemExitExample example; - - @Before - public void setUp() { - example = new SystemExitExample(); - securityManager = System.getSecurityManager(); - System.setSecurityManager(new NoExitSecurityManager()); - } - - @After - public void tearDown() throws Exception { - System.setSecurityManager(securityManager); - } - - @Test - public void testExit() throws Exception { - try { - example.readFile(); - } catch (ExitException e) { - assertEquals("Exit status", 2, e.status); - } - } - - protected static class ExitException extends SecurityException { - - private static final long serialVersionUID = 1L; - public final int status; - - public ExitException(int status) { - this.status = status; - } - } - - private static class NoExitSecurityManager extends SecurityManager { - @Override - public void checkPermission(Permission perm) { - } - - @Override - public void checkPermission(Permission perm, Object context) { - } - - @Override - public void checkExit(int status) { - super.checkExit(status); - throw new ExitException(status); - } - } -} \ No newline at end of file diff --git a/core-java-modules/core-java-perf-2/README.md b/core-java-modules/core-java-perf-2/README.md index 8718060645..aea10fa69c 100644 --- a/core-java-modules/core-java-perf-2/README.md +++ b/core-java-modules/core-java-perf-2/README.md @@ -5,3 +5,4 @@ This module contains articles about performance of Java applications ### Relevant Articles: - [External Debugging With JMXTerm](https://www.baeldung.com/java-jmxterm-external-debugging) - [Create and Detect Memory Leaks in Java](https://www.baeldung.com/java-create-detect-memory-leaks) +- [Differences Between Heap Dump, Thread Dump and Core Dump](https://www.baeldung.com/java-heap-thread-core-dumps) diff --git a/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.c b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.c new file mode 100644 index 0000000000..4a8b2c2b83 --- /dev/null +++ b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.c @@ -0,0 +1,15 @@ +#include +#include "CoreDump.h" + +void core() { + int *p = NULL; + *p = 0; +} + +JNIEXPORT void JNICALL Java_CoreDump_core (JNIEnv *env, jobject obj) { + core(); +}; + +void main() { +} + diff --git a/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.h b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.h new file mode 100644 index 0000000000..3b0e34b77d --- /dev/null +++ b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class CoreDump */ + +#ifndef _Included_CoreDump +#define _Included_CoreDump +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: CoreDump + * Method: core + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_CoreDump_core + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.java b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.java new file mode 100644 index 0000000000..17725ee567 --- /dev/null +++ b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/CoreDump.java @@ -0,0 +1,13 @@ +package com.baeldung.dumps; + +public class CoreDump { + static { + System.loadLibrary("nativelib"); + } + + public static void main(String[] args) { + new CoreDump().core(); + } + + private native void core(); +} diff --git a/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/HeapDump.java b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/HeapDump.java new file mode 100644 index 0000000000..c117c4f9a9 --- /dev/null +++ b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/HeapDump.java @@ -0,0 +1,19 @@ +package com.baeldung.dumps; + +import java.util.ArrayList; +import java.util.List; + +public class HeapDump { + public static void main(String[] args) { + List numbers = new ArrayList<>(); + + try { + while (true) { + numbers.add(10); + } + } catch (OutOfMemoryError e) { + System.out.println("Out of memory error occurred!"); + } + } + +} diff --git a/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/ThreadDump.java b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/ThreadDump.java new file mode 100644 index 0000000000..1d76c911de --- /dev/null +++ b/core-java-modules/core-java-perf-2/src/main/java/com/baeldung/dumps/ThreadDump.java @@ -0,0 +1,18 @@ +package com.baeldung.dumps; + +public class ThreadDump { + public static void main(String[] args) { + longRunningTask(); + } + + private static void longRunningTask() { + for (int i = 0; i < Integer.MAX_VALUE; i++) { + if (Thread.currentThread().isInterrupted()) { + System.out.println("Interrupted!"); + break; + } + System.out.println(i); + } + } + +} diff --git a/core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceTest.java b/core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceUnitTest.java similarity index 95% rename from core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceTest.java rename to core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceUnitTest.java index 90c96cba1b..ca288560a1 100644 --- a/core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceTest.java +++ b/core-java-modules/core-java-perf-2/src/test/java/com/baeldung/lapsedlistener/MovieQuoteServiceUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -class MovieQuoteServiceTest { +class MovieQuoteServiceUnitTest { @Test void whenSubscribeToService_thenServiceHasOneSubscriber() { diff --git a/core-java-modules/core-java-records/src/main/java/com/baeldung/optionalsasparameterrecords/Product.java b/core-java-modules/core-java-records/src/main/java/com/baeldung/optionalsasparameterrecords/Product.java new file mode 100644 index 0000000000..8ede001ee1 --- /dev/null +++ b/core-java-modules/core-java-records/src/main/java/com/baeldung/optionalsasparameterrecords/Product.java @@ -0,0 +1,6 @@ +package com.baeldung.optionalsasparameterrecords; + +import java.util.Optional; + +public record Product(String name, double price, Optional description) { +} diff --git a/core-java-modules/core-java-records/src/test/java/com/baeldung/optionalsasparameterrecords/OptionalAsRecordParameterUnitTest.java b/core-java-modules/core-java-records/src/test/java/com/baeldung/optionalsasparameterrecords/OptionalAsRecordParameterUnitTest.java new file mode 100644 index 0000000000..554fb2eac3 --- /dev/null +++ b/core-java-modules/core-java-records/src/test/java/com/baeldung/optionalsasparameterrecords/OptionalAsRecordParameterUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.optionalsasparameterrecords; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +public class OptionalAsRecordParameterUnitTest { + + @Test + public void givenRecordCreationWithOptional_thenCreateItProperly() { + var emptyDescriptionProduct = new Product("television", 1699.99, Optional.empty()); + Assertions.assertEquals("television", emptyDescriptionProduct.name()); + Assertions.assertEquals(1699.99, emptyDescriptionProduct.price()); + Assertions.assertNull(emptyDescriptionProduct.description().orElse(null)); + } +} diff --git a/core-java-modules/core-java-reflection-2/README.md b/core-java-modules/core-java-reflection-2/README.md index 4918b1fe98..dfd6bf28e6 100644 --- a/core-java-modules/core-java-reflection-2/README.md +++ b/core-java-modules/core-java-reflection-2/README.md @@ -9,3 +9,4 @@ - [Invoke a Static Method Using Java Reflection API](https://www.baeldung.com/java-invoke-static-method-reflection) - [What Is the JDK com.sun.proxy.$Proxy Class?](https://www.baeldung.com/jdk-com-sun-proxy) - [Unit Test Private Methods in Java](https://www.baeldung.com/java-unit-test-private-methods) +- [Constructing Java Objects From Only the Class Name](https://www.baeldung.com/java-objects-make-using-class-name) diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/BronzeJobCard.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/BronzeJobCard.java new file mode 100644 index 0000000000..cb8d7e8422 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/BronzeJobCard.java @@ -0,0 +1,21 @@ +package com.baeldung.reflection.createobject.basic; + +import java.lang.reflect.InvocationTargetException; + +public class BronzeJobCard { + private Object jobType; + public void setJobType(String jobType) throws ClassNotFoundException, + NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Class jobTypeClass = Class.forName(jobType); + this.jobType = jobTypeClass.getDeclaredConstructor().newInstance(); + } + public String startJob() { + if(this.jobType instanceof RepairJob) { + return "Start Bronze " + ((RepairJob) this.jobType).getJobType(); + } + if(this.jobType instanceof MaintenanceJob) { + return "Start Bronze " + ((MaintenanceJob) this.jobType).getJobType(); + } + return "Bronze Job Failed"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/GoldJobCard.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/GoldJobCard.java new file mode 100644 index 0000000000..f6b14b9355 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/GoldJobCard.java @@ -0,0 +1,17 @@ +package com.baeldung.reflection.createobject.basic; + +import java.lang.reflect.InvocationTargetException; + +public class GoldJobCard { + private T jobType; + + public void setJobType(Class jobTypeClass) throws + NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + this.jobType = jobTypeClass.getDeclaredConstructor().newInstance(); + } + + public String startJob() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return "Start Gold " + this.jobType.getClass().getMethod("getJobType") + .invoke(this.jobType).toString(); + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/MaintenanceJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/MaintenanceJob.java new file mode 100644 index 0000000000..8c268f0491 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/MaintenanceJob.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.createobject.basic; + +public class MaintenanceJob { + public String getJobType() { + return "Maintenance Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/PaintJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/PaintJob.java new file mode 100644 index 0000000000..74e6e2ccd2 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/PaintJob.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.createobject.basic; + +public class PaintJob { + public String getJobType() { + return "Paint Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/RepairJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/RepairJob.java new file mode 100644 index 0000000000..22fe8e3742 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/RepairJob.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.createobject.basic; + +public class RepairJob { + public String getJobType() { + return "Repair Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/SilverJobCard.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/SilverJobCard.java new file mode 100644 index 0000000000..231924bbaa --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/basic/SilverJobCard.java @@ -0,0 +1,22 @@ +package com.baeldung.reflection.createobject.basic; + +import java.lang.reflect.InvocationTargetException; + +public class SilverJobCard { + private Object jobType; + + public void setJobType(Class jobTypeClass) throws + NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + this.jobType = jobTypeClass.getDeclaredConstructor().newInstance(); + } + + public String startJob() { + if (this.jobType instanceof RepairJob) { + return "Start Silver " + ((RepairJob) this.jobType).getJobType(); + } + if (this.jobType instanceof MaintenanceJob) { + return "Start Silver " + ((MaintenanceJob) this.jobType).getJobType(); + } + return "Silver Job Failed"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/Job.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/Job.java new file mode 100644 index 0000000000..4fbf00e775 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/Job.java @@ -0,0 +1,5 @@ +package com.baeldung.reflection.createobject.special; + +public interface Job { + String getJobType(); +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/MaintenanceJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/MaintenanceJob.java new file mode 100644 index 0000000000..d93c20a09a --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/MaintenanceJob.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.createobject.special; + +public class MaintenanceJob implements Job { + public String getJobType() { + return "Maintenance Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PaintJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PaintJob.java new file mode 100644 index 0000000000..3eae7cb0c6 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PaintJob.java @@ -0,0 +1,8 @@ +package com.baeldung.reflection.createobject.special; + +public class PaintJob implements Job { + @Override + public String getJobType() { + return "Paint Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PlatinumJobCard.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PlatinumJobCard.java new file mode 100644 index 0000000000..4dd71e7fea --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/PlatinumJobCard.java @@ -0,0 +1,16 @@ +package com.baeldung.reflection.createobject.special; + +import java.lang.reflect.InvocationTargetException; + +public class PlatinumJobCard { + private T jobType; + + public void setJobType(Class jobTypeClass) throws + NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + this.jobType = jobTypeClass.getDeclaredConstructor().newInstance(); + } + + public String startJob() { + return "Start Platinum " + this.jobType.getJobType(); + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/RepairJob.java b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/RepairJob.java new file mode 100644 index 0000000000..985160fe48 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/java/com/baeldung/reflection/createobject/special/RepairJob.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.createobject.special; + +public class RepairJob implements Job { + public String getJobType() { + return "Repair Job"; + } +} diff --git a/core-java-modules/core-java-reflection-2/src/main/resources/Bronze.puml b/core-java-modules/core-java-reflection-2/src/main/resources/Bronze.puml new file mode 100644 index 0000000000..21f05fe52b --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/resources/Bronze.puml @@ -0,0 +1,20 @@ +@startuml +'https://plantuml.com/class-diagram + +class BronzeJobCard { + -Object jobType + +setJobType(String jobType) + +startJob() +} + +class MaintenanceJob { + +getJobType() +} +class RepairJob { + +getJobType() +} +BronzeJobCard -left-> MaintenanceJob:creates +BronzeJobCard -right-> RepairJob:creates + + +@enduml \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-2/src/main/resources/Gold.puml b/core-java-modules/core-java-reflection-2/src/main/resources/Gold.puml new file mode 100644 index 0000000000..2055154c21 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/resources/Gold.puml @@ -0,0 +1,20 @@ +@startuml +'https://plantuml.com/class-diagram + +class GoldJobCard { + -T jobType + +setJobType(Class jobTypeClass) + +startJob() +} + +class MaintenanceJob { + +getJobType() +} +class RepairJob { + +getJobType() +} +GoldJobCard -left-> MaintenanceJob:creates +GoldJobCard -right-> RepairJob:creates + + +@enduml \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-2/src/main/resources/Platinum.puml b/core-java-modules/core-java-reflection-2/src/main/resources/Platinum.puml new file mode 100644 index 0000000000..d9dc9b028d --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/resources/Platinum.puml @@ -0,0 +1,25 @@ +@startuml +'https://plantuml.com/class-diagram +interface Job { ++getJobType +} +class PlatinumJobCard { + +setJobType(Class jobTypeClass) + +startJob() +} + +class MaintenanceJob implements Job { + +getJobType() +} +class RepairJob implements Job { + +getJobType() +} +class PaintJob implements Job { + +getJobType() +} +PlatinumJobCard -up-> MaintenanceJob:creates +PlatinumJobCard -up-> RepairJob:creates +PlatinumJobCard -up-> PaintJob:creates + + +@enduml \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-2/src/main/resources/Silver.puml b/core-java-modules/core-java-reflection-2/src/main/resources/Silver.puml new file mode 100644 index 0000000000..46a9c88295 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/main/resources/Silver.puml @@ -0,0 +1,20 @@ +@startuml +'https://plantuml.com/class-diagram + +class SilverJobCard { + -Object jobType + +setJobType(Class jobTypeClass); + +startJob(); +} + +class MaintenanceJob { + +getJobType(); +} +class RepairJob { + +getJobType(); +} +SilverJobCard -left-> MaintenanceJob:creates +SilverJobCard -right-> RepairJob:creates + + +@enduml \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectBasicUnitTest.java b/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectBasicUnitTest.java new file mode 100644 index 0000000000..c8dcabf190 --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectBasicUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.reflection.createobject; + +import com.baeldung.reflection.createobject.basic.*; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InvocationTargetException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CreateObjectBasicUnitTest { + @Test + public void givenBronzeJobCard_whenJobTypeRepairAndMaintenance_thenStartJob() throws ClassNotFoundException, + InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + + BronzeJobCard bronzeJobCard1 = new BronzeJobCard(); + bronzeJobCard1.setJobType("com.baeldung.reflection.createobject.basic.RepairJob"); + assertEquals("Start Bronze Repair Job", bronzeJobCard1.startJob()); + + BronzeJobCard bronzeJobCard2 = new BronzeJobCard(); + bronzeJobCard2.setJobType("com.baeldung.reflection.createobject.basic.MaintenanceJob"); + assertEquals("Start Bronze Maintenance Job", bronzeJobCard2.startJob()); + } + @Test + public void givenBronzeJobCard_whenJobTypePaint_thenFailJob() throws ClassNotFoundException, + InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + + BronzeJobCard bronzeJobCard = new BronzeJobCard(); + bronzeJobCard.setJobType("com.baeldung.reflection.createobject.basic.PaintJob"); + assertEquals("Bronze Job Failed", bronzeJobCard.startJob()); + } + @Test + public void givenSilverJobCard_whenJobTypeRepairAndMaintenance_thenStartJob() throws InvocationTargetException, + NoSuchMethodException, InstantiationException, IllegalAccessException { + + SilverJobCard silverJobCard1 = new SilverJobCard(); + silverJobCard1.setJobType(RepairJob.class); + assertEquals("Start Silver Repair Job", silverJobCard1.startJob()); + + SilverJobCard silverJobCard2 = new SilverJobCard(); + silverJobCard2.setJobType(MaintenanceJob.class); + assertEquals("Start Silver Maintenance Job", silverJobCard2.startJob()); + } + @Test + public void givenSilverJobCard_whenJobTypePaint_thenFailJob() throws ClassNotFoundException, + InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + + SilverJobCard silverJobCard = new SilverJobCard(); + silverJobCard.setJobType(PaintJob.class); + assertEquals("Silver Job Failed", silverJobCard.startJob()); + } + @Test + public void givenGoldJobCard_whenJobTypeRepairMaintenanceAndPaint_thenStartJob() throws InvocationTargetException, + NoSuchMethodException, InstantiationException, IllegalAccessException { + + GoldJobCard goldJobCard1 = new GoldJobCard(); + goldJobCard1.setJobType(RepairJob.class); + assertEquals("Start Gold Repair Job", goldJobCard1.startJob()); + + GoldJobCard goldJobCard2 = new GoldJobCard(); + goldJobCard2.setJobType(MaintenanceJob.class); + assertEquals("Start Gold Maintenance Job", goldJobCard2.startJob()); + + GoldJobCard goldJobCard3 = new GoldJobCard(); + goldJobCard3.setJobType(PaintJob.class); + assertEquals("Start Gold Paint Job", goldJobCard3.startJob()); + } +} diff --git a/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectSpecialUnitTest.java b/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectSpecialUnitTest.java new file mode 100644 index 0000000000..99fdf7be2d --- /dev/null +++ b/core-java-modules/core-java-reflection-2/src/test/java/com/baeldung/reflection/createobject/CreateObjectSpecialUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.reflection.createobject; + +import com.baeldung.reflection.createobject.special.MaintenanceJob; +import com.baeldung.reflection.createobject.special.PaintJob; +import com.baeldung.reflection.createobject.special.PlatinumJobCard; +import com.baeldung.reflection.createobject.special.RepairJob; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InvocationTargetException; + +public class CreateObjectSpecialUnitTest { + @Test + public void givenPlatinumJobCard_whenJobTypeRepairMaintenanceAndPaint_thenStartJob() throws InvocationTargetException, + NoSuchMethodException, InstantiationException, IllegalAccessException { + + PlatinumJobCard platinumJobCard1 = new PlatinumJobCard(); + platinumJobCard1.setJobType(RepairJob.class); + assertEquals("Start Platinum Repair Job", platinumJobCard1.startJob()); + + PlatinumJobCard platinumJobCard2 = new PlatinumJobCard(); + platinumJobCard2.setJobType(MaintenanceJob.class); + assertEquals("Start Platinum Maintenance Job", platinumJobCard2.startJob()); + + PlatinumJobCard platinumJobCard3 = new PlatinumJobCard(); + platinumJobCard3.setJobType(PaintJob.class); + assertEquals("Start Platinum Paint Job", platinumJobCard3.startJob()); + } +} diff --git a/core-java-modules/core-java-reflection-3/README.md b/core-java-modules/core-java-reflection-3/README.md new file mode 100644 index 0000000000..023fb979e4 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Is Java Reflection Bad Practice?](https://www.baeldung.com/java-reflection-benefits-drawbacks) diff --git a/core-java-modules/core-java-reflection-3/pom.xml b/core-java-modules/core-java-reflection-3/pom.xml new file mode 100644 index 0000000000..fa5fe897e0 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + core-java-reflection-3 + core-java-reflection-3 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.springframework + spring-test + ${spring.version} + test + + + org.reflections + reflections + ${reflections.version} + + + + + core-java-reflection-3 + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${source.version} + ${target.version} + -parameters + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + + + + 0.9.12 + 1.8 + 1.8 + 5.3.4 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java new file mode 100644 index 0000000000..680079adea --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java @@ -0,0 +1,11 @@ +package com.baeldung.reflection.disadvantages.encapsulation; + +public class MyClass { + + private String veryPrivateField; + + public MyClass() { + + this.veryPrivateField = "Secret Information"; + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java new file mode 100644 index 0000000000..1de026f796 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.disadvantages.performance; + +public class BenchmarkRunner { + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java new file mode 100644 index 0000000000..e6c0c3daea --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java @@ -0,0 +1,29 @@ +package com.baeldung.reflection.disadvantages.performance; + +import org.openjdk.jmh.annotations.*; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.TimeUnit; + +public class InitializationBenchmark { + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void directInit() { + + Person person = new Person("John", "Doe", 50); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void reflectiveInit() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + Constructor constructor = Person.class.getDeclaredConstructor(String.class, String.class, Integer.class); + Person person = constructor.newInstance("John", "Doe", 50); + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java new file mode 100644 index 0000000000..1128cf8f33 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java @@ -0,0 +1,48 @@ +package com.baeldung.reflection.disadvantages.performance; + +import org.openjdk.jmh.annotations.*; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +public class MethodInvocationBenchmark { + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void directCall() { + + directCall(new Person("John", "Doe", 50)); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void reflectiveCall() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + + reflectiveCall(new Person("John", "Doe", 50)); + } + + + private void directCall(Person person) { + + person.getFirstName(); + person.getLastName(); + person.getAge(); + } + + private void reflectiveCall(Person person) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + + Method getFirstNameMethod = Person.class.getMethod("getFirstName"); + getFirstNameMethod.invoke(person); + + Method getLastNameMethod = Person.class.getMethod("getLastName"); + getLastNameMethod.invoke(person); + + Method getAgeMethod = Person.class.getMethod("getAge"); + getAgeMethod.invoke(person); + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java new file mode 100644 index 0000000000..014c82ba45 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java @@ -0,0 +1,38 @@ +package com.baeldung.reflection.disadvantages.performance; + +public class Person { + + private String firstName; + private String lastName; + private Integer age; + + public Person(String firstName, String lastName, Integer age) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java b/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java new file mode 100644 index 0000000000..efb0a7da31 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.reflection.disadvantages.encapsulation; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ReflectionEncapsulationUnitTest { + + @Test + public void givenPrivateField_whenUsingReflection_thenIsAccessible() throws IllegalAccessException, NoSuchFieldException { + MyClass myClassInstance = new MyClass(); + + Field privateField = MyClass.class.getDeclaredField("veryPrivateField"); + privateField.setAccessible(true); + + String accessedField = privateField.get(myClassInstance).toString(); + assertEquals(accessedField, "Secret Information"); + } +} diff --git a/core-java-modules/core-java-reflection/src/main/java/com/baeldung/reflection/Employee.java b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/reflection/Employee.java index 833cf26b14..43229b3d0e 100644 --- a/core-java-modules/core-java-reflection/src/main/java/com/baeldung/reflection/Employee.java +++ b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/reflection/Employee.java @@ -2,6 +2,7 @@ package com.baeldung.reflection; public class Employee extends Person { + public static final String LABEL = "employee"; public int employeeId; } diff --git a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java index cb1b5e926a..0a5764171b 100644 --- a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java +++ b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java @@ -1,6 +1,7 @@ package com.baeldung.reflection; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -9,128 +10,170 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; -import static org.junit.Assert.*; +import org.junit.Test; public class PersonAndEmployeeReflectionUnitTest { - // Fields names private static final String LAST_NAME_FIELD = "lastName"; private static final String FIRST_NAME_FIELD = "firstName"; private static final String EMPLOYEE_ID_FIELD = "employeeId"; + private static final String EMPLOYEE_TYPE_FIELD = "LABEL"; private static final String MONTH_EMPLOYEE_REWARD_FIELD = "reward"; @Test public void givenPersonClass_whenGetDeclaredFields_thenTwoFields() { - // When - Field[] allFields = Person.class.getDeclaredFields(); + List allFields = Arrays.asList(Person.class.getDeclaredFields()); - // Then - assertEquals(2, allFields.length); - - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(LAST_NAME_FIELD) - && field.getType().equals(String.class)) - ); - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(FIRST_NAME_FIELD) - && field.getType().equals(String.class)) - ); + assertEquals(2, allFields.size()); + Field lastName = allFields.stream() + .filter(field -> field.getName() + .equals(LAST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, lastName.getType()); + Field firstName = allFields.stream() + .filter(field -> field.getName() + .equals(FIRST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, firstName.getType()); } @Test - public void givenEmployeeClass_whenGetDeclaredFields_thenOneField() { - // When - Field[] allFields = Employee.class.getDeclaredFields(); + public void givenEmployeeClass_whenGetDeclaredFields_thenFilterAndReturnStaticField() { + List publicStaticField = Arrays.stream(Employee.class.getDeclaredFields()) + .filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) + .collect(Collectors.toList()); - // Then - assertEquals(1, allFields.length); - - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(EMPLOYEE_ID_FIELD) - && field.getType().equals(int.class)) - ); + assertEquals(1, publicStaticField.size()); + Field employeeTypeField = publicStaticField.get(0); + assertEquals(EMPLOYEE_TYPE_FIELD, employeeTypeField.getName()); } @Test - public void givenEmployeeClass_whenSuperClassGetDeclaredFields_thenOneField() { - // When - Field[] allFields = Employee.class.getSuperclass().getDeclaredFields(); + public void givenEmployeeClass_whenGetDeclaredFields_thenTwoField() { + List allFields = Arrays.asList(Employee.class.getDeclaredFields()); - // Then - assertEquals(2, allFields.length); - - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(LAST_NAME_FIELD) - && field.getType().equals(String.class)) - ); - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(FIRST_NAME_FIELD) - && field.getType().equals(String.class)) - ); + assertEquals(2, allFields.size()); + Field employeeIdField = allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_ID_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(int.class, employeeIdField.getType()); + Field employeeTypeField = allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_TYPE_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, employeeTypeField.getType()); } @Test - public void givenEmployeeClass_whenGetDeclaredFieldsOnBothClasses_thenThreeFields() { - // When - Field[] personFields = Employee.class.getSuperclass().getDeclaredFields(); - Field[] employeeFields = Employee.class.getDeclaredFields(); - Field[] allFields = new Field[employeeFields.length + personFields.length]; - Arrays.setAll(allFields, i -> (i < personFields.length ? personFields[i] : employeeFields[i - personFields.length])); + public void givenEmployeeClass_whenSuperClassGetDeclaredFields_thenTwoField() { + List allFields = Arrays.asList(Employee.class.getSuperclass() + .getDeclaredFields()); - // Then - assertEquals(3, allFields.length); + assertEquals(2, allFields.size()); + Field lastNameField = allFields.stream() + .filter(field -> field.getName() + .equals(LAST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, lastNameField.getType()); + Field firstNameField = allFields.stream() + .filter(field -> field.getName() + .equals(FIRST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, firstNameField.getType()); + } - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(LAST_NAME_FIELD) - && field.getType().equals(String.class)) - ); - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(FIRST_NAME_FIELD) - && field.getType().equals(String.class)) - ); - assertTrue(Arrays.stream(allFields).anyMatch(field -> - field.getName().equals(EMPLOYEE_ID_FIELD) - && field.getType().equals(int.class)) - ); + @Test + public void givenEmployeeClass_whenGetDeclaredFieldsOnBothClasses_thenFourFields() { + List personFields = Arrays.asList(Employee.class.getSuperclass() + .getDeclaredFields()); + List employeeFields = Arrays.asList(Employee.class.getDeclaredFields()); + List allFields = Stream.concat(personFields.stream(), employeeFields.stream()) + .collect(Collectors.toList()); + + assertEquals(4, allFields.size()); + Field lastNameField = allFields.stream() + .filter(field -> field.getName() + .equals(LAST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, lastNameField.getType()); + Field firstNameField = allFields.stream() + .filter(field -> field.getName() + .equals(FIRST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, firstNameField.getType()); + Field employeeIdField = allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_ID_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(int.class, employeeIdField.getType()); + Field employeeTypeField = allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_TYPE_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, employeeTypeField.getType()); } @Test public void givenEmployeeClass_whenGetDeclaredFieldsOnEmployeeSuperclassWithModifiersFilter_thenOneFields() { - // When - List personFields = Arrays.stream(Employee.class.getSuperclass().getDeclaredFields()) - .filter(f -> Modifier.isPublic(f.getModifiers()) || Modifier.isProtected(f.getModifiers())) - .collect(Collectors.toList()); + List personFields = Arrays.stream(Employee.class.getSuperclass() + .getDeclaredFields()) + .filter(f -> Modifier.isPublic(f.getModifiers()) || Modifier.isProtected(f.getModifiers())) + .collect(Collectors.toList()); - // Then assertEquals(1, personFields.size()); - - assertTrue(personFields.stream().anyMatch(field -> - field.getName().equals(LAST_NAME_FIELD) - && field.getType().equals(String.class)) - ); + Field personField = personFields.stream() + .filter(field -> field.getName() + .equals(LAST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")); + assertEquals(String.class, personField.getType()); } @Test - public void givenMonthEmployeeClass_whenGetAllFields_thenThreeFields() { - // When + public void givenMonthEmployeeClass_whenGetAllFields_thenFourFields() { List allFields = getAllFields(MonthEmployee.class); - // Then - assertEquals(3, allFields.size()); - - assertTrue(allFields.stream().anyMatch(field -> - field.getName().equals(LAST_NAME_FIELD) - && field.getType().equals(String.class)) - ); - assertTrue(allFields.stream().anyMatch(field -> - field.getName().equals(EMPLOYEE_ID_FIELD) - && field.getType().equals(int.class)) - ); - assertTrue(allFields.stream().anyMatch(field -> - field.getName().equals(MONTH_EMPLOYEE_REWARD_FIELD) - && field.getType().equals(double.class)) - ); + assertEquals(4, allFields.size()); + assertFalse(allFields.stream() + .anyMatch(field -> field.getName() + .equals(FIRST_NAME_FIELD))); + assertEquals(String.class, allFields.stream() + .filter(field -> field.getName() + .equals(LAST_NAME_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")) + .getType()); + assertEquals(int.class, allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_ID_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")) + .getType()); + assertEquals(double.class, allFields.stream() + .filter(field -> field.getName() + .equals(MONTH_EMPLOYEE_REWARD_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")) + .getType()); + assertEquals(String.class, allFields.stream() + .filter(field -> field.getName() + .equals(EMPLOYEE_TYPE_FIELD)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Field not found")) + .getType()); } public List getAllFields(Class clazz) { @@ -140,8 +183,8 @@ public class PersonAndEmployeeReflectionUnitTest { List result = new ArrayList<>(getAllFields(clazz.getSuperclass())); List filteredFields = Arrays.stream(clazz.getDeclaredFields()) - .filter(f -> Modifier.isPublic(f.getModifiers()) || Modifier.isProtected(f.getModifiers())) - .collect(Collectors.toList()); + .filter(f -> Modifier.isPublic(f.getModifiers()) || Modifier.isProtected(f.getModifiers())) + .collect(Collectors.toList()); result.addAll(filteredFields); return result; } diff --git a/core-java-modules/core-java-regex-2/README.md b/core-java-modules/core-java-regex-2/README.md index ccf60f56d9..404b33b65f 100644 --- a/core-java-modules/core-java-regex-2/README.md +++ b/core-java-modules/core-java-regex-2/README.md @@ -7,4 +7,7 @@ - [Creating a Java Array from Regular Expression Matches](https://www.baeldung.com/java-array-regex-matches) - [Getting the Text That Follows After the Regex Match in Java](https://www.baeldung.com/java-regex-text-after-match) - [Regular Expression: \z vs \Z Anchors in Java](https://www.baeldung.com/java-regular-expression-z-vs-z-anchors) +- [Extract Text Between Square Brackets](https://www.baeldung.com/java-get-content-between-square-brackets) +- [Get the Indexes of Regex Pattern Matches in Java](https://www.baeldung.com/java-indexes-regex-pattern-matches) +- [Check if a String is Strictly Alphanumeric With Java](https://www.baeldung.com/java-check-string-contains-only-letters-numbers) - More articles: [[<-- prev]](/core-java-modules/core-java-regex) diff --git a/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java b/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java new file mode 100644 index 0000000000..0525153ed9 --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java @@ -0,0 +1,91 @@ +package com.baeldung.alphanumeric; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1) +@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES) +@Fork(1) +public class AlphanumericPerformanceBenchmark { + + private static final String TEST_STRING = "ABC123abc123"; + private static final String REGEX = "[^[a-zA-Z0-9]*$]"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericRegex(Blackhole blackhole) { + final Matcher matcher = PATTERN.matcher(TEST_STRING); + boolean result = matcher.matches(); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericRegexDirectlyOnString(Blackhole blackhole) { + boolean result = TEST_STRING.matches(REGEX); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIteration(Blackhole blackhole) { + boolean result = true; + for (int i = 0; i < TEST_STRING.length(); ++i) { + final int codePoint = TEST_STRING.codePointAt(i); + if (!isAlphanumeric(codePoint)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithCharacterChecks(Blackhole blackhole) { + boolean result = true; + for (int i = 0; i < TEST_STRING.length(); ++i) { + final int codePoint = TEST_STRING.codePointAt(i); + if (!Character.isAlphabetic(codePoint) || !Character.isDigit(codePoint)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithCopy(Blackhole blackhole) { + boolean result = true; + for (final char c : TEST_STRING.toCharArray()) { + if (!isAlphanumeric(c)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithStream(Blackhole blackhole) { + boolean result = TEST_STRING.chars().allMatch(this::isAlphanumeric); + blackhole.consume(result); + } + + public boolean isAlphanumeric(final int codePoint) { + return (codePoint >= 65 && codePoint <= 90) || + (codePoint >= 97 && codePoint <= 122) || + (codePoint >= 48 && codePoint <= 57); + } +} diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java new file mode 100644 index 0000000000..b00bf7c4e3 --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.alphanumeric; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class AlphanumericUnitTest { + + private AlphanumericPerformanceBenchmark alphanumericPerformanceBenchmark = new AlphanumericPerformanceBenchmark(); + + @ParameterizedTest + @CsvSource({ + "A,true", + "B,true", + "C,true", + "1,true", + "2,true", + "3,true", + "!,false", + "@,false", + "#,false", + "$,false", + "%,false" + }) + void shouldCorrectlyIdentifyAlphanumericCharacterTest(char character, boolean result) { + boolean actual = alphanumericPerformanceBenchmark.isAlphanumeric(character); + assertEquals(actual, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/indexesofmatches/IndexesOfMatchesUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/indexesofmatches/IndexesOfMatchesUnitTest.java new file mode 100644 index 0000000000..7fb2afcdea --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/indexesofmatches/IndexesOfMatchesUnitTest.java @@ -0,0 +1,75 @@ +package com.baeldung.regex.indexesofmatches; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.jupiter.api.Test; + +public class IndexesOfMatchesUnitTest { + private static final String INPUT = "This line contains , , and ."; + + @Test + void whenUsingNorCharClass_thenGetExpectedTexts() { + Pattern pattern = Pattern.compile("<[^>]*>"); + Matcher matcher = pattern.matcher(INPUT); + List result = new ArrayList<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + assertThat(result).containsExactly("", "", ""); + } + + @Test + void whenCallingMatcherEnd_thenGetIndexesAfterTheMatchSequence() { + Pattern pattern = Pattern.compile("456"); + Matcher matcher = pattern.matcher("0123456789"); + String result = null; + int startIdx = -1; + int endIdx = -1; + if (matcher.find()) { + result = matcher.group(); + startIdx = matcher.start(); + endIdx = matcher.end(); + } + assertThat(result).isEqualTo("456"); + assertThat(startIdx).isEqualTo(4); + assertThat(endIdx).isEqualTo(7); + } + + @Test + void whenUsingMatcherStartAndEnd_thenGetIndexesOfMatches() { + Pattern pattern = Pattern.compile("<[^>]*>"); + Matcher matcher = pattern.matcher(INPUT); + List result = new ArrayList<>(); + Map indexesOfMatches = new LinkedHashMap<>(); + while (matcher.find()) { + result.add(matcher.group()); + indexesOfMatches.put(matcher.start(), matcher.end()); + } + assertThat(result).containsExactly("", "", ""); + assertThat(indexesOfMatches.entrySet()).map(entry -> INPUT.substring(entry.getKey(), entry.getValue())) + .containsExactly("", "", ""); + } + + @Test + void whenUsingMatcherStartAndEndWithGroupIdx_thenGetIndexesOfMatches() { + Pattern pattern = Pattern.compile("<([^>]*)>"); + Matcher matcher = pattern.matcher(INPUT); + List result = new ArrayList<>(); + Map indexesOfMatches = new LinkedHashMap<>(); + while (matcher.find()) { + result.add(matcher.group(1)); + indexesOfMatches.put(matcher.start(1), matcher.end(1)); + } + assertThat(result).containsExactly("the first value", "the second value", "the third value"); + + assertThat(indexesOfMatches.entrySet()).map(entry -> INPUT.substring(entry.getKey(), entry.getValue())) + .containsExactly("the first value", "the second value", "the third value"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java new file mode 100644 index 0000000000..2ea80a1f69 --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java @@ -0,0 +1,98 @@ +package com.baeldung.regex.squarebrackets; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ExtractTextBetweenSquareBracketsUnitTest { + static final String INPUT1 = "some text [THE IMPORTANT MESSAGE] something else"; + static final String EXPECTED1 = "THE IMPORTANT MESSAGE"; + + static final String INPUT2 = "[La La Land], [The last Emperor], and [Life of Pi] are all great movies."; + static final List EXPECTED2 = Lists.newArrayList("La La Land", "The last Emperor", "Life of Pi"); + + @Test + void whenUsingDotStarOnInput1_thenGetExpectedResult() { + String result = null; + String rePattern = "\\[(.*)]"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT1); + if (m.find()) { + result = m.group(1); + } + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingCharClassOnInput1_thenGetExpectedResult() { + String result = null; + String rePattern = "\\[([^]]*)"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT1); + if (m.find()) { + result = m.group(1); + } + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingSplitOnInput1_thenGetExpectedResult() { + String[] strArray = INPUT1.split("[\\[\\]]", -1); + String result = strArray.length == 3 ? strArray[1] : null; + + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingSplitWithLimit_thenGetExpectedResult() { + String[] strArray = "[THE IMPORTANT MESSAGE]".split("[\\[\\]]"); + assertThat(strArray).hasSize(2) + .containsExactly("", "THE IMPORTANT MESSAGE"); + + strArray = "[THE IMPORTANT MESSAGE]".split("[\\[\\]]", -1); + assertThat(strArray).hasSize(3) + .containsExactly("", "THE IMPORTANT MESSAGE", ""); + } + + @Test + void whenUsingNonGreedyOnInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String rePattern = "\\[(.*?)]"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT2); + while (m.find()) { + result.add(m.group(1)); + } + assertThat(result).isEqualTo(EXPECTED2); + } + + @Test + void whenUsingCharClassOnInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String rePattern = "\\[([^]]*)"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT2); + while (m.find()) { + result.add(m.group(1)); + } + assertThat(result).isEqualTo(EXPECTED2); + } + + @Test + void whenUsingSplitInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String[] strArray = INPUT2.split("[\\[\\]]", -1); + for (int i = 1; i < strArray.length; i += 2) { + result.add(strArray[i]); + } + assertThat(result).isEqualTo(EXPECTED2); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-scanner/README.md b/core-java-modules/core-java-scanner/README.md index 87bd9c41bc..6208dda964 100644 --- a/core-java-modules/core-java-scanner/README.md +++ b/core-java-modules/core-java-scanner/README.md @@ -11,5 +11,5 @@ This module contains articles about the Scanner. - [Integer.parseInt(scanner.nextLine()) and scanner.nextInt() in Java](https://www.baeldung.com/java-scanner-integer) - [Storing Java Scanner Input in an Array](https://www.baeldung.com/java-store-scanner-input-in-array) - [How to Take Input as String With Spaces in Java Using Scanner?](https://www.baeldung.com/java-scanner-input-with-spaces) -- [What’s the difference between Scanner next() and nextLine() methods?](https://www.baeldung.com/java-scanner-next-vs-nextline) +- [What’s the Difference between Scanner next() and nextLine() Methods?](https://www.baeldung.com/java-scanner-next-vs-nextline) - [Handle NoSuchElementException When Reading a File Through Scanner](https://www.baeldung.com/java-scanner-nosuchelementexception-reading-file) diff --git a/core-java-modules/core-java-scanner/pom.xml b/core-java-modules/core-java-scanner/pom.xml index f149f51955..bb5c7dca78 100644 --- a/core-java-modules/core-java-scanner/pom.xml +++ b/core-java-modules/core-java-scanner/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-scanner core-java-scanner diff --git a/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java b/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java index b013ff4ed1..4f40c3c195 100644 --- a/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java +++ b/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java @@ -28,9 +28,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.jupiter.api.Disabled; - -@Disabled //fixing in https://team.baeldung.com/browse/JAVA-23897 public class CertificatesUnitTest { private static final String GODADDY_CA_ALIAS = "godaddyrootg2ca [jdk]"; diff --git a/core-java-modules/core-java-security-3/pom.xml b/core-java-modules/core-java-security-3/pom.xml index ad9feeb36a..b979b56658 100644 --- a/core-java-modules/core-java-security-3/pom.xml +++ b/core-java-modules/core-java-security-3/pom.xml @@ -33,7 +33,7 @@ com.google.guava guava - ${google-guava.version} + ${guava.version} org.springframework.security @@ -47,7 +47,6 @@ 1.15 2.3.1 6.0.3 - 31.0.1-jre \ No newline at end of file diff --git a/core-java-modules/core-java-security-4/README.md b/core-java-modules/core-java-security-4/README.md new file mode 100644 index 0000000000..236715713b --- /dev/null +++ b/core-java-modules/core-java-security-4/README.md @@ -0,0 +1,8 @@ +## Core Java Security + +This module contains articles about core Java Security + +### Relevant Articles: +- [Check if Certificate Is Self-Signed or CA-Signed With Java](https://www.baeldung.com/java-check-certificate-sign) +- [Extract CN From X509 Certificate in Java](https://www.baeldung.com/java-extract-common-name-x509-certificate) +- More articles: [[<-- prev]](/core-java-modules/core-java-security-3) diff --git a/core-java-modules/core-java-security-4/pom.xml b/core-java-modules/core-java-security-4/pom.xml new file mode 100644 index 0000000000..2b9809b749 --- /dev/null +++ b/core-java-modules/core-java-security-4/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + core-java-security-4 + core-java-security-4 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.bouncycastle + bcpkix-jdk15on + ${bouncycastle.version} + + + org.cryptacular + cryptacular + ${cryptacular.version} + + + + + 1.70 + 1.2.6 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java b/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java new file mode 100644 index 0000000000..3e8445971f --- /dev/null +++ b/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java @@ -0,0 +1,51 @@ +package com.baeldung.certificate; + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; + +public class RootCertificateUtil { + + private RootCertificateUtil() { + } + + public static X509Certificate getRootCertificate(X509Certificate endEntityCertificate, KeyStore trustStore) + throws Exception { + X509Certificate issuerCertificate = findIssuerCertificate(endEntityCertificate, trustStore); + if (issuerCertificate != null) { + if (isRoot(issuerCertificate)) { + return issuerCertificate; + } else { + return getRootCertificate(issuerCertificate, trustStore); + } + } + return null; + } + + private static X509Certificate findIssuerCertificate(X509Certificate certificate, KeyStore trustStore) + throws KeyStoreException { + Enumeration aliases = trustStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + Certificate cert = trustStore.getCertificate(alias); + if (cert instanceof X509Certificate) { + X509Certificate x509Cert = (X509Certificate) cert; + if (x509Cert.getSubjectX500Principal().equals(certificate.getIssuerX500Principal())) { + return x509Cert; + } + } + } + return null; + } + + private static boolean isRoot(X509Certificate certificate) { + try { + certificate.verify(certificate.getPublicKey()); + return certificate.getKeyUsage() != null && certificate.getKeyUsage()[5]; + } catch (Exception e) { + return false; + } + } +} diff --git a/core-java-modules/core-java-security-4/src/main/resources/Baeldung.cer b/core-java-modules/core-java-security-4/src/main/resources/Baeldung.cer new file mode 100644 index 0000000000..72d0918424 --- /dev/null +++ b/core-java-modules/core-java-security-4/src/main/resources/Baeldung.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV +BAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREw +DwYDVQQDEwhCYWVsZHVuZzAeFw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRa +MEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNh +YmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5tGMh +jozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oM +AYm24xpLj1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6Iujr +CZ2TtXGM0g/gP++28KT7g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSj +fs8cuhqVwRQaZpCOoHU/P8wpXKw80sSdhz+SRueMPtVYqK0CiLL5/O0h0Y3le4IV +whgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMtMCswCQYDVR0TBAIwADAR +BglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4IB +AQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1 +vpswb5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAP +pHIqZsqo8lfcyAuh8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhU +CGPyIJXmvATMVvXMWCtfogAL+n42vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJt +XJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1PD7OxoGiY7V544zeGqJam1qxU +ia7y5BL6uOa/4ShSV8pcJDYz +-----END CERTIFICATE----- diff --git a/core-java-modules/core-java-security-4/src/main/resources/keystore.jks b/core-java-modules/core-java-security-4/src/main/resources/keystore.jks new file mode 100644 index 0000000000..656c6c17d3 Binary files /dev/null and b/core-java-modules/core-java-security-4/src/main/resources/keystore.jks differ diff --git a/core-java-modules/core-java-security-4/src/main/resources/truststore.jks b/core-java-modules/core-java-security-4/src/main/resources/truststore.jks new file mode 100644 index 0000000000..5e1a9b4ce1 Binary files /dev/null and b/core-java-modules/core-java-security-4/src/main/resources/truststore.jks differ diff --git a/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/ExtractCommonNameUnitTest.java b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/ExtractCommonNameUnitTest.java new file mode 100644 index 0000000000..91e40453ea --- /dev/null +++ b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/ExtractCommonNameUnitTest.java @@ -0,0 +1,94 @@ +package com.baeldung.certificate; + +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x500.style.IETFUtils; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.cryptacular.util.CertUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; +import javax.security.auth.x500.X500Principal; +import java.io.FileInputStream; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ExtractCommonNameUnitTest { + + private static final String EXPECTED_CN = "Baeldung"; + + private String certificatePath = "src/main/resources/Baeldung.cer"; + + private X509Certificate certificate; + + @BeforeEach + public void setUp() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC"); + certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(certificatePath)); + } + + @Test + void whenUsingBouncyCastle_thenExtractCommonName() { + X500Principal principal = certificate.getSubjectX500Principal(); + X500Name x500Name = new X500Name(principal.getName()); + RDN[] rdns = x500Name.getRDNs(BCStyle.CN); + List names = new ArrayList<>(); + for (RDN rdn : rdns) { + String name = IETFUtils.valueToString(rdn.getFirst().getValue()); + names.add(name); + } + + for (String commonName : names) { + assertEquals(EXPECTED_CN, commonName); + } + } + + @Test + void whenUsingLDAPAPI_thenExtractCommonName() throws Exception { + X500Principal principal = certificate.getSubjectX500Principal(); + LdapName ldapDN = new LdapName(principal.getName()); + List names = new ArrayList<>(); + for (Rdn rdn : ldapDN.getRdns()) { + if (rdn.getType().equalsIgnoreCase("cn")) { + String name = rdn.getValue().toString(); + names.add(name); + } + } + + for (String commonName : names) { + assertEquals(EXPECTED_CN, commonName); + } + } + + @Test + void whenUsingCryptacular_thenExtractCommonName() { + String commonName = CertUtil.subjectCN(certificate); + assertEquals(EXPECTED_CN, commonName); + } + + @Test + void whenUsingRegex_thenExtractCommonName() { + X500Principal principal = certificate.getSubjectX500Principal(); + List names = new ArrayList<>(); + Pattern pattern = Pattern.compile("CN=([^,]+)"); + Matcher matcher = pattern.matcher(principal.getName()); + while (matcher.find()) { + names.add(matcher.group(1)); + } + + for (String commonName : names) { + assertEquals(EXPECTED_CN, commonName); + } + } +} diff --git a/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java new file mode 100644 index 0000000000..f5ea3c1b87 --- /dev/null +++ b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.certificate; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.cert.X509Certificate; + +import static com.baeldung.certificate.RootCertificateUtil.getRootCertificate; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SignedCertificateUnitTest { + + private KeyStore keyStore; + + private KeyStore trustStore; + + @BeforeEach + public void setUp() throws Exception { + char[] passwd = "changeit".toCharArray(); + keyStore = KeyStore.getInstance("JKS"); + keyStore.load(this.getClass().getClassLoader().getResourceAsStream("keystore.jks"), passwd); + trustStore = KeyStore.getInstance("JKS"); + trustStore.load(this.getClass().getClassLoader().getResourceAsStream("truststore.jks"), passwd); + } + + @Test + void whenCertificateIsSelfSigned_thenSubjectIsEqualToIssuer() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertEquals(certificate.getSubjectDN(), certificate.getIssuerDN()); + } + + @Test + void whenCertificateIsSelfSigned_thenItCanBeVerifiedWithItsOwnPublicKey() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertDoesNotThrow(() -> certificate.verify(certificate.getPublicKey())); + } + + @Test + void whenCertificateIsCASigned_thenItCantBeVerifiedWithItsOwnPublicKey() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("baeldung"); + assertThrows(SignatureException.class, () -> certificate.verify(certificate.getPublicKey())); + } + + @Test + void whenCertificateIsCASigned_thenRootCanBeFoundInTruststore() throws Exception { + X509Certificate endEntityCertificate = (X509Certificate) keyStore.getCertificate("baeldung"); + X509Certificate rootCertificate = getRootCertificate(endEntityCertificate, trustStore); + assertNotNull(rootCertificate); + } + + @Test + void whenCertificateIsCA_thenItCanBeUsedToSignOtherCertificates() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("cloudflare"); + assertTrue(certificate.getKeyUsage()[5]); + } + + @Test + void whenCertificateIsCA_thenBasicConstrainsReturnsZeroOrGreaterThanZero() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("cloudflare"); + assertNotEquals(-1, certificate.getBasicConstraints()); + } + + @Test + void whenCertificateIsSelfSigned_thenItCantBeUsedToSignOtherCertificates() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertNull(certificate.getKeyUsage()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-security-algorithms/pom.xml b/core-java-modules/core-java-security-algorithms/pom.xml index 0dde9f861a..0204203fd7 100644 --- a/core-java-modules/core-java-security-algorithms/pom.xml +++ b/core-java-modules/core-java-security-algorithms/pom.xml @@ -13,28 +13,4 @@ 0.0.1-SNAPSHOT - - - commons-codec - commons-codec - ${commons-codec.version} - - - org.bouncycastle - bcprov-jdk15on - ${bouncycastle.version} - - - javax.xml.bind - jaxb-api - ${jaxb-api.version} - - - - - 1.60 - 1.11 - 2.3.1 - - \ No newline at end of file diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java index 36dee603eb..6f2e3250fc 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java @@ -7,7 +7,7 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class SecureConnection { - + public static void main(String[] args) { if (args.length != 2) { System.out.println("Use: SecureConnection host port"); @@ -20,20 +20,20 @@ public class SecureConnection { SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port); InputStream in = sslsocket.getInputStream(); OutputStream out = sslsocket.getOutputStream(); - + out.write(1); - + while (in.available() > 0) { System.out.print(in.read()); } - + System.out.println("Secured connection performed successfully"); - + } catch (Exception exception) { exception.printStackTrace(); } } - + /** * Get the host from arguments * @param args the arguments @@ -42,7 +42,7 @@ public class SecureConnection { private static String getHost(String[] args) { return args[0]; } - + /** * Get the port from arguments * @param args the arguments diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java index d6efc34c3e..cf9a76b39a 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java @@ -15,10 +15,8 @@ public class SimpleClient { SocketFactory factory = SSLSocketFactory.getDefault(); try (Socket connection = factory.createSocket(host, port)) { - ((SSLSocket) connection).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLSocket) connection).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLSocket) connection).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLSocket) connection).setEnabledProtocols(new String[] { "TLSv1.2" }); SSLParameters sslParams = new SSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); ((SSLSocket) connection).setSSLParameters(sslParams); @@ -28,6 +26,7 @@ public class SimpleClient { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); System.out.println(startClient("localhost", 8443)); } } diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java index 27d15d04d7..83946ccc1f 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java @@ -14,11 +14,10 @@ public class SimpleServer { ServerSocketFactory factory = SSLServerSocketFactory.getDefault(); try (ServerSocket listener = factory.createServerSocket(port)) { + System.setProperty("javax.net.debug", "ssl:handshake"); ((SSLServerSocket) listener).setNeedClientAuth(true); - ((SSLServerSocket) listener).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLServerSocket) listener).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLServerSocket) listener).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLServerSocket) listener).setEnabledProtocols(new String[] { "TLSv1.2" }); while (true) { try (Socket socket = listener.accept()) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); @@ -29,6 +28,7 @@ public class SimpleServer { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); startServer(8443); } } \ No newline at end of file diff --git a/core-java-modules/core-java-serialization/pom.xml b/core-java-modules/core-java-serialization/pom.xml index 5a6f256687..63771d2da0 100644 --- a/core-java-modules/core-java-serialization/pom.xml +++ b/core-java-modules/core-java-serialization/pom.xml @@ -53,6 +53,12 @@ ${spring.core.version} test + + org.projectlombok + lombok + ${lombok.version} + provided + diff --git a/core-java-modules/core-java-streams-2/README.md b/core-java-modules/core-java-streams-2/README.md index 2ff95045c3..2de80ebc67 100644 --- a/core-java-modules/core-java-streams-2/README.md +++ b/core-java-modules/core-java-streams-2/README.md @@ -4,12 +4,9 @@ This module contains articles about the Stream API in Java. ### Relevant Articles: - [The Java 8 Stream API Tutorial](https://www.baeldung.com/java-8-streams) -- [Introduction to Java 8 Streams](https://www.baeldung.com/java-8-streams-introduction) - [Java 8 Stream findFirst() vs. findAny()](https://www.baeldung.com/java-stream-findfirst-vs-findany) -- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce) - [Java IntStream Conversions](https://www.baeldung.com/java-intstream-convert) - [Java 8 Streams peek() API](https://www.baeldung.com/java-streams-peek-api) -- [Working With Maps Using Streams](https://www.baeldung.com/java-maps-streams) - [Collect a Java Stream to an Immutable Collection](https://www.baeldung.com/java-stream-immutable-collection) - [How to Add a Single Element to a Stream](https://www.baeldung.com/java-stream-append-prepend) - [Operating on and Removing an Item from Stream](https://www.baeldung.com/java-use-remove-item-stream) diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamApiUnitTest.java b/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamApiUnitTest.java index c4e1f2b3cb..53978f04b5 100644 --- a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamApiUnitTest.java +++ b/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamApiUnitTest.java @@ -1,6 +1,7 @@ package com.baeldung.streams; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +38,7 @@ public class Java8StreamApiUnitTest { assertEquals(list.size() - 1, size); } + @Ignore @Test public void checkOrder_whenChangeQuantityOfMethodCalls_thenCorrect() { diff --git a/core-java-modules/core-java-streams-3/README.md b/core-java-modules/core-java-streams-3/README.md index 48ebf145d2..70d9e68a5e 100644 --- a/core-java-modules/core-java-streams-3/README.md +++ b/core-java-modules/core-java-streams-3/README.md @@ -2,8 +2,7 @@ This module contains articles about the Stream API in Java. -### Relevant Articles: -- [The Difference Between map() and flatMap()](https://www.baeldung.com/java-difference-map-and-flatmap) +### Relevant Articles: - [How to Use if/else Logic in Java 8 Streams](https://www.baeldung.com/java-8-streams-if-else-logic) - [The Difference Between Collection.stream().forEach() and Collection.forEach()](https://www.baeldung.com/java-collection-stream-foreach) - [Primitive Type Streams in Java 8](https://www.baeldung.com/java-8-primitive-streams) @@ -12,5 +11,4 @@ This module contains articles about the Stream API in Java. - [Should We Close a Java Stream?](https://www.baeldung.com/java-stream-close) - [Returning Stream vs. Collection](https://www.baeldung.com/java-return-stream-collection) - [Convert a Java Enumeration Into a Stream](https://www.baeldung.com/java-enumeration-to-stream) -- [When to Use a Parallel Stream in Java](https://www.baeldung.com/java-when-to-use-parallel-stream) - More articles: [[<-- prev>]](/../core-java-streams-2) diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index fe791ebd42..e832cc1616 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -39,7 +39,7 @@ org.assertj assertj-core - 3.23.1 + ${assertj.version} test @@ -55,7 +55,7 @@ org.apache.commons commons-lang3 - 3.12.0 + ${commons-lang3.version} test @@ -81,7 +81,7 @@ com.google.guava guava - ${google.guava.version} + ${guava.version} com.oath.cyclops @@ -114,7 +114,7 @@ - 3.1 + 3.23.1 12 12 1.2.5 @@ -123,7 +123,6 @@ 1.0.0-alpha-4 3.5.1 4.4 - 31.1-jre 10.4.1 diff --git a/core-java-modules/core-java-streams-5/README.md b/core-java-modules/core-java-streams-5/README.md index c0df5990c4..629d52f0a9 100644 --- a/core-java-modules/core-java-streams-5/README.md +++ b/core-java-modules/core-java-streams-5/README.md @@ -1,3 +1,7 @@ ## Relevant Articles - [Difference Between parallelStream() and stream().parallel() in Java](https://www.baeldung.com/java-parallelstream-vs-stream-parallel) - [Working With Empty Stream in Java](https://www.baeldung.com/java-empty-stream) +- [Aggregate Runtime Exceptions in Java Streams](https://www.baeldung.com/java-streams-aggregate-exceptions) +- [Streams vs. Loops in Java](https://www.baeldung.com/java-streams-vs-loops) +- [Partition a Stream in Java](https://www.baeldung.com/java-partition-stream) +- [Taking Every N-th Element from Finite and Infinite Streams in Java](https://www.baeldung.com/java-nth-element-finite-infinite-streams) diff --git a/core-java-modules/core-java-streams-5/pom.xml b/core-java-modules/core-java-streams-5/pom.xml index d1f8af6461..d7baf84d30 100644 --- a/core-java-modules/core-java-streams-5/pom.xml +++ b/core-java-modules/core-java-streams-5/pom.xml @@ -38,6 +38,16 @@ 3.12.0 test + + io.vavr + vavr + ${vavr.version} + + + com.google.guava + guava + ${guava.version} + @@ -64,9 +74,10 @@ - 3.1 12 12 + 0.10.2 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomCollector.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomCollector.java new file mode 100644 index 0000000000..dea3d3f44c --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomCollector.java @@ -0,0 +1,38 @@ +package com.baeldung.aggregateexception; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collector; + +public class CustomCollector { + private final List results = new ArrayList<>(); + private final List exceptions = new ArrayList<>(); + + public static Collector> of(Function mapper) { + return Collector.of( + CustomCollector::new, + (collector, item) -> { + try { + R result = mapper.apply(item); + collector.results.add(result); + } catch (Exception e) { + collector.exceptions.add(e); + } + }, + (left, right) -> { + left.results.addAll(right.results); + left.exceptions.addAll(right.exceptions); + return left; + } + ); + } + + public List getResults() { + return results; + } + + public List getExceptions() { + return exceptions; + } +} diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomMapper.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomMapper.java new file mode 100644 index 0000000000..920c963337 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/CustomMapper.java @@ -0,0 +1,17 @@ +package com.baeldung.aggregateexception; + +import com.baeldung.aggregateexception.entity.Result; + +import java.util.function.Function; + +public class CustomMapper { + public static Function> mapper(Function func) { + return arg -> { + try { + return new Result(func.apply(arg)); + } catch (Exception e) { + return new Result(e); + } + }; + } +} diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/entity/Result.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/entity/Result.java new file mode 100644 index 0000000000..b723c3e510 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/aggregateexception/entity/Result.java @@ -0,0 +1,26 @@ +package com.baeldung.aggregateexception.entity; + +import java.util.Optional; + +public class Result { + private Optional result; + private Optional exception; + + public Result(R result) { + this.result = Optional.of(result); + this.exception = Optional.empty(); + } + + public Result(E exception) { + this.exception = Optional.of(exception); + this.result = Optional.empty(); + } + + public Optional getResult() { + return result; + } + + public Optional getException() { + return exception; + } +} diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/skippingelements/SkippingCollector.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/skippingelements/SkippingCollector.java new file mode 100644 index 0000000000..c6530f4940 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/skippingelements/SkippingCollector.java @@ -0,0 +1,36 @@ +package com.baeldung.skippingelements; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BinaryOperator; +import java.util.stream.Collector; + +class SkippingCollector { + + private static final BinaryOperator IGNORE_COMBINE = (a, b) -> a; + private final int skip; + private final List list = new ArrayList<>(); + private int currentIndex = 0; + + private SkippingCollector(int skip) { + this.skip = skip; + } + + private void accept(String item) { + final int index = ++currentIndex % skip; + if (index == 0) { + list.add(item); + } + } + + private List getResult() { + return list; + } + + public static Collector> collector(int skip) { + return Collector.of(() -> new SkippingCollector(skip), + SkippingCollector::accept, + IGNORE_COMBINE, + SkippingCollector::getResult); + } +} diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java new file mode 100644 index 0000000000..1ef3fa7707 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java @@ -0,0 +1,90 @@ +package com.baeldung.streams.partitioning; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import com.google.common.collect.Iterables; + +public class PartitionStream { + + public static Stream> partitionList(List source, int batchSize) { + if (batchSize <= 0) { + throw new IllegalArgumentException(String.format("Expected the batchSize to be greater than ZERO, actual value was: %s", batchSize)); + } + if (source.isEmpty()) { + return Stream.empty(); + } + int nrOfFullBatches = (source.size() - 1) / batchSize; + return IntStream.rangeClosed(0, nrOfFullBatches) + .mapToObj(batch -> { + int startIndex = batch * batchSize; + int endIndex = (batch == nrOfFullBatches) ? source.size() : (batch + 1) * batchSize; + return source.subList(startIndex, endIndex); + }); + } + + public static Iterable> partitionUsingGuava(Stream source, int batchSize) { + return Iterables.partition(source::iterator, batchSize); + } + + public static List> partitionStream(Stream source, int batchSize) { + return source.collect(partitionBySize(batchSize, Collectors.toList())); + } + + public static Collector partitionBySize(int batchSize, Collector, A, R> downstream) { + Supplier> supplier = () -> new Accumulator<>( + batchSize, + downstream.supplier().get(), + downstream.accumulator()::accept + ); + + BiConsumer, T> accumulator = (acc, value) -> acc.add(value); + + BinaryOperator> combiner = (acc1, acc2) -> acc1.combine(acc2, downstream.combiner()); + + Function, R> finisher = acc -> { + if (!acc.values.isEmpty()) { + downstream.accumulator().accept(acc.downstreamAccumulator, acc.values); + } + return downstream.finisher().apply(acc.downstreamAccumulator); + }; + + return Collector.of(supplier, accumulator, combiner, finisher, Collector.Characteristics.UNORDERED); + } + + static class Accumulator { + private final List values = new ArrayList<>(); + private final int batchSize; + private A downstreamAccumulator; + private final BiConsumer> batchFullListener; + + Accumulator(int batchSize, A accumulator, BiConsumer> onBatchFull) { + this.batchSize = batchSize; + this.downstreamAccumulator = accumulator; + this.batchFullListener = onBatchFull; + } + + void add(T value) { + values.add(value); + if (values.size() == batchSize) { + batchFullListener.accept(downstreamAccumulator, new ArrayList<>(values)); + values.clear(); + } + } + + Accumulator combine(Accumulator other, BinaryOperator accumulatorCombiner) { + this.downstreamAccumulator = accumulatorCombiner.apply(downstreamAccumulator, other.downstreamAccumulator); + other.values.forEach(this::add); + return this; + } + } + +} diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java new file mode 100644 index 0000000000..6c1ee9b2dd --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java @@ -0,0 +1,111 @@ +package com.baeldung.streams.streamsvsloops; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class PerformanceBenchmark { + + @State(Scope.Thread) + public static class MyState { + List numbers; + + @Setup(Level.Trial) + public void setUp() { + numbers = new ArrayList<>(); + for (int i = 0; i < 1_000_000; i++) { + numbers.add(i); + } + } + } + + @Benchmark + public int forLoopBenchmark(MyState state) { + int sum = 0; + for (int number : state.numbers) { + if (number % 2 == 0) { + sum = sum + (number * number); + } + } + return sum; + } + + @Benchmark + public int parallelStreamBenchMark(MyState state) { + return state.numbers.parallelStream() + .filter(number -> number % 2 == 0) + .map(number -> number * number) + .reduce(0, Integer::sum); + } + + @Benchmark + public int concurrentForLoopBenchmark(MyState state) throws InterruptedException, ExecutionException { + int numThreads = Runtime.getRuntime().availableProcessors(); + ExecutorService executorService = Executors.newFixedThreadPool(numThreads); + List> tasks = new ArrayList<>(); + int chunkSize = state.numbers.size() / numThreads; + + for (int i = 0; i < numThreads; i++) { + final int start = i * chunkSize; + final int end = (i == numThreads - 1) ? state.numbers.size() : (i + 1) * chunkSize; + tasks.add(() -> { + int sum = 0; + for (int j = start; j < end; j++) { + int number = state.numbers.get(j); + if (number % 2 == 0) { + sum = sum + (number * number); + } + } + return sum; + }); + } + + int totalSum = 0; + for (Future result : executorService.invokeAll(tasks)) { + totalSum += result.get(); + } + + executorService.shutdown(); + return totalSum; + } + + @Benchmark + public int streamBenchMark(MyState state) { + return state.numbers.stream() + .filter(number -> number % 2 == 0) + .map(number -> number * number) + .reduce(0, Integer::sum); + } + + public static void main(String[] args) throws RunnerException { + Options options = new OptionsBuilder().include(PerformanceBenchmark.class.getSimpleName()) + .build(); + new Runner(options).run(); + } +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/aggregateexception/AggregateExceptionHandlerUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/aggregateexception/AggregateExceptionHandlerUnitTest.java new file mode 100644 index 0000000000..6410645d2a --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/aggregateexception/AggregateExceptionHandlerUnitTest.java @@ -0,0 +1,150 @@ +package com.baeldung.aggregateexception; + +import com.baeldung.aggregateexception.entity.Result; +import io.vavr.control.Either; +import io.vavr.control.Try; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; + + +public class AggregateExceptionHandlerUnitTest { + private static final Logger logger = LoggerFactory.getLogger(AggregateExceptionHandlerUnitTest.class); + + @Test + public void givenExtractedMethod_whenFoundEx_thenSuppressExIntoRuntimeEx() { + String[] strings = {"1", "2", "3", "a", "b", "c"}; + RuntimeException runEx = Arrays.stream(strings) + .map(str -> callProcessThrowsExAndNoOutput(str)) + .filter(Objects::nonNull) + .reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> { + o1.addSuppressed(o2); + return o1; + }); + processExceptions(runEx); + assertEquals("Errors Occurred", runEx.getMessage()); + assertEquals(3, runEx.getSuppressed().length); + } + @Test + public void givenTryCatchInPipeline_whenFoundEx_thenSuppressExIntoRuntimeEx() { + String[] strings = {"1", "2", "3", "a", "b", "c"}; + RuntimeException runEx = Arrays.stream(strings).map(str -> { + try { + processThrowsExAndNoOutput(str); + return null; + } catch (RuntimeException e) { + return e; + } + }).filter(Objects::nonNull) + .collect(Collectors.collectingAndThen(Collectors.toList(), list -> { + RuntimeException runtimeException = new RuntimeException("Errors Occurred"); + list.forEach(runtimeException::addSuppressed); + return runtimeException; + })); + processExceptions(runEx); + assertEquals("Errors Occurred", runEx.getMessage()); + assertEquals(3, runEx.getSuppressed().length); + } + + @Test + public void givenProcessMethod_whenStreamResultHasExAndOutput_thenHandleExceptionListAndOutputList() { + List strings = List.of("1", "2", "3", "a", "b", "c"); + Map map = strings.stream() + .map(s -> processReturnsExAndOutput(s)) + .collect(Collectors.partitioningBy(o -> o instanceof RuntimeException, Collectors.toList())); + + List exceptions = (List)map.getOrDefault(Boolean.TRUE, List.of()); + List results = (List)map.getOrDefault(Boolean.FALSE, List.of()); + handleExceptionsAndOutputs(exceptions, results); + } + + @Test + public void givenCustomMapper_whenStreamResultHasExAndSuccess_thenHandleExceptionListAndOutputList() { + List strings = List.of("1", "2", "3", "a", "b", "c"); + strings.stream() + .map(CustomMapper.mapper(Integer::parseInt)) + .collect(Collectors.collectingAndThen(Collectors.toList(), list -> handleErrorsAndOutputForResult(list))); + } + + @Test + public void givenCustomCollector_whenStreamResultHasExAndSuccess_thenHandleAggrExceptionAndResults() { + String[] strings = {"1", "2", "3", "a", "b", "c"}; + Arrays.stream(strings) + .collect(Collectors.collectingAndThen(CustomCollector.of(Integer::parseInt), + col -> handleExAndResults(col.getExceptions(), col.getResults()))); + } + + @Test + public void givenVavrEitherAndTry_whenStreamResultHasExAndSuccess_thenHandleExceptionListAndOutputList() { + List strings = List.of("1", "2", "3", "a", "b", "c"); + strings.stream() + .map(str -> Try.of(() -> Integer.parseInt(str)).toEither()) + .collect(Collectors.collectingAndThen(Collectors.partitioningBy(Either::isLeft, Collectors.toList()), + map -> handleErrorsAndOutputForEither(map))); + } + + private static void processThrowsExAndNoOutput(String input) { + //throw exception when input is "a", "b", "c" + if (input.matches("[a-c]")) { + throw new RuntimeException("Downstream method throws exception for " + input); + } + } + private static RuntimeException callProcessThrowsExAndNoOutput(String input) { + try { + processThrowsExAndNoOutput(input); + return null; + } catch (RuntimeException e) { + return e; + } + } + + private static Object processReturnsExAndOutput(String input) { + logger.info("call a downstream method that returns an Integer"); + try { + return Integer.parseInt(input); + } catch (Exception e) { + return new RuntimeException("Exception in processWithReturnOutput for " + input, e); + } + } + + private static void processExceptions(Throwable throwable) { + logger.error("Process Exception" + throwable.getMessage()); + } + + private static void handleExceptionsAndOutputs(List exs, List output) { + logger.info("number of exceptions " + exs.size() + " number of outputs " + output.size()); + } + + private static String handleExAndResults(List ex, List results ) { + logger.info("handle aggregated exceptions and results" + ex.size() + " " + results.size()); + return "Exceptions and Results Handled"; + } + + private static String handleErrorsAndOutputForEither(Map>> map) { + logger.info("handle errors and output"); + map.getOrDefault(Boolean.TRUE, List.of()).forEach(either -> logger.error("Process Exception " + either.getLeft())); + + map.getOrDefault(Boolean.FALSE, List.of()).forEach(either -> logger.info("Process Result " + either.get())); + return "Errors and Output Handled"; + } + + private static String handleErrorsAndOutputForResult(List> successAndErrors) { + logger.info("handle errors and output"); + successAndErrors.forEach(result -> { + if (result.getException().isPresent()) { + logger.error("Process Exception " + result.getException().get()); + } else { + logger.info("Process Result" + result.getResult().get()); + } + }); + return "Errors and Output Handled"; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java new file mode 100644 index 0000000000..df75e69783 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java @@ -0,0 +1,82 @@ +package com.baeldung.partitioning; + +import static com.baeldung.streams.partitioning.PartitionStream.partitionList; +import static com.baeldung.streams.partitioning.PartitionStream.partitionStream; +import static com.baeldung.streams.partitioning.PartitionStream.partitionUsingGuava; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.atIndex; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class PartitionStreamsUnitTest { + + @Test + void whenPartitionList_thenReturnThreeSubLists() { + List source = List.of(1, 2, 3, 4, 5, 6, 7, 8); + + Stream> result = partitionList(source, 3); + + assertThat(result) + .containsExactlyInAnyOrder( + List.of(1, 2, 3), + List.of(4, 5, 6), + List.of(7, 8) + ); + } + + @Test + void whenPartitionEmptyList_thenReturnEmptyStream() { + Stream> result = partitionList(Collections.emptyList(), 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionListWithNegativeBatchSize_thenThrowException() { + assertThatThrownBy(() -> partitionList(List.of(1,2,3), -1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Expected the batchSize to be greater than ZERO, actual value was: -1"); + } + + @Test + void whenPartitionParallelStream_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result) + .hasSize(3) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).hasSize(2), atIndex(2)); + } + + @Test + void whenPartitionEmptyParallelStream_thenReturnEmptyList() { + Stream source = Stream.empty().parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionParallelStreamWithGuava_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + Iterable> result = partitionUsingGuava(source, 3); + + assertThat(result) + .map(ArrayList::new) + .hasSize(3) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).asList().hasSize(2), atIndex(2)); + } +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/skippingelements/SkippingElementsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/skippingelements/SkippingElementsUnitTest.java new file mode 100644 index 0000000000..92a13e62ab --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/skippingelements/SkippingElementsUnitTest.java @@ -0,0 +1,147 @@ +package com.baeldung.skippingelements; + + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class SkippingElementsUnitTest { + + private static Stream testSource() { + return Stream.of( + Arguments.of( + Stream.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", + "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty", "Twenty One", "Twenty Two", + "Twenty Three", "Twenty Four", "Twenty Five", "Twenty Six", "Twenty Seven", "Twenty Eight", "Twenty Nine", "Thirty", + "Thirty One", "Thirty Two", "Thirty Three"), + List.of("Three", "Six", "Nine", "Twelve", "Fifteen", "Eighteen", "Twenty One", "Twenty Four", "Twenty Seven", "Thirty", + "Thirty Three"), + 3), + Arguments.of( + Stream.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", + "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty", "Twenty One", "Twenty Two", + "Twenty Three", "Twenty Four", "Twenty Five", "Twenty Six", "Twenty Seven", "Twenty Eight", "Twenty Nine", "Thirty", + "Thirty One", "Thirty Two", "Thirty Three"), + List.of("Five", "Ten", "Fifteen", "Twenty", "Twenty Five", "Thirty"), + 5), + Arguments.of( + Stream.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", + "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty", "Twenty One", "Twenty Two", + "Twenty Three", "Twenty Four", "Twenty Five", "Twenty Six", "Twenty Seven", "Twenty Eight", "Twenty Nine", "Thirty", + "Thirty One", "Thirty Two", "Thirty Three"), + List.of("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", + "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty", "Twenty One", "Twenty Two", + "Twenty Three", "Twenty Four", "Twenty Five", "Twenty Six", "Twenty Seven", "Twenty Eight", "Twenty Nine", "Thirty", + "Thirty One", "Thirty Two", "Thirty Three"), + 1), + Arguments.of( + Stream.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + List.of("Wednesday", "Saturday"), + 3), + Arguments.of( + Stream.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + List.of("Friday"), + 5), + Arguments.of( + Stream.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + 1), + Arguments.of( + Stream.of("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", + "December"), + List.of("March", "June", "September", "December"), + 3), + Arguments.of( + Stream.of("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", + "December"), + List.of("May", "October"), + 5), + Arguments.of( + Stream.of("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", + "December"), + List.of("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", + "December"), + 1) + ); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInListWithFilterTestShouldFilterNthElement(Stream input, List expected, int n) { + final List sourceList = input.collect(Collectors.toList()); + final List actual = IntStream.range(0, sourceList.size()) + .filter(s -> (s + 1) % n == 0) + .mapToObj(sourceList::get) + .collect(Collectors.toList()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInListWithIterateTestShouldFilterNthElement(Stream input, List expected, int n) { + final List sourceList = input.collect(Collectors.toList()); + int limit = sourceList.size() / n; + final List actual = IntStream.iterate(n - 1, i -> (i + n)) + .limit(limit) + .mapToObj(sourceList::get) + .collect(Collectors.toList()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInListWithSublistTestShouldFilterNthElement(Stream input, List expected, int n) { + final List sourceList = input.collect(Collectors.toList()); + int limit = sourceList.size() / n; + final List actual = Stream.iterate(sourceList, s -> s.subList(n, s.size())) + .limit(limit) + .map(s -> s.get(n - 1)) + .collect(Collectors.toList()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInListWithForTestShouldFilterNthElement(Stream input, List expected, int n) { + final List sourceList = input.collect(Collectors.toList()); + List result = new ArrayList<>(); + for (int i = n - 1; i < sourceList.size(); i += n) { + result.add(sourceList.get(i)); + } + final List actual = result; + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInStreamWithIteratorTestShouldFilterNthElement(Stream input, List expected, int n) { + List result = new ArrayList<>(); + final Iterator iterator = input.iterator(); + int count = 0; + while (iterator.hasNext()) { + if (count % n == n - 1) { + result.add(iterator.next()); + } else { + iterator.next(); + } + ++count; + } + final List actual = result; + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("testSource") + void givenListSkipNthElementInStreamWithCollectorShouldFilterNthElement(Stream input, List expected, int n) { + final List actual = input.collect(SkippingCollector.collector(n)); + assertEquals(expected, actual); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java new file mode 100644 index 0000000000..e84fbc3da3 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.streamsvsloops; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; + +public class StreamsVsLoopsUnitTest { + + @Test + public void givenListWithFruits_whenFilterUsingStream_thenReturnedCount() { + List fruits = Arrays.asList("apple", "banana", "orange", "grape"); + long count = fruits.stream() + .filter(fruit -> fruit.length() > 5) + .count(); + assertEquals(2, count); + } + + @Test + public void givenListWithFruits_whenFilterUsingForLoop_thenReturnedCount() { + List fruits = Arrays.asList("apple", "banana", "orange", "grape"); + long count = 0; for (String fruit : fruits) { + if (fruit.length() > 5) { + count++; + } + } + assertEquals(2, count); + } + + @Test + public void givenListWithFruits_whenApplyUppercase_thenNewListGenerated() { + List desiredArray = new ArrayList<>(Arrays.asList("APPLE", "BANANA", "ORANGE")); + List fruits = new ArrayList<>(Arrays.asList("apple", "banana", "orange")); + List upperCaseFruits = fruits.stream() + .map(fruit -> fruit.toUpperCase()) + .collect(Collectors.toList()); + assertThat(desiredArray, is(upperCaseFruits)); + } + + @Test + public void givenListWithFruits_whenApplyUppercase_elementsAreUpdated() { + List desiredArray = new ArrayList<>(Arrays.asList("APPLE", "BANANA", "ORANGE")); + List fruits = new ArrayList<>(Arrays.asList("apple", "banana", "orange")); + for (int i = 0; i < fruits.size(); i++) { + fruits.set(i, fruits.get(i).toUpperCase()); + } + assertThat(desiredArray, is(fruits)); + } +} diff --git a/core-java-modules/core-java-streams-maps/pom.xml b/core-java-modules/core-java-streams-maps/pom.xml index 66e1fedd87..6b04897a29 100644 --- a/core-java-modules/core-java-streams-maps/pom.xml +++ b/core-java-modules/core-java-streams-maps/pom.xml @@ -58,7 +58,6 @@ - 3.1 1.8 1.8 diff --git a/core-java-modules/core-java-streams-simple/README.md b/core-java-modules/core-java-streams-simple/README.md new file mode 100644 index 0000000000..4cbe32ce32 --- /dev/null +++ b/core-java-modules/core-java-streams-simple/README.md @@ -0,0 +1,18 @@ +## Java Streams Ebook + +This module contains articles about Streams that are part of the Java Streams Ebook. + +### NOTE: + +Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. + +### Relevant Articles + +- [Introduction to Java 8 Streams](https://www.baeldung.com/java-8-streams-introduction) +- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors) +- [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) +- [Working With Maps Using Streams](https://www.baeldung.com/java-maps-streams) +- [The Difference Between map() and flatMap()](https://www.baeldung.com/java-difference-map-and-flatmap) +- [When to Use a Parallel Stream in Java](https://www.baeldung.com/java-when-to-use-parallel-stream) +- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector) +- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce) diff --git a/core-java-modules/core-java-streams-simple/pom.xml b/core-java-modules/core-java-streams-simple/pom.xml new file mode 100644 index 0000000000..5910e9daf2 --- /dev/null +++ b/core-java-modules/core-java-streams-simple/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + core-java-streams-simple + core-java-streams-simple + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + com.pivovarit + throwing-function + ${throwing-function.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + core-java-streams-simple + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + 1.5.1 + 17 + 17 + 17 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/filter/Customer.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/filter/Customer.java new file mode 100644 index 0000000000..51756c0067 --- /dev/null +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/filter/Customer.java @@ -0,0 +1,56 @@ +package com.baeldung.streams.filter; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +import javax.net.ssl.HttpsURLConnection; + +public class Customer { + private String name; + private int points; + private String profilePhotoUrl; + + public Customer(String name, int points) { + this(name, points, ""); + } + + public Customer(String name, int points, String profilePhotoUrl) { + this.name = name; + this.points = points; + this.profilePhotoUrl = profilePhotoUrl; + } + + public String getName() { + return name; + } + + public int getPoints() { + return points; + } + + public boolean hasOver(int points) { + return this.points > points; + } + + public boolean hasOverHundredPoints() { + return this.points > 100; + } + + public boolean hasValidProfilePhoto() throws IOException { + URL url = new URL(this.profilePhotoUrl); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + return connection.getResponseCode() == HttpURLConnection.HTTP_OK; + } + + public boolean hasValidProfilePhotoWithoutCheckedException() { + try { + URL url = new URL(this.profilePhotoUrl); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + return connection.getResponseCode() == HttpURLConnection.HTTP_OK; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPost.java similarity index 95% rename from core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPost.java index 314fbeeeb5..f22a20e67f 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPost.java @@ -1,4 +1,4 @@ -package com.baeldung.java_16_features.groupingby; +package com.baeldung.streams.groupingby; import java.util.IntSummaryStatistics; diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPostType.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPostType.java similarity index 51% rename from core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPostType.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPostType.java index df38b7e1c4..9bc5d95422 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPostType.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/BlogPostType.java @@ -1,4 +1,4 @@ -package com.baeldung.java_16_features.groupingby; +package com.baeldung.streams.groupingby; public enum BlogPostType { NEWS, REVIEW, GUIDE diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/Tuple.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/Tuple.java similarity index 94% rename from core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/Tuple.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/Tuple.java index ad41207aa4..e57a9190ec 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/Tuple.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/groupingby/Tuple.java @@ -1,4 +1,4 @@ -package com.baeldung.java_16_features.groupingby; +package com.baeldung.streams.groupingby; import java.util.Objects; diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/FileSearchCost.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/FileSearchCost.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/FileSearchCost.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/FileSearchCost.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/MergingCosts.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/MergingCosts.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/ParallelStream.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/ParallelStream.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/SequentialStream.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/SequentialStream.java diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/application/Application.java similarity index 90% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/application/Application.java index 62d080c32c..2ea91edddd 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/application/Application.java @@ -1,8 +1,7 @@ -package com.baeldung.reduce.application; +package com.baeldung.streams.reduce.application; + +import com.baeldung.streams.reduce.entities.User; -import com.baeldung.reduce.entities.User; -import com.baeldung.reduce.utilities.NumberUtils; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/benchmarks/JMHStreamReduceBenchMark.java similarity index 94% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/benchmarks/JMHStreamReduceBenchMark.java index ecb0347e96..3c11643bce 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/benchmarks/JMHStreamReduceBenchMark.java @@ -1,6 +1,6 @@ -package com.baeldung.reduce.benchmarks; +package com.baeldung.streams.reduce.benchmarks; -import com.baeldung.reduce.entities.User; +import com.baeldung.streams.reduce.entities.User; import java.util.ArrayList; import java.util.List; import org.openjdk.jmh.annotations.Benchmark; diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Rating.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Rating.java similarity index 95% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Rating.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Rating.java index 566691d442..400322c9ce 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Rating.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Rating.java @@ -1,4 +1,4 @@ -package com.baeldung.reduce.entities; +package com.baeldung.streams.reduce.entities; import java.util.ArrayList; import java.util.List; diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Review.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Review.java similarity index 90% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Review.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Review.java index b889a5f154..6d623127cf 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Review.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/Review.java @@ -1,4 +1,4 @@ -package com.baeldung.reduce.entities; +package com.baeldung.streams.reduce.entities; public class Review { diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/User.java similarity index 89% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/User.java index 6e0a529de6..610bd93b22 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/entities/User.java @@ -1,4 +1,4 @@ -package com.baeldung.reduce.entities; +package com.baeldung.streams.reduce.entities; public class User { diff --git a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/utilities/NumberUtils.java similarity index 97% rename from core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java rename to core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/utilities/NumberUtils.java index 38d5b50120..ed77bfe635 100644 --- a/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java +++ b/core-java-modules/core-java-streams-simple/src/main/java/com/baeldung/streams/reduce/utilities/NumberUtils.java @@ -1,4 +1,4 @@ -package com.baeldung.reduce.utilities; +package com.baeldung.streams.reduce.utilities; import java.util.List; import java.util.function.BiFunction; diff --git a/axon/src/main/resources/logback.xml b/core-java-modules/core-java-streams-simple/src/main/resources/logback.xml similarity index 100% rename from axon/src/main/resources/logback.xml rename to core-java-modules/core-java-streams-simple/src/main/resources/logback.xml diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Detail.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/Detail.java similarity index 100% rename from core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Detail.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/Detail.java diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamsUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/Java8StreamsUnitTest.java similarity index 100% rename from core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/Java8StreamsUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/Java8StreamsUnitTest.java diff --git a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/collectors/Java8CollectorsUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/collectors/Java8CollectorsUnitTest.java similarity index 99% rename from core-java-modules/core-java-11-2/src/test/java/com/baeldung/collectors/Java8CollectorsUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/collectors/Java8CollectorsUnitTest.java index 7990b1fdb7..085c1b5d7f 100644 --- a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/collectors/Java8CollectorsUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/collectors/Java8CollectorsUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.collectors; +package com.baeldung.streams.collectors; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; diff --git a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/filter/StreamFilterUnitTest.java similarity index 91% rename from core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/filter/StreamFilterUnitTest.java index 5ad875f61e..be7162217f 100644 --- a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/filter/StreamFilterUnitTest.java @@ -1,8 +1,8 @@ -package com.baeldung.stream.filter; +package com.baeldung.streams.filter; import org.junit.jupiter.api.Test; -import pl.touk.throwing.ThrowingPredicate; -import pl.touk.throwing.exception.WrappedException; +import com.pivovarit.function.ThrowingPredicate; +import com.pivovarit.function.exception.WrappedException; import java.io.IOException; import java.util.Arrays; @@ -14,10 +14,10 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -public class StreamFilterUnitTest { +class StreamFilterUnitTest { @Test - public void givenListOfCustomers_whenFilterByPoints_thenGetTwo() { + void givenListOfCustomers_whenFilterByPoints_thenGetTwo() { Customer john = new Customer("John P.", 15); Customer sarah = new Customer("Sarah M.", 200); Customer charles = new Customer("Charles B.", 150); @@ -53,7 +53,7 @@ public class StreamFilterUnitTest { } @Test - public void givenListOfCustomers_whenFilterByMethodReference_thenGetTwo() { + void givenListOfCustomers_whenFilterByMethodReference_thenGetTwo() { Customer john = new Customer("John P.", 15); Customer sarah = new Customer("Sarah M.", 200); Customer charles = new Customer("Charles B.", 150); @@ -70,7 +70,7 @@ public class StreamFilterUnitTest { } @Test - public void givenListOfCustomersWithOptional_whenFilterBy100Points_thenGetTwo() { + void givenListOfCustomersWithOptional_whenFilterBy100Points_thenGetTwo() { Optional john = Optional.of(new Customer("John P.", 15)); Optional sarah = Optional.of(new Customer("Sarah M.", 200)); Optional mary = Optional.of(new Customer("Mary T.", 300)); @@ -89,7 +89,7 @@ public class StreamFilterUnitTest { } @Test - public void givenListOfCustomers_whenFilterWithCustomHandling_thenThrowException() { + void givenListOfCustomers_whenFilterWithCustomHandling_thenThrowException() { Customer john = new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e"); Customer sarah = new Customer("Sarah M.", 200); Customer charles = new Customer("Charles B.", 150); @@ -103,7 +103,7 @@ public class StreamFilterUnitTest { } @Test - public void givenListOfCustomers_whenFilterWithThrowingFunction_thenThrowException() { + void givenListOfCustomers_whenFilterWithThrowingFunction_thenThrowException() { Customer john = new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e"); Customer sarah = new Customer("Sarah M.", 200); Customer charles = new Customer("Charles B.", 150); @@ -156,5 +156,4 @@ public class StreamFilterUnitTest { }) .collect(Collectors.toList())).isInstanceOf(RuntimeException.class); } - -} +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java similarity index 73% rename from core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java index 1b09ea25c6..6de0f73351 100644 --- a/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/flatmap/map/Java8MapAndFlatMapUnitTest.java @@ -1,6 +1,7 @@ package com.baeldung.streams.flatmap.map; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.Collection; @@ -10,12 +11,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; -public class Java8MapAndFlatMapUnitTest { + +class Java8MapAndFlatMapUnitTest { @Test - public void givenStream_whenCalledMap_thenProduceList() { + void givenStream_whenCalledMap_thenProduceList() { List myList = Stream.of("a", "b") .map(String::toUpperCase) .collect(Collectors.toList()); @@ -23,7 +24,7 @@ public class Java8MapAndFlatMapUnitTest { } @Test - public void givenStream_whenCalledFlatMap_thenProduceFlattenedList() throws Exception { + void givenStream_whenCalledFlatMap_thenProduceFlattenedList() { List> list = Arrays.asList(Arrays.asList("a"), Arrays.asList("b")); System.out.println(list); @@ -33,13 +34,13 @@ public class Java8MapAndFlatMapUnitTest { } @Test - public void givenOptional_whenCalledMap_thenProduceOptional() { + void givenOptional_whenCalledMap_thenProduceOptional() { Optional s = Optional.of("test"); assertEquals(Optional.of("TEST"), s.map(String::toUpperCase)); } @Test - public void givenOptional_whenCalledFlatMap_thenProduceFlattenedOptional() { + void givenOptional_whenCalledFlatMap_thenProduceFlattenedOptional() { assertEquals(Optional.of(Optional.of("STRING")), Optional.of("string") .map(s -> Optional.of("STRING"))); diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/groupingby/JavaGroupingByCollectorUnitTest.java similarity index 89% rename from core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/groupingby/JavaGroupingByCollectorUnitTest.java index 603bebb7c5..be5d176c50 100644 --- a/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/groupingby/JavaGroupingByCollectorUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.java_16_features.groupingby; +package com.baeldung.streams.groupingby; import static java.util.Comparator.comparingInt; import static java.util.stream.Collectors.averagingInt; @@ -33,13 +33,13 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; -public class JavaGroupingByCollectorUnitTest { +class JavaGroupingByCollectorUnitTest { private static final List posts = Arrays.asList(new BlogPost("News item 1", "Author 1", BlogPostType.NEWS, 15), new BlogPost("Tech review 1", "Author 2", BlogPostType.REVIEW, 5), new BlogPost("Programming guide", "Author 1", BlogPostType.GUIDE, 20), new BlogPost("News item 2", "Author 2", BlogPostType.NEWS, 35), new BlogPost("Tech review 2", "Author 1", BlogPostType.REVIEW, 15)); @Test - public void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() { + void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() { Map> postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType)); @@ -52,7 +52,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() { + void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() { Map postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType, mapping(BlogPost::getTitle, joining(", ", "Post titles: [", "]")))); @@ -62,7 +62,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() { + void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() { Map likesPerType = posts.stream() .collect(groupingBy(BlogPost::getType, summingInt(BlogPost::getLikes))); @@ -75,7 +75,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() { + void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() { EnumMap> postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType, () -> new EnumMap<>(BlogPostType.class), toList())); @@ -88,7 +88,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() { + void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() { Map> postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType, toSet())); @@ -101,7 +101,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() { + void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() { ConcurrentMap> postsPerType = posts.parallelStream() .collect(groupingByConcurrent(BlogPost::getType)); @@ -114,7 +114,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() { + void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() { Map averageLikesPerType = posts.stream() .collect(groupingBy(BlogPost::getType, averagingInt(BlogPost::getLikes))); @@ -127,7 +127,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() { + void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() { Map numberOfPostsPerType = posts.stream() .collect(groupingBy(BlogPost::getType, counting())); @@ -140,7 +140,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() { + void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() { Map> maxLikesPerPostType = posts.stream() .collect(groupingBy(BlogPost::getType, maxBy(comparingInt(BlogPost::getLikes)))); @@ -164,7 +164,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() { + void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() { Map>> map = posts.stream() .collect(groupingBy(BlogPost::getAuthor, groupingBy(BlogPost::getType))); @@ -189,7 +189,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() { + void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() { Map likeStatisticsPerType = posts.stream() .collect(groupingBy(BlogPost::getType, summarizingInt(BlogPost::getLikes))); @@ -203,7 +203,7 @@ public class JavaGroupingByCollectorUnitTest { } @Test - public void givenAListOfPosts_whenGroupedByComplexMapPairKeyType_thenGetAMapBetweenPairAndList() { + void givenAListOfPosts_whenGroupedByComplexMapPairKeyType_thenGetAMapBetweenPairAndList() { Map, List> postsPerTypeAndAuthor = posts.stream() .collect(groupingBy(post -> new ImmutablePair<>(post.getType(), post.getAuthor()))); diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamMapUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/map/StreamMapUnitTest.java similarity index 98% rename from core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamMapUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/map/StreamMapUnitTest.java index 509a3a3569..c493ed903d 100644 --- a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamMapUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/map/StreamMapUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.streams; +package com.baeldung.streams.map; import org.junit.Before; import org.junit.Test; diff --git a/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java similarity index 100% rename from core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/reduce/StreamReduceUnitTest.java b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/reduce/StreamReduceUnitTest.java similarity index 67% rename from core-java-modules/core-java-streams-2/src/test/java/com/baeldung/reduce/StreamReduceUnitTest.java rename to core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/reduce/StreamReduceUnitTest.java index 21eedf953e..009dd2ee37 100644 --- a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/reduce/StreamReduceUnitTest.java +++ b/core-java-modules/core-java-streams-simple/src/test/java/com/baeldung/streams/reduce/StreamReduceUnitTest.java @@ -1,79 +1,80 @@ -package com.baeldung.reduce; +package com.baeldung.streams.reduce; -import com.baeldung.reduce.entities.User; -import com.baeldung.reduce.utilities.NumberUtils; -import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.streams.reduce.entities.User; +import com.baeldung.streams.reduce.utilities.NumberUtils; + +import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; - -public class StreamReduceUnitTest { +class StreamReduceUnitTest { @Test - public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { + void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); int result = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); assertThat(result).isEqualTo(21); } @Test - public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { + void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); int result = numbers.stream().reduce(0, Integer::sum); assertThat(result).isEqualTo(21); } @Test - public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { + void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { List letters = Arrays.asList("a", "b", "c", "d", "e"); String result = letters.stream().reduce("", (partialString, element) -> partialString + element); assertThat(result).isEqualTo("abcde"); } @Test - public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { + void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { List letters = Arrays.asList("a", "b", "c", "d", "e"); String result = letters.stream().reduce("", String::concat); assertThat(result).isEqualTo("abcde"); } @Test - public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { + void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { List letters = Arrays.asList("a", "b", "c", "d", "e"); String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); assertThat(result).isEqualTo("ABCDE"); } @Test - public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { + void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); assertThat(result).isEqualTo(65); } @Test - public void givenStringList_whenReduceWithParallelStream_thenCorrect() { + void givenStringList_whenReduceWithParallelStream_thenCorrect() { List letters = Arrays.asList("a", "b", "c", "d", "e"); String result = letters.parallelStream().reduce("", String::concat); assertThat(result).isEqualTo("abcde"); } @Test - public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { + void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21); } @Test - public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { + void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); } @Test - public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { + void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21); } diff --git a/core-java-modules/core-java-streams/README.md b/core-java-modules/core-java-streams/README.md index 360f7190ea..adb4c1dda1 100644 --- a/core-java-modules/core-java-streams/README.md +++ b/core-java-modules/core-java-streams/README.md @@ -9,7 +9,6 @@ This module contains articles about the Stream API in Java. - [Iterable to Stream in Java](https://www.baeldung.com/java-iterable-to-stream) - [How to Iterate Over a Stream With Indices](https://www.baeldung.com/java-stream-indices) - [Stream Ordering in Java](https://www.baeldung.com/java-stream-ordering) -- [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) - [Counting Matches on a Stream Filter](https://www.baeldung.com/java-stream-filter-count) - [Summing Numbers with Java Streams](https://www.baeldung.com/java-stream-sum) - [How to Find All Getters Returning Null](https://www.baeldung.com/java-getters-returning-null) diff --git a/core-java-modules/core-java-streams/pom.xml b/core-java-modules/core-java-streams/pom.xml index b0794829c2..005968d214 100644 --- a/core-java-modules/core-java-streams/pom.xml +++ b/core-java-modules/core-java-streams/pom.xml @@ -14,33 +14,6 @@ - - org.openjdk.jmh - jmh-core - ${jmh-core.version} - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh-generator.version} - provided - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - log4j - log4j - ${log4j.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - com.codepoetics protonpack @@ -56,21 +29,6 @@ streamex ${streamex.version} - - org.aspectj - aspectjrt - ${asspectj.version} - - - org.aspectj - aspectjweaver - ${asspectj.version} - - - pl.touk - throwing-function - ${throwing-function.version} - @@ -96,15 +54,11 @@ - 0.9.0 - 1.15 - 0.6.5 - 2.10 - 1.3 - 1.8.9 - 3.1 - 1.8 - 1.8 + 0.10.4 + 1.16 + 0.8.1 + 17 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-string-algorithms-3/README.md b/core-java-modules/core-java-string-algorithms-3/README.md index 6af818b52d..abcac63ea4 100644 --- a/core-java-modules/core-java-string-algorithms-3/README.md +++ b/core-java-modules/core-java-string-algorithms-3/README.md @@ -11,3 +11,6 @@ This module contains articles about string-related algorithms. - [Find the First Non Repeating Character in a String in Java](https://www.baeldung.com/java-find-the-first-non-repeating-character) - [Find the First Embedded Occurrence of an Integer in a Java String](https://www.baeldung.com/java-string-find-embedded-integer) - [Find the Most Frequent Characters in a String](https://www.baeldung.com/java-string-find-most-frequent-characters) +- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) +- [Check if Letter Is Emoji With Java](https://www.baeldung.com/java-check-letter-emoji) +- [Wrapping a String After a Number of Characters Word-Wise](https://www.baeldung.com/java-wrap-string-number-characters-word-wise) diff --git a/core-java-modules/core-java-string-algorithms-3/pom.xml b/core-java-modules/core-java-string-algorithms-3/pom.xml index 7d4adeba92..507e830e8a 100644 --- a/core-java-modules/core-java-string-algorithms-3/pom.xml +++ b/core-java-modules/core-java-string-algorithms-3/pom.xml @@ -23,6 +23,16 @@ commons-lang3 ${apache-commons-lang3.version} + + com.vdurmont + emoji-java + ${emoji-java.version} + + + org.apache.commons + commons-text + ${apache-commons-text.version} + @@ -52,6 +62,8 @@ 11 1.7 3.12.0 + 5.1.1 + 1.10.0 \ No newline at end of file diff --git a/core-java-modules/core-java-string-algorithms/src/main/java/com/baeldung/repetition/SubstringRepetition.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/repetition/SubstringRepetition.java similarity index 100% rename from core-java-modules/core-java-string-algorithms/src/main/java/com/baeldung/repetition/SubstringRepetition.java rename to core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/repetition/SubstringRepetition.java diff --git a/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/wrappingcharacterwise/Wrapper.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/wrappingcharacterwise/Wrapper.java new file mode 100644 index 0000000000..7400745b2f --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/wrappingcharacterwise/Wrapper.java @@ -0,0 +1,28 @@ +package com.baeldung.wrappingcharacterwise; + +import java.lang.IllegalArgumentException; +import java.lang.String; +import java.lang.StringBuilder; + +public class Wrapper { + + public String wrapStringCharacterWise(String input, int n) { + StringBuilder stringBuilder = new StringBuilder(input); + int index = 0; + while(stringBuilder.length() > index + n) { + int lastLineReturn = stringBuilder.lastIndexOf("\n", index + n); + if (lastLineReturn > index) { + index = lastLineReturn; + } else { + index = stringBuilder.lastIndexOf(" ", index + n); + if (index == -1) { + throw new IllegalArgumentException("impossible to slice " + stringBuilder.substring(0, n)); + } + stringBuilder.replace(index, index + 1, "\n"); + index++; + } + } + return stringBuilder.toString(); + } + +} diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/findemojis/FindEmojisUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/findemojis/FindEmojisUnitTest.java new file mode 100644 index 0000000000..3cd5b1ba97 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/findemojis/FindEmojisUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.findemojis; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.vdurmont.emoji.EmojiManager; + +public class FindEmojisUnitTest { + + @Test + public void givenAWord_whenUsingEmojiJava_thenDetectEmoji() { + boolean emoji = EmojiManager.isEmoji("\uD83D\uDC3B"); + assertTrue(emoji); + + boolean notEmoji = EmojiManager.isEmoji("w"); + assertFalse(notEmoji); + } + + @Test + public void givenAWord_whenUsingRegex_thenDetectEmoji() { + String regexPattern = "[\uD800-\uDBFF\uDC00-\uDFFF]+"; + String emojiString = "\uD83D\uDC3B"; + boolean emoji = emojiString.matches(regexPattern); + assertTrue(emoji); + + String notEmojiString = "w"; + boolean notEmoji = notEmojiString.matches(regexPattern); + assertFalse(notEmoji); + } + +} diff --git a/core-java-modules/core-java-string-algorithms/src/test/java/com/baeldung/repetition/SubstringRepetitionUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/repetition/SubstringRepetitionUnitTest.java similarity index 100% rename from core-java-modules/core-java-string-algorithms/src/test/java/com/baeldung/repetition/SubstringRepetitionUnitTest.java rename to core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/repetition/SubstringRepetitionUnitTest.java diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/wrappingcharacterwise/WrapperUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/wrappingcharacterwise/WrapperUnitTest.java new file mode 100644 index 0000000000..8dcc323f7b --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/wrappingcharacterwise/WrapperUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.wrappingcharacterwise; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.apache.commons.text.WordUtils; +import org.junit.jupiter.api.Test; + +public class WrapperUnitTest { + + Wrapper wrapper = new Wrapper(); + String lineSeparator = System.lineSeparator(); + + @Test + void givenStringWithLessThanNCharacters_whenWrapStringCharacterWise_thenUnchanged() { + String input = "short sentence"; + assertEquals(input, wrapper.wrapStringCharacterWise(input, 20)); + } + + @Test + void givenStringWithMoreThanNCharacters_whenWrapStringCharacterWise_thenCorrectlyWrapped() { + String input = "Baeldung is a popular website that provides in-depth tutorials and articles on various programming and software development topics, primarily focused on Java and related technologies."; + assertEquals("Baeldung is a\npopular website that\nprovides in-depth\ntutorials and\narticles on various\nprogramming and\nsoftware development\ntopics, primarily\nfocused on Java and\nrelated\ntechnologies.", wrapper.wrapStringCharacterWise(input, 20)); + } + + @Test + void givenStringWithATooLongWord_whenWrapStringCharacterWise_thenThrows() { + String input = "The word straightforward has more than 10 characters"; + assertThrows(IllegalArgumentException.class, () -> wrapper.wrapStringCharacterWise(input, 10)); + } + + @Test + void givenStringWithLineReturns_whenWrapStringCharacterWise_thenWrappedAccordingly() { + String input = "Baeldung\nis a popular website that provides in-depth tutorials and articles on various programming and software development topics, primarily focused on Java and related technologies."; + assertEquals("Baeldung\nis a popular\nwebsite that\nprovides in-depth\ntutorials and\narticles on various\nprogramming and\nsoftware development\ntopics, primarily\nfocused on Java and\nrelated\ntechnologies.", wrapper.wrapStringCharacterWise(input, 20)); + } + + @Test + void givenStringWithLessThanNCharacters_whenWrap_thenUnchanged() { + String input = "short sentence"; + assertEquals(input, WordUtils.wrap(input, 20)); + } + + @Test + void givenStringWithMoreThanNCharacters_whenWrap_thenCorrectlyWrapped() { + String input = "Baeldung is a popular website that provides in-depth tutorials and articles on various programming and software development topics, primarily focused on Java and related technologies."; + assertEquals("Baeldung is a" + lineSeparator + "popular website that" + lineSeparator + "provides in-depth" + lineSeparator + "tutorials and" + lineSeparator + "articles on various" + lineSeparator + "programming and" + lineSeparator + "software development" + lineSeparator + "topics, primarily" + lineSeparator + "focused on Java and" + lineSeparator + "related" + lineSeparator + "technologies.", WordUtils.wrap(input, 20)); + } + + @Test + void givenStringWithATooLongWord_whenWrap_thenLongWordIsNotWrapped() { + String input = "The word straightforward has more than 10 characters"; + assertEquals("The word" + lineSeparator + "straightforward" + lineSeparator + "has more" + lineSeparator + "than 10" + lineSeparator + "characters", WordUtils.wrap(input, 10)); + } + + @Test + void givenStringWithLineReturns_whenWrap_thenWrappedLikeThereWasNone() { + String input = "Baeldung" + lineSeparator + "is a popular website that provides in-depth tutorials and articles on various programming and software development topics, primarily focused on Java and related technologies."; + assertEquals("Baeldung" + lineSeparator + "is a" + lineSeparator + "popular website that" + lineSeparator + "provides in-depth" + lineSeparator + "tutorials and" + lineSeparator + "articles on various" + lineSeparator + "programming and" + lineSeparator + "software development" + lineSeparator + "topics, primarily" + lineSeparator + "focused on Java and" + lineSeparator + "related" + lineSeparator + "technologies.", WordUtils.wrap(input, 20)); + } + +} diff --git a/core-java-modules/core-java-string-algorithms/README.md b/core-java-modules/core-java-string-algorithms/README.md index 5a7abf074a..e2f909ed38 100644 --- a/core-java-modules/core-java-string-algorithms/README.md +++ b/core-java-modules/core-java-string-algorithms/README.md @@ -11,6 +11,5 @@ This module contains articles about string-related algorithms. - [How to Reverse a String in Java](https://www.baeldung.com/java-reverse-string) - [Check if a String Is a Pangram in Java](https://www.baeldung.com/java-string-pangram) - [Check If a String Contains Multiple Keywords in Java](https://www.baeldung.com/string-contains-multiple-words) -- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) - [Remove Emojis from a Java String](https://www.baeldung.com/java-string-remove-emojis) - More articles: [[next -->]](../core-java-string-algorithms-2) diff --git a/core-java-modules/core-java-string-apis-2/pom.xml b/core-java-modules/core-java-string-apis-2/pom.xml index 51ab3bc1f8..814d301532 100644 --- a/core-java-modules/core-java-string-apis-2/pom.xml +++ b/core-java-modules/core-java-string-apis-2/pom.xml @@ -22,7 +22,7 @@ org.apache.commons commons-lang3 - ${commons.lang3.version} + ${commons-lang3.version} com.ibm.icu @@ -42,8 +42,6 @@ - 3.12.0 - 31.1-jre 61.1 diff --git a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java index aa15345bcb..13a0407a98 100644 --- a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java +++ b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java @@ -1,11 +1,11 @@ package com.baeldung.charsequence; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import org.junit.Test; + public class CharSequenceVsStringUnitTest { @Test @@ -44,4 +44,43 @@ public class CharSequenceVsStringUnitTest { assertEquals(firstAddressOfTest, secondAddressOfTest); } + + @Test + public void givenCharSequenceAsString_whenConvertingUsingCasting_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence = "baeldung"; + String explicitCastedString = (String) charSequence; + + assertEquals(expected, charSequence); + assertEquals(expected, explicitCastedString); + } + + @Test(expected = ClassCastException.class) + public void givenCharSequenceAsStringBuiler_whenConvertingUsingCasting_thenThrowException() { + CharSequence charSequence = new StringBuilder("baeldung"); + String castedString = (String) charSequence; + } + + @Test + public void givenCharSequence_whenConvertingUsingToString_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + + assertEquals(expected, charSequence1.toString()); + assertEquals(expected, charSequence2.toString()); + } + + @Test + public void givenCharSequence_whenConvertingUsingValueOf_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + CharSequence charSequence3 = null; + + assertEquals(expected, String.valueOf(charSequence1)); + assertEquals(expected, String.valueOf(charSequence2)); + assertEquals("null", String.valueOf(charSequence3)); + } + } diff --git a/core-java-modules/core-java-string-conversions-3/README.md b/core-java-modules/core-java-string-conversions-3/README.md index 96799d1660..ec169f71d2 100644 --- a/core-java-modules/core-java-string-conversions-3/README.md +++ b/core-java-modules/core-java-string-conversions-3/README.md @@ -1,3 +1,7 @@ ## Relevant Articles - [Object.toString() vs String.valueOf()](https://www.baeldung.com/java-object-tostring-vs-string-valueof) - [Convert String to Int Using Encapsulation](https://www.baeldung.com/java-encapsulation-convert-string-to-int) +- [HashMap with Multiple Values for the Same Key](https://www.baeldung.com/java-hashmap-multiple-values-per-key) +- [Split Java String Into Key-Value Pairs](https://www.baeldung.com/java-split-string-map) +- [How to Center Text Output in Java](https://www.baeldung.com/java-center-text-output) +- [How to Convert an Object to String](https://www.baeldung.com/java-object-string-representation) diff --git a/core-java-modules/core-java-string-conversions-3/pom.xml b/core-java-modules/core-java-string-conversions-3/pom.xml index ddd5f7a497..b494a03fa7 100644 --- a/core-java-modules/core-java-string-conversions-3/pom.xml +++ b/core-java-modules/core-java-string-conversions-3/pom.xml @@ -23,4 +23,12 @@ - \ No newline at end of file + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + diff --git a/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/hashmapmultivalues/MultiValueHashMap.java b/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/hashmapmultivalues/MultiValueHashMap.java new file mode 100644 index 0000000000..5e4faebb05 --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/hashmapmultivalues/MultiValueHashMap.java @@ -0,0 +1,29 @@ +package com.baeldung.hashmapmultivalues; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class MultiValueHashMap { + private final HashMap> map; + + // Constructor + public MultiValueHashMap() { + map = new HashMap<>(); + } + + public void put(K key, V value) { + map.computeIfAbsent(key, k -> new ArrayList<>()).add(value); + } + + public List get(K key) { + return map.getOrDefault(key, new ArrayList<>()); + } + + public void remove(K key, V value) { + map.computeIfPresent(key, (k, v) -> { + v.remove(value); + return v; + }); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/objecttostring/Person.java b/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/objecttostring/Person.java new file mode 100644 index 0000000000..61c0bd5711 --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/main/java/com/baeldung/objecttostring/Person.java @@ -0,0 +1,34 @@ +package com.baeldung.objecttostring; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class Person { + private String name; + private int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public String toString() { + return "Person{name='" + name + "', age=" + age + '}'; + } + + public String toCustomString() { + return new ToStringBuilder(this, ToStringStyle.JSON_STYLE) + .append("name", name) + .append("age", age) + .toString(); + } +} diff --git a/core-java-modules/core-java-string-conversions-3/src/java.com.baeldung.multivluehashmap/MultiValueHashMapTest.java b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/hashmapmultivalues/MultiValueHashMapUnitTest.java similarity index 66% rename from core-java-modules/core-java-string-conversions-3/src/java.com.baeldung.multivluehashmap/MultiValueHashMapTest.java rename to core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/hashmapmultivalues/MultiValueHashMapUnitTest.java index a3d0bc35de..b330df22df 100644 --- a/core-java-modules/core-java-string-conversions-3/src/java.com.baeldung.multivluehashmap/MultiValueHashMapTest.java +++ b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/hashmapmultivalues/MultiValueHashMapUnitTest.java @@ -1,12 +1,13 @@ +package com.baeldung.hashmapmultivalues; + import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.*; -public class MultiValueHashMapTest { +public class MultiValueHashMapUnitTest { @Test public void given_MultiValueHashMap_whenPuttingAndGettingSingleValue_thenValueIsRetrieved() { MultiValueHashMap map = new MultiValueHashMap<>(); @@ -49,31 +50,4 @@ public class MultiValueHashMapTest { assertEquals(List.of("one"), map.get(1)); } - public class MultiValueHashMap { - private HashMap> map; - - // Constructor - public MultiValueHashMap() { - map = new HashMap<>(); - } - - public void put(K key, V value) { - if (!map.containsKey(key)) { - map.put(key, new ArrayList<>()); - } - map.get(key).add(value); - } - - public List get(K key) { - return map.getOrDefault(key, new ArrayList<>()); - } - - public void remove(K key, V value) { - if (map.containsKey(key)) { - map.get(key).remove(value); - } - } - - - } } diff --git a/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/joinasnl/JoinStringsAsNaturalLangUnitTest.java b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/joinasnl/JoinStringsAsNaturalLangUnitTest.java new file mode 100644 index 0000000000..f3ca5a3e2b --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/joinasnl/JoinStringsAsNaturalLangUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.joinasnl; + +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class JoinStringsAsNaturalLangUnitTest { + String joinItemsAsNaturalLanguage(List list, boolean oxfordComma) { + if (list.size() < 3) { + return String.join(" and ", list); + } + // list has at least three elements + int lastIdx = list.size() - 1; + StringBuilder sb = new StringBuilder(); + return sb.append(String.join(", ", list.subList(0, lastIdx))) + .append(oxfordComma ? ", and " : " and ") + .append(list.get(lastIdx)) + .toString(); + } + + @Test + void whenCallingJoinByGrammar_thenGetTheExpectedResult() { + assertEquals("", joinItemsAsNaturalLanguage(emptyList(), false)); + assertEquals("A", joinItemsAsNaturalLanguage(List.of("A"), false)); + assertEquals("A and B", joinItemsAsNaturalLanguage(List.of("A", "B"), false)); + assertEquals("A, B, C, D and I have a comma (,)", joinItemsAsNaturalLanguage(List.of("A", "B", "C", "D", "I have a comma (,)"), false)); + // with oxford comma = true + assertEquals("", joinItemsAsNaturalLanguage(emptyList(), true)); + assertEquals("A", joinItemsAsNaturalLanguage(List.of("A"), true)); + assertEquals("A and B", joinItemsAsNaturalLanguage(List.of("A", "B"), true)); + assertEquals("A, B, C, D, and I have a comma (,)", joinItemsAsNaturalLanguage(List.of("A", "B", "C", "D", "I have a comma (,)"), true)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/objecttostring/PersonUnitTest.java b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/objecttostring/PersonUnitTest.java new file mode 100644 index 0000000000..7b61956dfc --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/objecttostring/PersonUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.objecttostring; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class PersonUnitTest { + @Test + public void givenObject_whenToString_thenConvert() { + Person person = new Person("Sarah", 28); + String expected = "Person{name='Sarah', age=28}"; + String actual = person.toString(); + assertEquals(expected, actual); + } + + @Test + public void givenObject_whenValueOf_thenConvert() { + Person person = new Person("Sarah", 28); + String expected = "Person{name='Sarah', age=28}"; + String actual = String.valueOf(person); + assertEquals(expected, actual); + } + + @Test + public void givenObject_whenConcat_thenConvert() { + Person person = new Person("Sarah", 28); + String expected = "Person{name='Sarah', age=28}"; + String actual = "" + person; + assertEquals(expected, actual); + } + + @Test + public void givenObject_whenToStringBuilder_thenConvert() { + Person person = new Person("Sarah", 28); + String expected = "{\"name\":\"Sarah\",\"age\":28}"; + String actual = person.toCustomString(); + assertEquals(expected, actual); + } +} diff --git a/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java new file mode 100644 index 0000000000..25f68ff373 --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.stringsplitkeyvalue; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StringSplitKeyValueUnitTest { + +@Test +public void givenStringData_whenUsingTokenizer_thenTokenizeAndValidate() { + String data = "name=John age=30 city=NewYork"; + StringTokenizer tokenizer = new StringTokenizer(data); + + // Create a map to store key-value pairs + Map keyValueMap = new HashMap<>(); + + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split("="); + + if (keyValue.length == 2) { + String key = keyValue[0]; + String value = keyValue[1]; + + // Store key-value pairs in the map + keyValueMap.put(key, value); + } + } + + // Use assertions to validate the key-value pairs in the map + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); +} + + +@Test +public void givenDataWithPattern_whenUsingMatcher_thenPerformPatternMatching() { + String data = "name=John,age=30;city=NewYork"; + Pattern pattern = Pattern.compile("\\b(\\w+)=(\\w+)\\b"); + Matcher matcher = pattern.matcher(data); + + // Create a map to store key-value pairs + Map keyValueMap = new HashMap<>(); + + while (matcher.find()) { + String key = matcher.group(1); + String value = matcher.group(2); + + // Store key-value pairs in the map + keyValueMap.put(key, value); + } + + // Use assertions to validate the key-value pairs in the map + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); +} + + @Test + public void givenStringData_whenUsingJavaMap_thenSplitAndValidate() { + String data = "name=John age=30 city=NewYork"; + Map keyValueMap = Arrays.stream(data.split(" ")) + .map(kv -> kv.split("=")) + .filter(kvArray -> kvArray.length == 2) + .collect(Collectors.toMap(kv -> kv[0], kv -> kv[1])); + + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); + } +} diff --git a/core-java-modules/core-java-string-operations-2/pom.xml b/core-java-modules/core-java-string-operations-2/pom.xml index c6debc4f71..902e8f09b4 100644 --- a/core-java-modules/core-java-string-operations-2/pom.xml +++ b/core-java-modules/core-java-string-operations-2/pom.xml @@ -54,6 +54,11 @@ commons-codec ${commons-codec.version} + + org.springframework + spring-core + ${spring-core.version} + @@ -95,6 +100,7 @@ 3.0.0 2.2.6 1.14 + 5.3.0 \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/emptystrings/EmptyStringsUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/emptystrings/EmptyStringsUnitTest.java index d772c38341..9652e0e770 100644 --- a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/emptystrings/EmptyStringsUnitTest.java +++ b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/emptystrings/EmptyStringsUnitTest.java @@ -3,6 +3,7 @@ package com.baeldung.emptystrings; import com.google.common.base.Strings; import org.apache.commons.lang3.StringUtils; import org.junit.Test; +import org.springframework.util.ObjectUtils; import javax.validation.ConstraintViolation; import javax.validation.Validation; @@ -109,6 +110,24 @@ public class EmptyStringsUnitTest { assertFalse(Strings.isNullOrEmpty(blankString)); } + /* + * Spring Core ObjectUtils + */ + @Test + public void givenSomeEmptyString_thenObjectUtilsIsEmptyReturnsTrue() { + assertTrue(ObjectUtils.isEmpty(emptyString)); + } + + @Test + public void givenSomeNonEmptyString_thenObjectUtilsIsEmptyReturnsFalse() { + assertFalse(ObjectUtils.isEmpty(nonEmptyString)); + } + + @Test + public void givenSomeBlankString_thenObjectUtilsIsEmptyReturnsFalse() { + assertFalse(ObjectUtils.isEmpty(blankString)); + } + /* * Bean Validation */ diff --git a/core-java-modules/core-java-string-operations-5/README.md b/core-java-modules/core-java-string-operations-5/README.md index 21ba1bf985..dffd3c1ab6 100644 --- a/core-java-modules/core-java-string-operations-5/README.md +++ b/core-java-modules/core-java-string-operations-5/README.md @@ -10,4 +10,4 @@ - [Guide to Splitting a String by Whitespace in Java](https://www.baeldung.com/java-splitting-a-string-by-whitespace) - [Check if the First Letter of a String Is a Number](https://www.baeldung.com/java-check-if-string-starts-with-number) - [Print “” Quotes Around a String in Java](https://www.baeldung.com/java-string-print-quotes) -- [Remove Punctuation From a String in Java](https://www.baeldung.com/java-remove-punctuation-from-string) \ No newline at end of file +- [Remove Punctuation From a String in Java](https://www.baeldung.com/java-remove-punctuation-from-string) diff --git a/core-java-modules/core-java-string-operations-6/README.md b/core-java-modules/core-java-string-operations-6/README.md index 853d58287d..9d92552dd1 100644 --- a/core-java-modules/core-java-string-operations-6/README.md +++ b/core-java-modules/core-java-string-operations-6/README.md @@ -10,3 +10,5 @@ - [Check if a String Contains Non-Alphanumeric Characters](https://www.baeldung.com/java-string-test-special-characters) - [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars) - [Performance Comparison Between Different Java String Concatenation Methods](https://www.baeldung.com/java-string-concatenation-methods) +- [Replacing Single Quote with \’ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) +- [Check if a String Contains a Number Value in Java](https://www.baeldung.com/java-string-number-presence) diff --git a/core-java-modules/core-java-string-operations-6/pom.xml b/core-java-modules/core-java-string-operations-6/pom.xml index 0ec32d91b1..ca9a7a9297 100644 --- a/core-java-modules/core-java-string-operations-6/pom.xml +++ b/core-java-modules/core-java-string-operations-6/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-string-operations-6 core-java-string-operations-6 diff --git a/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java new file mode 100644 index 0000000000..081ffabab1 --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.replace; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class ReplaceStringUnitTest { + private final String ORIGINAL_STRING = "This is 'Baeldung' tutorial."; + private final String EXPECTED_STRING = "This is \\'Baeldung\\' tutorial."; + + @Test + public void givenString_thenReplaceUsinReplaceAllMethod() { + String modifiedString = ORIGINAL_STRING.replaceAll("'", "\\\\'"); + assertEquals(EXPECTED_STRING, modifiedString); + } + + @Test + public void givenString_thenReplaceUsinReplaceMethod() { + String modifiedString = ORIGINAL_STRING.replace("'", "\\'"); + assertEquals(EXPECTED_STRING, modifiedString); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-7/README.md b/core-java-modules/core-java-string-operations-7/README.md new file mode 100644 index 0000000000..6c4fab384b --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/README.md @@ -0,0 +1,4 @@ + +### Relevant Articles: +- [How to Center Text Output in Java](https://www.baeldung.com/java-center-text-output) +- [Capitalize the First Letter of Each Word in a String](https://www.baeldung.com/java-string-initial-capital-letter-every-word) diff --git a/core-java-modules/core-java-string-operations-7/pom.xml b/core-java-modules/core-java-string-operations-7/pom.xml new file mode 100644 index 0000000000..a2c7036e34 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + core-java-string-operations-7 + core-java-string-operations-7 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.apache.commons + commons-lang3 + ${apache.commons.lang3.version} + + + org.apache.commons + commons-text + ${commons-text.version} + + + org.liquibase + liquibase-core + 4.9.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.liquibase + liquibase-core + 4.9.1 + test + + + junit + junit + 4.13.2 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + 11 + 11 + 3.13.0 + 1.10.0 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtils.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtils.java new file mode 100644 index 0000000000..cccc745499 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtils.java @@ -0,0 +1,40 @@ +package com.baeldung.capitalizefirstcharactereachword; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; + +class CapitalizeFirstCharacterEachWordUtils { + + static String usingCharacterToUpperCaseMethod(String input) { + if (input == null || input.isEmpty()) { + return null; + } + + return Arrays.stream(input.split("\\s+")) + .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1)) + .collect(Collectors.joining(" ")); + } + + static String usingStringToUpperCaseMethod(String input) { + if (input == null || input.isEmpty()) { + return null; + } + + return Arrays.stream(input.split("\\s+")) + .map(word -> word.substring(0, 1).toUpperCase() + word.substring(1)) + .collect(Collectors.joining(" ")); + } + + static String usingStringUtilsClass(String input) { + if (input == null || input.isEmpty()) { + return null; + } + + return Arrays.stream(input.split("\\s+")) + .map(StringUtils::capitalize) + .collect(Collectors.joining(" ")); + } + +} diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/CharsetUsageExample.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/CharsetUsageExample.java new file mode 100644 index 0000000000..5ef8783ac8 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/CharsetUsageExample.java @@ -0,0 +1,34 @@ +package com.baeldung.mutablestrings; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +public class CharsetUsageExample { + + public ByteBuffer encodeString(String inputString) { + Charset charset = Charset.forName("UTF-8"); + CharsetEncoder encoder = charset.newEncoder(); + + CharBuffer charBuffer = CharBuffer.wrap(inputString); + ByteBuffer byteBuffer = ByteBuffer.allocate(50); + + encoder.encode(charBuffer, byteBuffer, true); // true indicates the end of input + byteBuffer.flip(); + return byteBuffer; + } + + public String decodeString(ByteBuffer byteBuffer) { + Charset charset = Charset.forName("UTF-8"); + CharsetDecoder decoder = charset.newDecoder(); + CharBuffer decodedCharBuffer = CharBuffer.allocate(50); + decoder.decode(byteBuffer, decodedCharBuffer, true); + decodedCharBuffer.flip(); + + return decodedCharBuffer.toString(); + } +} diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStringUsingCharset.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStringUsingCharset.java new file mode 100644 index 0000000000..3e4285c9d0 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStringUsingCharset.java @@ -0,0 +1,65 @@ +package com.baeldung.mutablestrings; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.util.concurrent.atomic.AtomicReference; + +public class MutableStringUsingCharset { + + private final AtomicReference cbRef = new AtomicReference<>(); + private final Charset myCharset = new Charset("mycharset", null) { + @Override + public boolean contains(Charset cs) { + return false; + } + + @Override + public CharsetDecoder newDecoder() { + return new CharsetDecoder(this, 1.0f, 1.0f) { + @Override + protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { + cbRef.set(out); + while (in.remaining() > 0) { + out.append((char) in.get()); + } + return CoderResult.UNDERFLOW; + } + }; + } + + @Override + public CharsetEncoder newEncoder() { + CharsetEncoder cd = new CharsetEncoder(this, 1.0f, 1.0f) { + @Override + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { + while (in.hasRemaining()) { + if (!out.hasRemaining()) { + return CoderResult.OVERFLOW; + } + char currentChar = in.get(); + if (currentChar > 127) { + return CoderResult.unmappableForLength(1); + } + out.put((byte) currentChar); + } + return CoderResult.UNDERFLOW; + } + }; + return cd; + } + }; + + public String createModifiableString(String s) { + return new String(s.getBytes(), myCharset); + } + + public void modifyString() { + CharBuffer cb = cbRef.get(); + cb.position(0); + cb.put("xyz"); + } +} diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStrings.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStrings.java new file mode 100644 index 0000000000..99994498b9 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/mutablestrings/MutableStrings.java @@ -0,0 +1,24 @@ +package com.baeldung.mutablestrings; + +import java.lang.reflect.Field; +import java.nio.charset.Charset; + +import com.google.errorprone.annotations.DoNotCall; + +public class MutableStrings { + + /** + * This involves using Reflection to change String fields and it is not encouraged to use this in programs. + * @throws NoSuchFieldException + * @throws IllegalAccessException + */ + @DoNotCall + public void mutableUsingReflection() throws NoSuchFieldException, IllegalAccessException { + String myString = "Hello World"; + String otherString = new String("Hello World"); + Field f = String.class.getDeclaredField("value"); + f.setAccessible(true); + f.set(myString, "Hi World".toCharArray()); + System.out.println(otherString); + } +} diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/strcontainsnumber/StrContainsNumberUtils.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/strcontainsnumber/StrContainsNumberUtils.java new file mode 100644 index 0000000000..a609b94cb8 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/strcontainsnumber/StrContainsNumberUtils.java @@ -0,0 +1,77 @@ +package com.baeldung.strcontainsnumber; + +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.base.CharMatcher; + +public class StrContainsNumberUtils { + + static boolean checkUsingMatchesMethod(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + return input.matches(".*\\d.*"); + } + + static boolean checkUsingPatternClass(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + return Pattern.compile(".*\\d.*") + .matcher(input) + .matches(); + } + + static boolean checkUsingReplaceAllMethod(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + String result = input.replaceAll("\\d", ""); + return result.length() != input.length(); + } + + static boolean checkUsingIsDigitMethod(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + for (char c : input.toCharArray()) { + if (Character.isDigit(c)) { + return true; + } + } + + return false; + } + + static boolean checkUsingStreamApi(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + return input.chars() + .anyMatch(Character::isDigit); + } + + static boolean checkUsingApacheCommonsLang(String input) { + String result = StringUtils.getDigits(input); + return result != null && !result.isEmpty(); + } + + static boolean checkUsingGuava(String input) { + if (input == null || input.isEmpty()) { + return false; + } + + String result = CharMatcher.forPredicate(Character::isDigit) + .retainFrom(input); + + return !result.isEmpty(); + } + +} diff --git a/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/unicode/UnicodeLetterChecker.java b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/unicode/UnicodeLetterChecker.java new file mode 100644 index 0000000000..8ac8671586 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/main/java/com/baeldung/unicode/UnicodeLetterChecker.java @@ -0,0 +1,30 @@ +package com.baeldung.unicode; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; + +public class UnicodeLetterChecker { + public boolean characterClassCheck(String input) { + for (char c : input.toCharArray()) { + if (!Character.isLetter(c)) { + return false; + } + } + return true; + } + + public boolean regexCheck(String input) { + Pattern pattern = Pattern.compile("^\\p{L}+$"); + Matcher matcher = pattern.matcher(input); + return matcher.matches(); + } + + public boolean isAlphaCheck(String input) { + return StringUtils.isAlpha(input); + } + + public boolean StreamsCheck(String input) { + return input.codePoints().allMatch(Character::isLetter); + } +} diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtilsUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtilsUnitTest.java new file mode 100644 index 0000000000..27c7ddb4c4 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/capitalizefirstcharactereachword/CapitalizeFirstCharacterEachWordUtilsUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.capitalizefirstcharactereachword; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.commons.text.WordUtils; +import org.junit.jupiter.api.Test; + +class CapitalizeFirstCharacterEachWordUtilsUnitTest { + + @Test + void givenString_whenUsingCharacterToUpperCaseMethod_thenCapitalizeFirstCharacter() { + String input = "hello baeldung visitors"; + + assertEquals("Hello Baeldung Visitors", CapitalizeFirstCharacterEachWordUtils.usingCharacterToUpperCaseMethod(input)); + } + + @Test + void givenString_whenUsingSubstringMethod_thenCapitalizeFirstCharacter() { + String input = "Hi, my name is azhrioun"; + + assertEquals("Hi, My Name Is Azhrioun", CapitalizeFirstCharacterEachWordUtils.usingStringToUpperCaseMethod(input)); + } + + @Test + void givenString_whenUsingStringUtilsClass_thenCapitalizeFirstCharacter() { + String input = "life is short the world is wide"; + + assertEquals("Life Is Short The World Is Wide", CapitalizeFirstCharacterEachWordUtils.usingStringUtilsClass(input)); + } + + @Test + void givenString_whenUsingWordUtilsClass_thenCapitalizeFirstCharacter() { + String input = "smile sunshine is good for your teeth"; + + assertEquals("Smile Sunshine Is Good For Your Teeth", WordUtils.capitalizeFully(input)); + } + +} diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/centertext/CenteringTextUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/centertext/CenteringTextUnitTest.java new file mode 100644 index 0000000000..a3f95b0181 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/centertext/CenteringTextUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.centertext; + +import liquibase.repackaged.org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; + +public class CenteringTextUnitTest { + + @Test + public void givenTextAndTotalWidth_whenUsingStringFormat_thenTextIsCentered() { + String text = "Centered Text"; + int totalWidth = 15; + int padding = (totalWidth - text.length()) / 2; + String centeredText = String.format("%" + padding + "s%s%" + padding + "s", "", text, ""); + Assert.assertEquals(" Centered Text ", centeredText); + } + + @Test + public void givenTextAndTotalWidth_whenCenterUsingStringBuilder_thenTextIsCentered() { + String text = "Centered Text"; + int width = 15; + int padding = (width - text.length()) / 2; + StringBuilder centeredText = new StringBuilder(); + for (int i = 0; i < padding; i++) { + centeredText.append(" "); + } + centeredText.append(text); + for (int i = 0; i < padding; i++) { + centeredText.append(" "); + } + String centeredTextString = centeredText.toString(); + Assert.assertEquals(" Centered Text ", centeredTextString); + } + + @Test + public void givenTextAndTotalWidth_whenUsingStringUtilsCenterMethod_thenTextIsCentered() { + String text = "Centered Text"; + int width = 15; + String centeredText = StringUtils.center(text, width); + assertEquals(" Centered Text ", centeredText); + } + +} diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/CharsetUsageUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/CharsetUsageUnitTest.java new file mode 100644 index 0000000000..f009b0242f --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/CharsetUsageUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.mutablestring; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.baeldung.mutablestrings.CharsetUsageExample; + +public class CharsetUsageUnitTest { + + @Test + public void givenCharset_whenStringIsEncodedAndDecoded_thenGivesCorrectResult() { + CharsetUsageExample ch = new CharsetUsageExample(); + String inputString = "hello दुनिया"; + String result = ch.decodeString(ch.encodeString(inputString)); + Assertions.assertEquals(inputString, result); + } +} diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/MutableStringUsingCharsetUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/MutableStringUsingCharsetUnitTest.java new file mode 100644 index 0000000000..81a92038d5 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/mutablestring/MutableStringUsingCharsetUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.mutablestring; + +import org.junit.Assert; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import com.baeldung.mutablestrings.MutableStringUsingCharset; + +public class MutableStringUsingCharsetUnitTest { + @Test + @Disabled + /** + * This test is disabled as it works well for Java 8 and below + */ + public void givenCustomCharSet_whenStringUpdated_StringGetsMutated() throws Exception { + MutableStringUsingCharset ms = new MutableStringUsingCharset(); + String s = ms.createModifiableString("Hello"); + Assert.assertEquals("Hello", s); + ms.modifyString(); + Assert.assertEquals("something", s); + } + +} + diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/strcontainsnumber/StrContainsNumberUtilsUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/strcontainsnumber/StrContainsNumberUtilsUnitTest.java new file mode 100644 index 0000000000..9a60a827e0 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/strcontainsnumber/StrContainsNumberUtilsUnitTest.java @@ -0,0 +1,69 @@ +package com.baeldung.strcontainsnumber; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.Test; + +public class StrContainsNumberUtilsUnitTest { + + private static final String INPUT_WITH_NUMBERS = "We hope 2024 will be great"; + private static final String INPUT_WITHOUT_NUMBERS = "Hello world"; + + @Test + public void givenInputString_whenUsingMatchesMethod_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingMatchesMethod(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingMatchesMethod(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingMatchesMethod("")); + assertFalse(StrContainsNumberUtils.checkUsingMatchesMethod(null)); + } + + @Test + public void givenInputString_whenUsingPatternClass_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingPatternClass(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingPatternClass(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingPatternClass("")); + assertFalse(StrContainsNumberUtils.checkUsingPatternClass(null)); + } + + @Test + public void givenInputString_whenUsingReplaceAllMethod_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingReplaceAllMethod(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingReplaceAllMethod(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingReplaceAllMethod("")); + assertFalse(StrContainsNumberUtils.checkUsingReplaceAllMethod(null)); + } + + @Test + public void givenInputString_whenUsingIsDigitMethod_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingIsDigitMethod(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingIsDigitMethod(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingIsDigitMethod("")); + assertFalse(StrContainsNumberUtils.checkUsingIsDigitMethod(null)); + } + + @Test + public void givenInputString_whenUsingStreamApi_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingStreamApi(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingStreamApi(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingStreamApi("")); + assertFalse(StrContainsNumberUtils.checkUsingStreamApi(null)); + } + + @Test + public void givenInputString_whenUsingApacheCommonsLang_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingApacheCommonsLang(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingApacheCommonsLang(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingApacheCommonsLang("")); + assertFalse(StrContainsNumberUtils.checkUsingApacheCommonsLang(null)); + } + + @Test + public void givenInputString_whenUsingGuava_ThenCheck() { + assertTrue(StrContainsNumberUtils.checkUsingGuava(INPUT_WITH_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingGuava(INPUT_WITHOUT_NUMBERS)); + assertFalse(StrContainsNumberUtils.checkUsingGuava("")); + assertFalse(StrContainsNumberUtils.checkUsingGuava(null)); + } + +} diff --git a/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/unicode/UnicodeLetterCheckerUnitTest.java b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/unicode/UnicodeLetterCheckerUnitTest.java new file mode 100644 index 0000000000..a7ed9e5db9 --- /dev/null +++ b/core-java-modules/core-java-string-operations-7/src/test/java/com/baeldung/unicode/UnicodeLetterCheckerUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.unicode; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +public class UnicodeLetterCheckerUnitTest { + @Test + public void givenString_whenUsingIsLetter_thenReturnTrue() { + UnicodeLetterChecker checker = new UnicodeLetterChecker(); + + boolean isUnicodeLetter = checker.characterClassCheck("HelloWorld"); + assertTrue(isUnicodeLetter); + } + + @Test + public void givenString_whenUsingRegex_thenReturnTrue() { + UnicodeLetterChecker checker = new UnicodeLetterChecker(); + + boolean isUnicodeLetter = checker.regexCheck("HelloWorld"); + assertTrue(isUnicodeLetter); + } + + @Test + public void givenString_whenUsingIsAlpha_thenReturnTrue() { + UnicodeLetterChecker checker = new UnicodeLetterChecker(); + + boolean isUnicodeLetter = checker.isAlphaCheck("HelloWorld"); + assertTrue(isUnicodeLetter); + } + + @Test + public void givenString_whenUsingStreams_thenReturnTrue() { + UnicodeLetterChecker checker = new UnicodeLetterChecker(); + + boolean isUnicodeLetter = checker.StreamsCheck("HelloWorld"); + assertTrue(isUnicodeLetter); + } +} diff --git a/core-java-modules/core-java-string-operations/pom.xml b/core-java-modules/core-java-string-operations/pom.xml index 577736a324..601d0341a3 100644 --- a/core-java-modules/core-java-string-operations/pom.xml +++ b/core-java-modules/core-java-string-operations/pom.xml @@ -15,30 +15,20 @@ - javax.xml.bind - jaxb-api - 2.4.0-b180725.0427 + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.xml.bind-api.version} org.apache.commons commons-lang3 ${commons-lang3.version} - - org.openjdk.jmh - jmh-core - ${jmh-core.version} - log4j log4j ${log4j.version} - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh-generator.version} - commons-codec commons-codec @@ -57,7 +47,8 @@ - 1.15 + 1.16.0 + 4.0.0 \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/base64encodinganddecoding/StringToByteArrayUnitTest.java b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/base64encodinganddecoding/StringToByteArrayUnitTest.java index 6f8a17e316..491574f0f1 100644 --- a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/base64encodinganddecoding/StringToByteArrayUnitTest.java +++ b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/base64encodinganddecoding/StringToByteArrayUnitTest.java @@ -2,7 +2,7 @@ package com.baeldung.base64encodinganddecoding; import org.junit.Test; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.Arrays; diff --git a/core-java-modules/core-java-strings/README.md b/core-java-modules/core-java-strings/README.md index 03e980e5a5..dbbfcc79b6 100644 --- a/core-java-modules/core-java-strings/README.md +++ b/core-java-modules/core-java-strings/README.md @@ -14,3 +14,4 @@ Listed here there are only those articles that does not fit into other core-java - [Java String Interview Questions and Answers](https://www.baeldung.com/java-string-interview-questions) - [Java Multi-line String](https://www.baeldung.com/java-multiline-string) - [Reuse StringBuilder for Efficiency](https://www.baeldung.com/java-reuse-stringbuilder-for-efficiency) +- [How to Iterate Over the String Characters in Java](https://www.baeldung.com/java-iterate-string-characters) diff --git a/core-java-modules/core-java-strings/src/main/java/com/baeldung/stringIterator/StringIterator.java b/core-java-modules/core-java-strings/src/main/java/com/baeldung/stringIterator/StringIterator.java new file mode 100644 index 0000000000..0e46c7eedd --- /dev/null +++ b/core-java-modules/core-java-strings/src/main/java/com/baeldung/stringIterator/StringIterator.java @@ -0,0 +1,42 @@ +package com.baeldung.stringIterator; + +import java.text.*; +import java.util.*; + +public class StringIterator { + + public static String javaCharArray(String str){ + StringBuilder result = new StringBuilder(); + for (char c : str.toCharArray()) { + result.append(c); + } + return result.toString(); + } + + public static String javaforLoop(String str) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + result.append(c); + } + return result.toString(); + } + + public static String java8forEach(String str){ + StringBuilder result = new StringBuilder(); + str.chars().forEach(name -> { + result.append((char) name); + }); + return result.toString(); + } + + public static String javaCharacterIterator(String str){ + StringBuilder result = new StringBuilder(); + CharacterIterator it = new StringCharacterIterator(str); + while (it.current() != CharacterIterator.DONE) { + result.append(it.current()); + it.next(); + } + return result.toString(); + } +} diff --git a/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/Dummy.java b/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/Dummy.java new file mode 100644 index 0000000000..27ebf8331f --- /dev/null +++ b/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/Dummy.java @@ -0,0 +1,14 @@ +package com.baeldung.passstringbyreference; + +public class Dummy { + + String dummyString; + + public String getDummyString() { + return dummyString; + } + + public void setDummyString(String dummyString) { + this.dummyString = dummyString; + } +} diff --git a/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/PassStringUnitTest.java b/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/PassStringUnitTest.java new file mode 100644 index 0000000000..e1b284a94e --- /dev/null +++ b/core-java-modules/core-java-strings/src/test/java/com/baeldung/passstringbyreference/PassStringUnitTest.java @@ -0,0 +1,85 @@ +package com.baeldung.passstringbyreference; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +class PassStringUnitTest { + + @Test + void givenAString_whenPassedToVoidMethod_thenStringIsNotModified() { + String s = "hello"; + concatStringWithNoReturn(s); + assertEquals("hello", s); + } + + void concatStringWithNoReturn(String input) { + input += " world"; + assertEquals("hello world", input); + } + + @Test + void givenAString_whenPassedToMethodAndReturnNewString_thenStringIsModified() { + String s = "hello"; + assertEquals("hello world", concatStringWithReturn(s)); + } + + String concatStringWithReturn(String input) { + return input + " world"; + } + + @Test + void givenAString_whenPassStringBuilderToVoidMethod_thenConcatNewStringOk() { + StringBuilder builder = new StringBuilder("hello"); + concatWithStringBuilder(builder); + + assertEquals("hello world", builder.toString()); + } + + void concatWithStringBuilder(StringBuilder input) { + input.append(" world"); + } + + @Test + void givenAString_whenPassStringBufferToVoidMethod_thenConcatNewStringOk() { + StringBuffer builder = new StringBuffer("hello"); + concatWithStringBuffer(builder); + + assertEquals("hello world", builder.toString()); + } + + void concatWithStringBuffer(StringBuffer input) { + input.append(" world"); + } + + @Test + void givenObjectWithStringField_whenSetDifferentValue_thenObjectIsModified() { + Dummy dummy = new Dummy(); + assertNull(dummy.getDummyString()); + modifyStringValueInInputObject(dummy, "hello world"); + assertEquals("hello world", dummy.getDummyString()); + } + + void modifyStringValueInInputObject(Dummy dummy, String dummyString) { + dummy.setDummyString(dummyString); + } + + @Test + void givenObjectWithStringField_whenSetDifferentValueWithStringBuilder_thenSetStringInNewObject() { + assertEquals("hello world", getDummy("hello", "world").getDummyString()); + } + + Dummy getDummy(String hello, String world) { + StringBuilder builder = new StringBuilder(); + + builder.append(hello) + .append(" ") + .append(world); + + Dummy dummy = new Dummy(); + dummy.setDummyString(builder.toString()); + + return dummy; + } +} diff --git a/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringIterator/StringIteratorTest.java b/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringIterator/StringIteratorTest.java new file mode 100644 index 0000000000..585d65d4be --- /dev/null +++ b/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringIterator/StringIteratorTest.java @@ -0,0 +1,39 @@ +package com.baeldung.stringIterator; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class StringIteratorTest { + + @Test + public void whenUseCharArrayMethod_thenIterate() { + String input = "Hello, Baeldung!"; + String expectedOutput = "Hello, Baeldung!"; + String result = StringIterator.javaCharArray(input); + assertEquals(expectedOutput, result); + } + + @Test + public void whenUseJavaForLoop_thenIterate() { + String input = "Hello, Baeldung!"; + String expectedOutput = "Hello, Baeldung!"; + String result = StringIterator.javaForLoop(input); + assertEquals(expectedOutput, result); + } + + @Test + public void whenUseForEachMethod_thenIterate() { + String input = "Hello, Baeldung!"; + String expectedOutput = "Hello, Baeldung!"; + String result = StringIterator.java8ForEach(input); + assertEquals(expectedOutput, result); + } + + @Test + public void whenUseCharacterIterator_thenIterate() { + String input = "Hello, Baeldung!"; + String expectedOutput = "Hello, Baeldung!"; + String result = StringIterator.javaCharacterIterator(input); + assertEquals(expectedOutput, result); + } +} diff --git a/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringtoolong/StringTooLongUnitTest.java b/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringtoolong/StringTooLongUnitTest.java index 4035cadb83..185c2809c1 100644 --- a/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringtoolong/StringTooLongUnitTest.java +++ b/core-java-modules/core-java-strings/src/test/java/com/baeldung/stringtoolong/StringTooLongUnitTest.java @@ -27,7 +27,7 @@ public class StringTooLongUnitTest { @Test public void whenStoringInPropertiesString_thenNoCompilationError() throws IOException { String sValue = null; - try (InputStream input = new FileInputStream("src/main/resources/config.properties")) { + try (InputStream input = new FileInputStream("src/test/resources/config.properties")) { Properties prop = new Properties(); prop.load(input); sValue = prop.getProperty("string.too.long"); diff --git a/core-java-modules/core-java-strings/src/test/resources/config.properties b/core-java-modules/core-java-strings/src/test/resources/config.properties new file mode 100644 index 0000000000..86ae17679f --- /dev/null +++ b/core-java-modules/core-java-strings/src/test/resources/config.properties @@ -0,0 +1 @@ +string.too.long="a long string example" \ No newline at end of file diff --git a/core-java-modules/core-java-strings/src/test/resources/stringtoolong.txt b/core-java-modules/core-java-strings/src/test/resources/stringtoolong.txt new file mode 100644 index 0000000000..f31b4a28bd --- /dev/null +++ b/core-java-modules/core-java-strings/src/test/resources/stringtoolong.txt @@ -0,0 +1,4 @@ +Get busy living +or +get busy dying. +--Stephen King \ No newline at end of file diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index e9bb86e500..bf5b90cd32 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -24,19 +24,58 @@ - - - + + + + + + core-java-9-improvements + core-java-9-streams + core-java-9 + core-java-10 + core-java-11 + core-java-11-2 + core-java-11-3 + core-java-12 + core-java-13 + core-java-15 + core-java-collections-array-list + core-java-collections-array-list-2 + core-java-collections-list-4 + core-java-collections-list-5 + core-java-collections-maps-4 + core-java-collections-maps-5 + core-java-concurrency-simple + core-java-datetime-string + core-java-io-conversions-2 + core-java-jpms + core-java-lang-oop-constructors-2 + core-java-methods + core-java-networking-3 + core-java-os + core-java-perf-2 + core-java-streams-4 + core-java-streams-5 + core-java-streams-collect + core-java-streams-maps + core-java-string-algorithms-3 + core-java-string-operations-3 + core-java-string-operations-4 + core-java-string-operations-5 + + core-java-time-measurements core-java-annotations core-java-arrays-sorting core-java-arrays-guides core-java-arrays-multidimensional core-java-arrays-convert core-java-arrays-operations-basic + core-java-arrays-operations-basic-2 core-java-arrays-operations-advanced + core-java-arrays-operations-advanced-2 core-java-booleans core-java-char core-java-collections @@ -49,9 +88,11 @@ core-java-collections-list core-java-collections-list-2 core-java-collections-list-3 + core-java-collections-list-6 core-java-collections-maps core-java-collections-maps-2 core-java-collections-maps-3 + core-java-collections-maps-7 core-java-compiler core-java-concurrency-2 core-java-concurrency-advanced @@ -79,6 +120,7 @@ core-java-io-2 core-java-io-3 core-java-io-4 + core-java-io-5 core-java-io-apis core-java-io-apis-2 core-java-io-conversions @@ -113,6 +155,7 @@ core-java-networking-2 core-java-networking-4 core-java-nio + core-java-nio-2 core-java-numbers core-java-numbers-2 core-java-numbers-3 @@ -124,11 +167,15 @@ core-java-properties core-java-reflection core-java-reflection-2 + core-java-reflection-3 core-java-scanner core-java-security-2 core-java-security-3 + core-java-security-4 core-java-security-algorithms + core-java-serialization core-java-streams + core-java-streams-simple core-java-streams-3 core-java-string-algorithms core-java-string-algorithms-2 @@ -140,11 +187,18 @@ core-java-string-operations core-java-string-operations-2 core-java-string-operations-6 + core-java-string-operations-7 core-java-regex core-java-regex-2 core-java-uuid core-java-collections-maps-6 core-java-records + core-java-9-jigsaw + + core-java-collections-set + core-java-date-operations-1 + + core-java-httpclient diff --git a/data-structures/src/main/java/com/baeldung/avltree/AVLTree.java b/data-structures/src/main/java/com/baeldung/avltree/AVLTree.java index ca0cfce7b4..117a35e028 100644 --- a/data-structures/src/main/java/com/baeldung/avltree/AVLTree.java +++ b/data-structures/src/main/java/com/baeldung/avltree/AVLTree.java @@ -42,17 +42,17 @@ public class AVLTree { return root == null ? -1 : root.height; } - private Node insert(Node node, int key) { - if (node == null) { + private Node insert(Node root, int key) { + if (root == null) { return new Node(key); - } else if (node.key > key) { - node.left = insert(node.left, key); - } else if (node.key < key) { - node.right = insert(node.right, key); + } else if (root.key > key) { + root.left = insert(root.left, key); + } else if (root.key < key) { + root.right = insert(root.right, key); } else { throw new RuntimeException("duplicate Key!"); } - return rebalance(node); + return rebalance(root); } private Node delete(Node node, int key) { diff --git a/di-modules/avaje/README.md b/di-modules/avaje/README.md index ea914e551f..f0fa9f058e 100644 --- a/di-modules/avaje/README.md +++ b/di-modules/avaje/README.md @@ -4,4 +4,4 @@ This module contains articles about Avaje ### Relevant articles: -- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject/intro) \ No newline at end of file +- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject) diff --git a/di-modules/avaje/pom.xml b/di-modules/avaje/pom.xml index 7ffe14bd72..49162c518e 100644 --- a/di-modules/avaje/pom.xml +++ b/di-modules/avaje/pom.xml @@ -1,37 +1,37 @@ - 4.0.0 - com.baeldung - inject-intro - 0.0.1-SNAPSHOT - avaje-inject-intro - - 11 - 11 - 9.5 - - - - io.avaje - avaje-inject - ${avaje.inject.version} - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.baeldung + inject-intro + 0.0.1-SNAPSHOT + avaje-inject-intro + + 11 + 11 + 9.5 + + + + io.avaje + avaje-inject + ${avaje.inject.version} + - - io.avaje - avaje-inject-test - ${avaje.inject.version} - test - + + io.avaje + avaje-inject-test + ${avaje.inject.version} + test + - - - io.avaje - avaje-inject-generator - ${avaje.inject.version} - provided - true - - + + + io.avaje + avaje-inject-generator + ${avaje.inject.version} + provided + true + + \ No newline at end of file diff --git a/disruptor/pom.xml b/disruptor/pom.xml index 75e783e935..b3b065d67e 100644 --- a/disruptor/pom.xml +++ b/disruptor/pom.xml @@ -119,7 +119,6 @@ 3.3.6 2.4.3 - 3.0.2 1.4.4 diff --git a/docker-modules/docker-caching/multi-module-caching/pom.xml b/docker-modules/docker-caching/multi-module-caching/pom.xml index b64cf1a8b8..60f14a17e5 100644 --- a/docker-modules/docker-caching/multi-module-caching/pom.xml +++ b/docker-modules/docker-caching/multi-module-caching/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/docker-modules/docker-caching/single-module-caching/pom.xml b/docker-modules/docker-caching/single-module-caching/pom.xml index a388c7563f..0e5174b7ca 100644 --- a/docker-modules/docker-caching/single-module-caching/pom.xml +++ b/docker-modules/docker-caching/single-module-caching/pom.xml @@ -49,7 +49,7 @@ 8 8 UTF-8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/docker-modules/dockerfile/git-strategies/.gitmodules b/docker-modules/dockerfile-git-strategies/.gitmodules similarity index 100% rename from docker-modules/dockerfile/git-strategies/.gitmodules rename to docker-modules/dockerfile-git-strategies/.gitmodules diff --git a/docker-modules/dockerfile/git-strategies/Dockerfile b/docker-modules/dockerfile-git-strategies/Dockerfile similarity index 91% rename from docker-modules/dockerfile/git-strategies/Dockerfile rename to docker-modules/dockerfile-git-strategies/Dockerfile index 91dfee3bc6..98911bdcbd 100644 --- a/docker-modules/dockerfile/git-strategies/Dockerfile +++ b/docker-modules/dockerfile-git-strategies/Dockerfile @@ -1,4 +1,4 @@ -ADD . /project/ +ADD git-strategies /project/ ADD /build/ /project/ ADD /output/project.jar /project/ diff --git a/docker-modules/dockerfile/README.md b/docker-modules/dockerfile-git-strategies/README.md similarity index 100% rename from docker-modules/dockerfile/README.md rename to docker-modules/dockerfile-git-strategies/README.md diff --git a/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java b/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java index fd2090aecb..386b2ca4a7 100644 --- a/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java +++ b/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java @@ -1,8 +1,15 @@ package com.baeldung.drools.config; +import java.util.Arrays; +import java.util.List; + import org.drools.decisiontable.DecisionTableProviderImpl; import org.kie.api.KieServices; -import org.kie.api.builder.*; +import org.kie.api.builder.KieBuilder; +import org.kie.api.builder.KieFileSystem; +import org.kie.api.builder.KieModule; +import org.kie.api.builder.KieRepository; +import org.kie.api.builder.ReleaseId; import org.kie.api.io.Resource; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; @@ -10,35 +17,19 @@ import org.kie.internal.builder.DecisionTableConfiguration; import org.kie.internal.builder.DecisionTableInputType; import org.kie.internal.builder.KnowledgeBuilderFactory; import org.kie.internal.io.ResourceFactory; -import java.util.Arrays; -import java.util.List; public class DroolsBeanFactory { private static final String RULES_PATH = "com/baeldung/drools/rules/"; private KieServices kieServices = KieServices.Factory.get(); - private KieFileSystem getKieFileSystem() { + private KieFileSystem getKieFileSystem() { KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); - List rules = Arrays.asList("BackwardChaining.drl", "SuggestApplicant.drl", "Product_rules.drl.xls"); - for(String rule:rules) { + List rules = Arrays.asList("com/baeldung/drools/rules/BackwardChaining.drl", "com/baeldung/drools/rules/SuggestApplicant.drl", "com/baeldung/drools/rules/Product_rules.drl.xls"); + for (String rule : rules) { kieFileSystem.write(ResourceFactory.newClassPathResource(rule)); } return kieFileSystem; - - } - - public KieContainer getKieContainer() { - getKieRepository(); - - KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem()); - kb.buildAll(); - - KieModule kieModule = kb.getKieModule(); - KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId()); - - return kContainer; - } private void getKieRepository() { @@ -47,20 +38,14 @@ public class DroolsBeanFactory { } public KieSession getKieSession() { - getKieRepository(); - KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); - - kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/BackwardChaining.drl")); - kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/SuggestApplicant.drl")); - kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/Product_rules.drl.xls")); - - KieBuilder kb = kieServices.newKieBuilder(kieFileSystem); + KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem()); kb.buildAll(); - KieModule kieModule = kb.getKieModule(); - KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId()); + KieRepository kieRepository = kieServices.getRepository(); + ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId(); + KieContainer kieContainer = kieServices.newKieContainer(krDefaultReleaseId); - return kContainer.newKieSession(); + return kieContainer.newKieSession(); } public KieSession getKieSession(Resource dt) { diff --git a/google-auto-project/README.md b/google-auto-project/README.md index d45a113a8f..44dd6c5d61 100644 --- a/google-auto-project/README.md +++ b/google-auto-project/README.md @@ -8,3 +8,5 @@ This module contains articles about automatic code generation - [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) +- [Java Annotation Processing and Creating a Builder](https://www.baeldung.com/java-annotation-processing-builder) + diff --git a/annotations/annotation-processing/pom.xml b/google-auto-project/annotation-processing/pom.xml similarity index 90% rename from annotations/annotation-processing/pom.xml rename to google-auto-project/annotation-processing/pom.xml index 14bbc409e5..5c872c2059 100644 --- a/annotations/annotation-processing/pom.xml +++ b/google-auto-project/annotation-processing/pom.xml @@ -8,8 +8,8 @@ com.baeldung - 1.0.0-SNAPSHOT - annotations + google-auto-project + 1.0 diff --git a/annotations/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProcessor.java b/google-auto-project/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProcessor.java similarity index 100% rename from annotations/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProcessor.java rename to google-auto-project/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProcessor.java diff --git a/annotations/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProperty.java b/google-auto-project/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProperty.java similarity index 100% rename from annotations/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProperty.java rename to google-auto-project/annotation-processing/src/main/java/com/baeldung/annotation/processor/BuilderProperty.java diff --git a/spring-ejb-modules/wildfly/widlfly-web/src/main/resources/logback.xml b/google-auto-project/annotation-processing/src/main/resources/logback.xml similarity index 100% rename from spring-ejb-modules/wildfly/widlfly-web/src/main/resources/logback.xml rename to google-auto-project/annotation-processing/src/main/resources/logback.xml diff --git a/annotations/annotation-user/pom.xml b/google-auto-project/annotation-user/pom.xml similarity index 88% rename from annotations/annotation-user/pom.xml rename to google-auto-project/annotation-user/pom.xml index 37a2e36f61..c21a4ca03d 100644 --- a/annotations/annotation-user/pom.xml +++ b/google-auto-project/annotation-user/pom.xml @@ -8,8 +8,8 @@ com.baeldung - annotations - 1.0.0-SNAPSHOT + google-auto-project + 1.0 diff --git a/annotations/annotation-user/src/main/java/com/baeldung/annotation/Person.java b/google-auto-project/annotation-user/src/main/java/com/baeldung/annotation/Person.java similarity index 100% rename from annotations/annotation-user/src/main/java/com/baeldung/annotation/Person.java rename to google-auto-project/annotation-user/src/main/java/com/baeldung/annotation/Person.java diff --git a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/resources/logback.xml b/google-auto-project/annotation-user/src/main/resources/logback.xml similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/resources/logback.xml rename to google-auto-project/annotation-user/src/main/resources/logback.xml diff --git a/annotations/annotation-user/src/test/java/com/baeldung/annotation/PersonBuilderUnitTest.java b/google-auto-project/annotation-user/src/test/java/com/baeldung/annotation/PersonBuilderUnitTest.java similarity index 100% rename from annotations/annotation-user/src/test/java/com/baeldung/annotation/PersonBuilderUnitTest.java rename to google-auto-project/annotation-user/src/test/java/com/baeldung/annotation/PersonBuilderUnitTest.java diff --git a/google-auto-project/pom.xml b/google-auto-project/pom.xml index 839ccabc5f..034fea5aad 100644 --- a/google-auto-project/pom.xml +++ b/google-auto-project/pom.xml @@ -6,6 +6,8 @@ google-auto-project 1.0 google-auto-project + pom + com.baeldung @@ -13,6 +15,11 @@ 1.0.0-SNAPSHOT + + annotation-processing + annotation-user + + com.google.auto.value diff --git a/gradle-modules/gradle-5/README.md b/gradle-modules/gradle-5/README.md index e37c100534..7871c0e822 100644 --- a/gradle-modules/gradle-5/README.md +++ b/gradle-modules/gradle-5/README.md @@ -2,3 +2,4 @@ - [Run a Java main Method Using Gradle](https://www.baeldung.com/gradle-run-java-main) - [Finding Unused Gradle Dependencies](https://www.baeldung.com/gradle-finding-unused-dependencies) +- [Intro to Gradle Lint Plugin](https://www.baeldung.com/java-gradle-lint-intro) diff --git a/gradle-modules/gradle-5/build.gradle b/gradle-modules/gradle-5/build.gradle index 84cf05bad6..bc3f233f99 100644 --- a/gradle-modules/gradle-5/build.gradle +++ b/gradle-modules/gradle-5/build.gradle @@ -1,14 +1,21 @@ -plugins{ - id "nebula.lint" version "16.9.0" +plugins { + id "nebula.lint" version "18.1.0" } + description = "Gradle 5 root project" allprojects { - apply plugin :"java" - apply plugin :"nebula.lint" + apply plugin: "java" + apply plugin: "nebula.lint" gradleLint { - rules=['unused-dependency'] + rules = [ + // 'unused-dependency', + // 'dependency-parentheses', + // 'undeclared-dependency', + // 'minimum-dependency-version' + ] reportFormat = 'text' + reportOnlyFixableViolations = true } group = "com.baeldung" version = "0.0.1" @@ -16,6 +23,6 @@ allprojects { targetCompatibility = "1.8" repositories { - jcenter() + mavenCentral() } } \ No newline at end of file diff --git a/gradle-modules/gradle-5/gradle-lint-intro.gradle b/gradle-modules/gradle-5/gradle-lint-intro.gradle new file mode 100644 index 0000000000..4b919c21e8 --- /dev/null +++ b/gradle-modules/gradle-5/gradle-lint-intro.gradle @@ -0,0 +1,6 @@ +allprojects { + apply plugin: "nebula.lint" + gradleLint { + rules = ['dependency-parenthesis'] + } +} \ No newline at end of file diff --git a/gradle-modules/gradle-5/gradle-lint-intro/.gitignore b/gradle-modules/gradle-5/gradle-lint-intro/.gitignore new file mode 100644 index 0000000000..84c048a73c --- /dev/null +++ b/gradle-modules/gradle-5/gradle-lint-intro/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/gradle-modules/gradle-5/gradle-lint-intro/build.gradle b/gradle-modules/gradle-5/gradle-lint-intro/build.gradle new file mode 100644 index 0000000000..fab83bfeec --- /dev/null +++ b/gradle-modules/gradle-5/gradle-lint-intro/build.gradle @@ -0,0 +1,15 @@ + +description = "Introduction to Gradle Lint Plugin" + +ext { + awsVersion = '2.20.83' +} + + +dependencies { + implementation platform("software.amazon.awssdk:bom:$awsVersion") + testImplementation('junit:junit:4.13.1') + gradleLint.ignore('unused-dependency', 'dependency-parentheses') { + implementation('software.amazon.awssdk:sts') + } +} diff --git a/gradle-modules/gradle-5/gradle/wrapper/gradle-wrapper.properties b/gradle-modules/gradle-5/gradle/wrapper/gradle-wrapper.properties index 4c46317507..7666e22b54 100644 --- a/gradle-modules/gradle-5/gradle/wrapper/gradle-wrapper.properties +++ b/gradle-modules/gradle-5/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip diff --git a/gradle-modules/gradle-5/lint.gradle b/gradle-modules/gradle-5/lint.gradle new file mode 100644 index 0000000000..7fc8ca780e --- /dev/null +++ b/gradle-modules/gradle-5/lint.gradle @@ -0,0 +1,16 @@ +import com.netflix.nebula.lint.plugin.GradleLintPlugin + +initscript { + repositories { mavenCentral() } + dependencies { + classpath 'com.netflix.nebula:gradle-lint-plugin:18.1.0' + } +} + +allprojects { + apply plugin: GradleLintPlugin + gradleLint { + rules=[] + alwaysRun= false + } +} \ No newline at end of file diff --git a/gradle-modules/gradle-5/settings.gradle b/gradle-modules/gradle-5/settings.gradle index c73af319a3..3173a23d5c 100644 --- a/gradle-modules/gradle-5/settings.gradle +++ b/gradle-modules/gradle-5/settings.gradle @@ -2,4 +2,5 @@ rootProject.name='gradle-5' include 'java-exec' include 'unused-dependencies' include 'source-sets' -include 'cmd-line-args' \ No newline at end of file +include 'cmd-line-args' +include 'gradle-lint-intro' \ No newline at end of file diff --git a/gradle-modules/gradle/gradle-fat-jar/build.gradle b/gradle-modules/gradle/gradle-fat-jar/build.gradle index 6e2934194e..4c3d86d757 100644 --- a/gradle-modules/gradle/gradle-fat-jar/build.gradle +++ b/gradle-modules/gradle/gradle-fat-jar/build.gradle @@ -8,8 +8,10 @@ buildscript { } } -apply plugin: 'java' -apply plugin: 'com.github.johnrengelman.shadow' +plugins { + id 'com.github.johnrengelman.shadow' version '7.1.2' + id 'java' +} repositories { mavenCentral() @@ -30,7 +32,7 @@ task customFatJar(type: Jar) { manifest { attributes 'Main-Class': 'com.baeldung.fatjar.Application' } - baseName = 'all-in-one-jar' + archiveBaseName = 'all-in-one-jar' duplicatesStrategy = DuplicatesStrategy.EXCLUDE from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } with jar diff --git a/guest/README.md b/guest/README.md deleted file mode 100644 index ff12555376..0000000000 --- a/guest/README.md +++ /dev/null @@ -1 +0,0 @@ -## Relevant articles: diff --git a/guest/memory-leaks/src/test/java/com/baeldung/Key.java b/guest/memory-leaks/src/test/java/com/baeldung/Key.java deleted file mode 100644 index 6ae2fe7fcf..0000000000 --- a/guest/memory-leaks/src/test/java/com/baeldung/Key.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.baeldung; - -public class Key { - - public static String key; - - public Key(String key) { - Key.key = key; - } - -} diff --git a/guest/memory-leaks/src/test/java/com/baeldung/MemoryLeaksTest.java b/guest/memory-leaks/src/test/java/com/baeldung/MemoryLeaksTest.java deleted file mode 100644 index a8a094b4db..0000000000 --- a/guest/memory-leaks/src/test/java/com/baeldung/MemoryLeaksTest.java +++ /dev/null @@ -1,98 +0,0 @@ -//package com.baeldung; -// -//import java.io.BufferedReader; -//import java.io.File; -//import java.io.IOException; -//import java.io.InputStream; -//import java.io.InputStreamReader; -//import java.net.URISyntaxException; -//import java.net.URL; -//import java.net.URLConnection; -//import java.nio.charset.StandardCharsets; -//import java.nio.file.Files; -//import java.nio.file.Paths; -//import java.nio.file.StandardOpenOption; -//import java.util.ArrayList; -//import java.util.Map; -//import java.util.Random; -//import java.util.Scanner; -// -//import org.junit.FixMethodOrder; -//import org.junit.Test; -//import org.junit.runner.RunWith; -//import org.junit.runners.JUnit4; -//import org.junit.runners.MethodSorters; -// -//@FixMethodOrder(MethodSorters.NAME_ASCENDING) -//@RunWith(JUnit4.class) -//public class MemoryLeaksTest { -// private Random random = new Random(); -// public static final ArrayList list = new ArrayList(1000000); -// -// @Test -// public void givenStaticField_whenLotsOfOperations_thenMemoryLeak() throws InterruptedException { -// for (int i = 0; i < 1000000; i++) { -// list.add(random.nextDouble()); -// } -// System.gc(); -// Thread.sleep(10000); //to allow GC do its job -// } -// -// -// @Test -// public void givenNormalField_whenLotsOfOperations_thenGCWorksFine() throws InterruptedException { -// addElementsToTheList(); -// System.gc(); -// Thread.sleep(10000); //to allow GC do its job -// } -// -// private void addElementsToTheList(){ -// ArrayList list = new ArrayList(1000000); -// for (int i = 0; i < 1000000; i++) { -// list.add(random.nextDouble()); -// } -// } -// -// @SuppressWarnings({ "resource" }) -// @Test(expected = OutOfMemoryError.class) -// public void givenLengthString_whenIntern_thenOutOfMemory() throws IOException, InterruptedException { -// Thread.sleep(15000); -// String str = new Scanner(new File("src/test/resources/large.txt"), "UTF-8").useDelimiter("\\A") -// .next(); -// System.gc(); -// str.intern(); -// Thread.sleep(10000); -// } -// -// @Test(expected = OutOfMemoryError.class) -// public void givenURL_whenUnclosedStream_thenOutOfMemory() throws IOException, URISyntaxException { -// String str = ""; -// URLConnection conn = new URL("http:norvig.com/big.txt").openConnection(); -// BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); -// while (br.readLine() != null) { -// str += br.readLine(); -// } -// Files.write(Paths.get("src/main/resources/"), str.getBytes(), StandardOpenOption.CREATE); -// } -// -// @SuppressWarnings("unused") -// @Test(expected = OutOfMemoryError.class) -// public void givenConnection_whenUnclosed_thenOutOfMemory() throws IOException, URISyntaxException { -// URL url = new URL("ftp:speedtest.tele2.net"); -// URLConnection urlc = url.openConnection(); -// InputStream is = urlc.getInputStream(); -// String str = ""; -// while (true) { -// str += is.toString() -// .intern(); -// } -// } -// -// @Test(expected = OutOfMemoryError.class) -// public void givenMap_whenNoEqualsNoHashCodeMethods_thenOutOfMemory() throws IOException, URISyntaxException { -// Map map = System.getProperties(); -// while (true) { -// map.put(new Key("key"), "value"); -// } -// } -//} diff --git a/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java b/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java index 047d53ab62..4dc9e40292 100644 --- a/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java +++ b/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java @@ -20,6 +20,7 @@ import org.joda.time.DateTimeZone; import org.junit.Test; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.util.StdDateFormat; @@ -67,6 +68,8 @@ public class JacksonDateUnitTest { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.findAndRegisterModules(); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID); + objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); String converted = objectMapper.writeValueAsString(now); diff --git a/jackson-modules/jackson-jr/README.md b/jackson-modules/jackson-jr/README.md index ad7d5dce7d..f435469a90 100644 --- a/jackson-modules/jackson-jr/README.md +++ b/jackson-modules/jackson-jr/README.md @@ -1,3 +1,2 @@ ## Relevant Articles - [Guide to Java Jackson-jr Library](https://www.baeldung.com/java-jackson-jr-library) -- [Difference Between Future, CompletableFuture, and Rxjava’s Observable](https://www.baeldung.com/java-future-completablefuture-rxjavas-observable) diff --git a/jackson-modules/jackson-polymorphic-deserialization/README.md b/jackson-modules/jackson-polymorphic-deserialization/README.md index feb40da5c4..a8468ab829 100644 --- a/jackson-modules/jackson-polymorphic-deserialization/README.md +++ b/jackson-modules/jackson-polymorphic-deserialization/README.md @@ -1,2 +1,2 @@ ## Relevant Articles -- [@JsonSubTypes Vs. Reflections for Polymorphic Deserialization in Jackson](https://www.baeldung.com/java-jackson-polymorphic-deserialization) +- [@JsonSubTypes vs. Reflections for Polymorphic Deserialization in Jackson](https://www.baeldung.com/java-jackson-polymorphic-deserialization) diff --git a/jackson-modules/jackson-polymorphic-deserialization/pom.xml b/jackson-modules/jackson-polymorphic-deserialization/pom.xml index afa9cab82f..0d88c19500 100644 --- a/jackson-modules/jackson-polymorphic-deserialization/pom.xml +++ b/jackson-modules/jackson-polymorphic-deserialization/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 jackson-polymorphic-deserialization jackson-polymorphic-deserialization diff --git a/jackson-simple/pom.xml b/jackson-simple/pom.xml index d01c43dc90..3bf523bbfa 100644 --- a/jackson-simple/pom.xml +++ b/jackson-simple/pom.xml @@ -33,7 +33,7 @@ - 2.14.2 + 2.15.2 17 diff --git a/java-jdi/pom.xml b/java-jdi/pom.xml index aad2f7cfff..e7b2326e21 100644 --- a/java-jdi/pom.xml +++ b/java-jdi/pom.xml @@ -14,10 +14,6 @@ ../parent-java - - - - java-jdi @@ -33,9 +29,6 @@ ${maven.compiler.source.version} ${maven.compiler.target.version} - - --add-exports=jdk.jdi/com.sun.jdi=ALL-UNNAMED - diff --git a/java-panama/pom.xml b/java-panama/pom.xml index 7c6b420eeb..18dffaec73 100644 --- a/java-panama/pom.xml +++ b/java-panama/pom.xml @@ -1,10 +1,10 @@ - ${project.model.version} + 4.0.0 com.baeldung.java.panama java-panama - ${project.version} + 1.0 java-panama jar diff --git a/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/ExchangeRate.java b/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/ExchangeRate.java index afc7ef92ce..026f5a23c5 100644 --- a/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/ExchangeRate.java +++ b/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/ExchangeRate.java @@ -16,9 +16,7 @@ public final class ExchangeRate { public static List providers() { List services = new ArrayList<>(); ServiceLoader loader = ServiceLoader.load(ExchangeRateProvider.class); - loader.forEach(exchangeRateProvider -> { - services.add(exchangeRateProvider); - }); + loader.forEach(services::add); return services; } diff --git a/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/api/Quote.java b/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/api/Quote.java index 577af3b618..b5c2bf23fb 100644 --- a/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/api/Quote.java +++ b/java-spi/exchange-rate-api/src/main/java/com/baeldung/rate/api/Quote.java @@ -8,7 +8,12 @@ public class Quote { private BigDecimal ask; private BigDecimal bid; private LocalDate date; - //... + + public Quote(String currency, BigDecimal ask, BigDecimal bid) { + this.currency = currency; + this.ask = ask; + this.bid = bid; + } public String getCurrency() { return currency; diff --git a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponse.java b/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponse.java deleted file mode 100644 index 9ba4fb26b0..0000000000 --- a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.rate.impl; - -import com.baeldung.rate.api.Quote; - -import java.util.List; - -public class QuoteResponse { - private List result; - private String error; - - public List getResult() { - return result; - } - - public void setResult(List result) { - this.result = result; - } - - public String getError() { - return error; - } - - public void setError(String error) { - this.error = error; - } -} diff --git a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponseWrapper.java b/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponseWrapper.java deleted file mode 100644 index 6d7be086f0..0000000000 --- a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/QuoteResponseWrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.rate.impl; - -public class QuoteResponseWrapper { - private QuoteResponse quoteResponse; - - public QuoteResponse getQuoteResponse() { - return quoteResponse; - } - - public void setQuoteResponse(QuoteResponse quoteResponse) { - this.quoteResponse = quoteResponse; - } -} diff --git a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/YahooQuoteManagerImpl.java b/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/YahooQuoteManagerImpl.java index f5c60699c7..ff507d4c9f 100644 --- a/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/YahooQuoteManagerImpl.java +++ b/java-spi/exchange-rate-impl/src/main/java/com/baeldung/rate/impl/YahooQuoteManagerImpl.java @@ -2,64 +2,102 @@ package com.baeldung.rate.impl; import com.baeldung.rate.api.Quote; import com.baeldung.rate.api.QuoteManager; + import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import javax.json.bind.Jsonb; import javax.json.bind.JsonbBuilder; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; +import java.math.BigDecimal; import java.time.LocalDate; +import java.util.ArrayList; import java.util.Currency; import java.util.List; +import java.util.Map; public class YahooQuoteManagerImpl implements QuoteManager { - static final String URL_PROVIDER = "https://query1.finance.yahoo.com/v7/finance/quote"; + static final String URL_PROVIDER = "https://query2.finance.yahoo.com/v6/finance/quoteSummary/%s=X?modules=summaryDetail"; OkHttpClient client = new OkHttpClient(); @Override public List getQuotes(String baseCurrency, LocalDate date) { - StringBuilder sb = new StringBuilder(); + List currencyQuery = new ArrayList<>(); Currency.getAvailableCurrencies().forEach(currency -> { if (!baseCurrency.equals(currency.getCurrencyCode())) { - sb.append(baseCurrency).append(currency.getCurrencyCode()).append("=X").append(","); + currencyQuery.add(String.format(URL_PROVIDER, baseCurrency + currency.getCurrencyCode())); } }); - - String value = ""; - try { - value = URLEncoder.encode(sb.toString().substring(0, sb.toString().length() - 1), "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + final List quotes = new ArrayList<>(); + for (String url: currencyQuery) { + String response = doGetRequest(url); + if (response != null) { + final Quote map = map(response); + if (map != null) { + quotes.add(map); + } + } } - String queryString = String.format("%s=%s", "symbols", value); - String response = doGetRequest(queryString); - System.out.println(response); - return map(response); + return quotes; } - private List map(String response) { - QuoteResponseWrapper qrw = JsonbBuilder.create().fromJson(response, QuoteResponseWrapper.class); - return qrw.getQuoteResponse().getResult(); + private Quote map(String response) { + try (final Jsonb jsonb = JsonbBuilder.create()) { + final Map qrw = jsonb.fromJson(response, Map.class); + return parseResult(qrw); + } catch (Exception e) { + System.out.println("Error while trying to read response"); + return null; + } } - String doGetRequest(String queryString) { - String fullUrl = URL_PROVIDER + "?" + queryString; + private static Quote parseResult(Map qrw) { + Quote quote = null; + if (qrw != null) { + final Map quoteSummary = (Map) qrw.get("quoteSummary"); + if (quoteSummary != null) { + final List result = (List) quoteSummary.get("result"); + if (result != null) { + final Map resultArray = result.get(0); + if (resultArray != null) { + final Map summaryDetail = (Map) resultArray.get("summaryDetail"); + if (summaryDetail != null) { + quote = constructQuote(summaryDetail); + } + } + } + } + } + return quote; + } - System.out.println(fullUrl); + private static Quote constructQuote(Map summaryDetail) { + final String currency = (String) summaryDetail.get("currency"); + final Map ask = (Map) summaryDetail.get("ask"); + final Map bid = (Map) summaryDetail.get("bid"); + final BigDecimal askPrice = (BigDecimal) ask.get("raw"); + final BigDecimal bidPrice = (BigDecimal) bid.get("raw"); + if (askPrice != null && bidPrice != null) { + return new Quote(currency, askPrice, bidPrice); + } + return null; + } + + String doGetRequest(String url) { + + System.out.println(url); Request request = new Request.Builder() - .url(fullUrl) + .url(url) .build(); - Response response = null; + Response response; try { response = client.newCall(request).execute(); return response.body().string(); } catch (IOException e) { - e.printStackTrace(); + return null; } - return null; } } diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml index 7c5c006aa9..d529b32022 100644 --- a/java-websocket/pom.xml +++ b/java-websocket/pom.xml @@ -30,7 +30,6 @@ 1.1 2.8.0 - 3.3.2 \ No newline at end of file diff --git a/javaxval-2/README.md b/javaxval-2/README.md index b7603d9e84..3ae53ebd94 100644 --- a/javaxval-2/README.md +++ b/javaxval-2/README.md @@ -7,4 +7,5 @@ This module contains articles about Bean Validation. - [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator) - [Hibernate Validator Annotation Processor in Depth](https://www.baeldung.com/hibernate-validator-annotation-processor) - [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) +- [Java Validation List Annotations](https://www.baeldung.com/java-validation-list-annotations) - More articles: [[<-- prev]](../javaxval) diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java new file mode 100644 index 0000000000..b6660c225a --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface AllLevels { +} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java similarity index 79% rename from spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java index 4191625b4f..31c8d69639 100644 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java @@ -1,12 +1,7 @@ -package com.baeldung.listvalidation.domain; +package com.baeldung.javaxval.listvalidation; -import com.baeldung.listvalidation.groups.AllLevels; -import com.baeldung.listvalidation.groups.Junior; -import com.baeldung.listvalidation.groups.MidSenior; -import com.baeldung.listvalidation.groups.Senior; -import org.springframework.lang.Nullable; +import jakarta.validation.constraints.*; -import javax.validation.constraints.*; import java.util.Date; public class JobAspirant { @@ -14,7 +9,6 @@ public class JobAspirant { @Size(min = 5, message = "Name should have at least 5 characters", groups = AllLevels.class), @Size(max = 20, message = "Name should have at most 20 characters", groups = AllLevels.class) }) - @Pattern.List({ @Pattern(regexp = "^[\\p{Alpha} ]*$", message = "Name should contain only alphabets and space", groups = AllLevels.class), @Pattern(regexp = "^[^\\s].*$", message = "Name should not start with space", groups = AllLevels.class), @@ -22,18 +16,8 @@ public class JobAspirant { @Pattern(regexp = "^((?! ).)*$", message = "Name should not contain consecutive spaces", groups = AllLevels.class), @Pattern(regexp = "^[^a-z].*$", message = "Name should not start with a lower case character", groups = AllLevels.class) }) - - private String name; - public Integer getExperience() { - return experience; - } - - public void setExperience(Integer experience) { - this.experience = experience; - } - @Min.List({ @Min(value = 15, message = "Years of experience cannot be less than 15 Years", groups = Senior.class), @Min(value = 10, message = "Years of experience cannot be less than 10 Years", groups = MidSenior.class), @@ -47,18 +31,16 @@ public class JobAspirant { private Integer experience; @AssertTrue.List({ - @AssertTrue(message = "Terms and Conditions consent missing for Senior Level Job Application", groups = Senior.class), - @AssertTrue(message = "Terms and Conditions consent missing for Mid-Senior Level Job Application", groups = MidSenior.class), - @AssertTrue(message = "Terms and Conditions consent missing for Junior Level Job Application", groups = Junior.class) + @AssertTrue(message = "Terms and Conditions consent missing for Senior Level Job", groups = Senior.class), + @AssertTrue(message = "Terms and Conditions consent missing for Mid-Senior Level Job", groups = MidSenior.class), + @AssertTrue(message = "Terms and Conditions consent missing for Junior Level Job", groups = Junior.class) }) - @Nullable private Boolean agreement; - @Nullable @Future.List({ - @Future(message = "Active passport is mandatory for Senior Level Job Application", groups = Senior.class), - @Future(message = "Active passport is mandatory for Mid-Senior Level Job Application", groups = MidSenior.class), - @Future(message = "Active passport is mandatory for Junior Level Job Application", groups = Junior.class) + @Future(message = "Active passport is mandatory for Senior Level Job", groups = Senior.class), + @Future(message = "Active passport is mandatory for Mid-Senior Level Job", groups = MidSenior.class), + @Future(message = "Active passport is mandatory for Junior Level Job", groups = Junior.class) }) private Date passportExpiryDate; @@ -70,8 +52,6 @@ public class JobAspirant { @Pattern(regexp = "^(Junior)$", message = "Job level should be Junior" ,flags = Pattern.Flag.CASE_INSENSITIVE, groups = Junior.class) }) -// @Pattern(regexp = "^(Senior|MidSenior|Junior)$", message = "Job level should be Senior, MidSenior or Junior" -// ,flags = Pattern.Flag.CASE_INSENSITIVE, groups = AllLevels.class) private String jobLevel; public String getJobLevel() { @@ -104,4 +84,12 @@ public class JobAspirant { public void setPassportExpiryDate(Date passportExpiryDate) { this.passportExpiryDate = passportExpiryDate; } + + public Integer getExperience() { + return experience; + } + + public void setExperience(Integer experience) { + this.experience = experience; + } } diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java new file mode 100644 index 0000000000..e881f4d6cd --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface Junior { +} diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java new file mode 100644 index 0000000000..f3a6bb67f8 --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface MidSenior { +} diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java new file mode 100644 index 0000000000..be3cf00d9c --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface Senior { +} diff --git a/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java b/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java new file mode 100644 index 0000000000..cee020c69f --- /dev/null +++ b/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java @@ -0,0 +1,209 @@ +package com.baeldung.javaxval.listvalidation; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JobAspirantUnitTest { + private static Validator validator; + @BeforeClass + public static void setupValidatorInstance() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + @Test + public void givenJobLevelJunior_whenInValidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 3, true); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 5 Years"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 8, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 10 Years"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 13, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 15 Years"); + }); + } + @Test + public void givenJobLevelJunior_whenInValidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 11, true); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 10 Years"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 16, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 15 Years"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 23, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 20 Years"); + }); + } + @Test + public void whenInvalidName_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, true); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("name"); + assertThat(action.getMessage()).isEqualTo("Name should not contain consecutive spaces"); + }); + } + @Test + public void givenJuniorLevel_whenInvalidAgreement_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 7, false); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("agreement"); + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Junior Level Job"); + }); + } + @Test + public void givenSeniorLevel_whenInvalidAgreement_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, false); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("agreement"); + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Senior Level Job"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidPassport_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2021-12-31", 12, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("passportExpiryDate"); + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Mid-Senior Level Job"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidPassport_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2021-12-31", 18, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("passportExpiryDate"); + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Senior Level Job"); + }); + } + @Test + public void givenJobLevelSenior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, true); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelMidSenior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 12, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelJunior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 7, true); + Set> violations = validator.validate(jobAspirant, Junior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelJunior_whenAllFieldsInValid_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", " John Adam", "2022-12-31", 3, false); + Set> violations = validator.validate(jobAspirant, Junior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(4); + violations.forEach(action -> { + String fieldName = action.getPropertyPath().toString(); + switch(fieldName) { + case "name": + assertThat(action.getMessage()).isEqualTo("Name should not start with space"); + break; + case "passportExpiryDate": + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Junior Level Job"); + break; + case "experience": + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 5 Years"); + break; + case "agreement": + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Junior Level Job"); + break; + } + }); + } + @Test + public void givenJobLevelSenior_whenAllFieldsInValid_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam ", "2022-12-31", 12, false); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(4); + violations.forEach(action -> { + String fieldName = action.getPropertyPath().toString(); + switch(fieldName) { + case "name": + assertThat(action.getMessage()).isEqualTo("Name should not end with space"); + break; + case "passportExpiryDate": + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Senior Level Job"); + break; + case "experience": + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 15 Years"); + break; + case "agreement": + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Senior Level Job"); + break; + } + }); + } + private JobAspirant getJobAspirant(String jobLevel, String name, String passportExpDate, int exp, boolean agmt) throws ParseException { + JobAspirant jobAspirant = new JobAspirant(); + jobAspirant.setName(name); + jobAspirant.setPassportExpiryDate(convertStringToDate(passportExpDate)); + jobAspirant.setJobLevel(jobLevel); + jobAspirant.setExperience(exp); + jobAspirant.setAgreement(agmt); + return jobAspirant; + } + private Date convertStringToDate(String date) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(date); + } +} diff --git a/javaxval/README.md b/javaxval/README.md index 7420580f8e..188c2e59d0 100644 --- a/javaxval/README.md +++ b/javaxval/README.md @@ -3,11 +3,11 @@ This module contains articles about Bean Validation. ### Relevant Articles: -- [Java Bean Validation Basics](https://www.baeldung.com/javax-validation) +- [Java Bean Validation Basics](https://www.baeldung.com/java-validation) - [Validating Container Elements with Jakarta Bean Validation 3.0](https://www.baeldung.com/bean-validation-container-elements) - [Validations for Enum Types](https://www.baeldung.com/javax-validations-enums) - [Javax BigDecimal Validation](https://www.baeldung.com/javax-bigdecimal-validation) -- [Grouping Javax Validation Constraints](https://www.baeldung.com/javax-validation-groups) +- [Grouping Jakarta (Javax) Validation Constraints](https://www.baeldung.com/javax-validation-groups) - [Constraint Composition with Bean Validation](https://www.baeldung.com/java-bean-validation-constraint-composition) - [Using @NotNull on a Method Parameter](https://www.baeldung.com/java-notnull-method-parameter) - [Difference Between @NotNull, @NotEmpty, and @NotBlank Constraints in Bean Validation](https://www.baeldung.com/java-bean-validation-not-null-empty-blank) diff --git a/jenkins-modules/plugins/pom.xml b/jenkins-modules/plugins/pom.xml index 42add1664e..c2b1408556 100644 --- a/jenkins-modules/plugins/pom.xml +++ b/jenkins-modules/plugins/pom.xml @@ -12,6 +12,7 @@ org.jenkins-ci.plugins plugin 2.33 + diff --git a/jersey/README.md b/jersey/README.md index 4c8c235be5..aa5a6a3b28 100644 --- a/jersey/README.md +++ b/jersey/README.md @@ -11,3 +11,4 @@ This module contains articles about Jersey. - [Explore Jersey Request Parameters](https://www.baeldung.com/jersey-request-parameters) - [Add a Header to a Jersey SSE Client Request](https://www.baeldung.com/jersey-sse-client-request-headers) - [Exception Handling With Jersey](https://www.baeldung.com/java-exception-handling-jersey) +- [@FormDataParam vs. @FormParam in Jersey](https://www.baeldung.com/jersey-formdataparam-vs-formparam) diff --git a/jersey/pom.xml b/jersey/pom.xml index 005fa85077..d279406e9a 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -76,6 +76,11 @@ jersey-apache-connector ${jersey.version} + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey.version} + @@ -100,7 +105,6 @@ 3.1.1 - 3.3.2 - \ No newline at end of file + diff --git a/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java new file mode 100644 index 0000000000..15e82679ef --- /dev/null +++ b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java @@ -0,0 +1,61 @@ +package com.baeldung.jersey.server.form; + +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +@Path("form") +public class FormExampleResource +{ + @GET + @Path("/example1") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample1() throws Exception + { + File f = new File("src/main/resources/html/example1.html"); + return new FileInputStream(f); + } + + @GET + @Path("/example2") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample2() throws Exception + { + File f = new File("src/main/resources/html/example2.html"); + return new FileInputStream(f); + } + + @POST + @Path("/example1") + public String example1(@FormParam("first_name") String firstName, + @FormParam("last_name") String lastName, + @FormParam("age") String age) + { + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age; + } + + @POST + @Path("/example2") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String example2(@FormDataParam("first_name") String firstName, + @FormDataParam("last_name") String lastName, + @FormDataParam("age") String age, + @FormDataParam("photo") InputStream photo) + throws Exception + { + int len; + int size = 1024; + byte[] buf; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + buf = new byte[size]; + while ((len = photo.read(buf, 0, size)) != -1) + bos.write(buf, 0, len); + buf = bos.toByteArray(); + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age + ", Photo (# of bytes) = " + buf.length; + } +} diff --git a/jersey/src/main/resources/formexamples/example1.html b/jersey/src/main/resources/formexamples/example1.html new file mode 100644 index 0000000000..6335dcce08 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example1.html @@ -0,0 +1,16 @@ + + + Example 1 using @FormParam + + +
+ + + + + + + +
+ + diff --git a/jersey/src/main/resources/formexamples/example2.html b/jersey/src/main/resources/formexamples/example2.html new file mode 100644 index 0000000000..4875c652a4 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example2.html @@ -0,0 +1,18 @@ + + + Example 2 using @FormDataParam + + +
+ + + + + + + + + +
+ + diff --git a/jhipster-6/README.md b/jhipster-6/README.md index 9db409a032..6ddf33e8cf 100644 --- a/jhipster-6/README.md +++ b/jhipster-6/README.md @@ -1,3 +1,3 @@ ## JHipster 6 -This module contains articles about JHipster 5. This is an aggregator module, articles are in the relevant submodules. +This module contains articles about JHipster 6. This is an aggregator module, articles are in the relevant submodules. diff --git a/jhipster-6/bookstore-monolith/pom.xml b/jhipster-6/bookstore-monolith/pom.xml index f719baab8b..a35abb9c19 100644 --- a/jhipster-6/bookstore-monolith/pom.xml +++ b/jhipster-6/bookstore-monolith/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.baeldung.jhipster6 bookstore-monolith 0.0.1-SNAPSHOT @@ -56,10 +55,6 @@ jaxb-runtime 4.0.0 - - - - com.fasterxml.jackson.datatype jackson-datatype-hibernate5 @@ -649,6 +644,76 @@
+ + default-jdk9-and-above + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + true + + + + npm install + + true + + + + webpack build dev + + true + + + + webpack build test + none + + + + + + + + integration-jdk9-and-above + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + true + + + + npm install + + true + + + + webpack build dev + + true + + + + webpack build test + none + + + + + + no-liquibase @@ -1098,7 +1163,7 @@ 3.1.0 - 3.8.0 + 3.11.0 2.10 3.0.0-M1 2.2.1 diff --git a/jmh/pom.xml b/jmh/pom.xml index e5e0f46044..e8a88bf301 100644 --- a/jmh/pom.xml +++ b/jmh/pom.xml @@ -83,10 +83,8 @@ - 3.3.0 0.17 3.5.0 - 3.11.0 \ No newline at end of file diff --git a/jsf/pom.xml b/jsf/pom.xml index 81030537fb..09dea98f65 100644 --- a/jsf/pom.xml +++ b/jsf/pom.xml @@ -76,8 +76,6 @@ 2.2.14 3.0.0 - - 3.3.1 1.3.1 diff --git a/json-modules/json-2/README.md b/json-modules/json-2/README.md index a29484d9fc..f41a7047fa 100644 --- a/json-modules/json-2/README.md +++ b/json-modules/json-2/README.md @@ -13,5 +13,6 @@ This module contains articles about JSON. - [Getting a Value in JSONObject](https://www.baeldung.com/java-jsonobject-get-value) - [Pretty-Print a JSON in Java](https://www.baeldung.com/java-json-pretty-print) - [Remove Whitespaces From a JSON in Java](https://www.baeldung.com/java-json-minify-remove-whitespaces) +- [Programmatic Generation of JSON Schemas in Java](https://www.baeldung.com/java-json-schema-create-automatically) - More Articles: [[<-- prev]](/json-modules/json) diff --git a/json-modules/json-2/pom.xml b/json-modules/json-2/pom.xml index 82fe689ebf..6cca576fb1 100644 --- a/json-modules/json-2/pom.xml +++ b/json-modules/json-2/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 json-2 0.0.1-SNAPSHOT @@ -123,6 +123,26 @@ javax.annotation-api 1.3.2 + + com.github.victools + jsonschema-generator + ${jsonschema-generator.version} + + + com.github.victools + jsonschema-module-jackson + ${jsonschema-generator.version} + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation.version} + + + com.github.victools + jsonschema-module-jakarta-validation + ${jsonschema-generator.version} +
@@ -162,17 +182,67 @@ + + + com.github.victools + jsonschema-maven-plugin + ${jsonschema-generator.version} + + + + generate + + + + + + com.baeldung.jsonschemageneration.plugin + + + com.baeldung.jsonschemageneration.plugin.Person + + DRAFT_2020_12 + src/main/resources/schemas + {1}/{0}.json + true + + PLAIN_JSON + + + + + SCHEMA_VERSION_INDICATOR + + + + Jackson + + + + + + JakartaValidation + + + + + + + + + 0.9.23 1.9.2 1.2.21 - 20211205 1.1.1 0.1.1 0.4.2 0.13.0 + 4.31.1 + 3.0.2 \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java new file mode 100644 index 0000000000..07e00bba0f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java @@ -0,0 +1,70 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AdvancedArticle { + private UUID id; + private String title; + + private String content; + + @AllowedTypes({ Timestamp.class, Date.class }) + private Object createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Object getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Object createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3fbf6bac6e --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java @@ -0,0 +1,39 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class AdvancedConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withInstanceAttributeOverride((node, field, context) -> node.put("readOnly", field.getDeclaredType().isInstanceOf(UUID.class))); + + configBuilder.forFields() + .withTargetTypeOverridesResolver(field -> Optional.ofNullable(field.getAnnotationConsideringFieldAndGetterIfSupported(AllowedTypes.class)) + .map(AllowedTypes::value) + .map(Stream::of) + .map(stream -> stream.map(subtype -> field.getContext().resolve(subtype))) + .map(stream -> stream.collect(Collectors.toList())) + .orElse(null)); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AdvancedArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java new file mode 100644 index 0000000000..9c2ae2780d --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface AllowedTypes { + Class[] value(); +} + diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3e1b556311 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java @@ -0,0 +1,44 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.baeldung.jsonschemageneration.recursive.Author; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class IndividualConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withRequiredCheck(field -> field.getAnnotationConsideringFieldAndGetter(Nullable.class) == null).withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null); + + configBuilder.forMethods().withRequiredCheck(method -> method.getAnnotationConsideringFieldAndGetter(NotNull.class) != null); + + configBuilder.forTypesInGeneral() + .withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == List.class ? Collections.EMPTY_LIST : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == Date.class ? Date.from(Instant.now()) : null) + .withEnumResolver(scope -> scope.getType().getErasedType().isEnum() ? Stream.of(scope.getType().getErasedType().getEnumConstants()).map(v -> ((Enum) v).name()).collect(Collectors.toList()) : null); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Author.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java new file mode 100644 index 0000000000..eda5015400 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jackson.JacksonModule; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.Option.EXTRA_OPEN_API_FORMAT_VALUES; +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jackson.JacksonOption.RESPECT_JSONPROPERTY_REQUIRED; + +public class JacksonModuleSchemaGenerator { + public static void main(String[] args) { + + JacksonModule module = new JacksonModule(RESPECT_JSONPROPERTY_REQUIRED); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module).with(EXTRA_OPEN_API_FORMAT_VALUES); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String surname; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @JsonIgnore + String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + + } + + static class Address { + + @JsonProperty() + String street; + + @JsonProperty(required = true) + String city; + + @JsonProperty(required = true) + String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java new file mode 100644 index 0000000000..ca19d35357 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java @@ -0,0 +1,63 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationModule; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.INCLUDE_PATTERN_EXPRESSIONS; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.NOT_NULLABLE_FIELD_IS_REQUIRED; + +public class JakartaValidationModuleSchemaGenerator { + public static void main(String[] args) { + + JakartaValidationModule module = new JakartaValidationModule(NOT_NULLABLE_FIELD_IS_REQUIRED, INCLUDE_PATTERN_EXPRESSIONS); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @NotNull UUID id; + + @NotNull String name; + + @NotNull @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull String surname; + + @NotNull Address address; + + @Null String fullName; + + @NotNull Date createdAt; + + @Size(max = 10) List friends; + + } + + static class Address { + + @Null String street; + + @NotNull String city; + + @NotNull String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java new file mode 100644 index 0000000000..f87dcd5981 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java @@ -0,0 +1,61 @@ +package com.baeldung.jsonschemageneration.plugin; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class Person { + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + + String surname; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @Null String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @Size(max = 10) + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + +} + +class Address { + + @Null + @JsonProperty + String street; + + @NotNull + @JsonProperty(required = true) + String city; + + @NotNull + @JsonProperty(required = true) + String country; +} \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java new file mode 100644 index 0000000000..a19afb3f6f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java @@ -0,0 +1,12 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.List; +import java.util.UUID; + +public class Author { + private UUID id; + private String name; + private String role; + + private List articles; +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java new file mode 100644 index 0000000000..3ab7464aaf --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AuthoredArticle { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + private Author author; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java new file mode 100644 index 0000000000..2047dac53f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.recursive; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class RecursiveSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AuthoredArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java new file mode 100644 index 0000000000..480dc2e425 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java @@ -0,0 +1,66 @@ +package com.baeldung.jsonschemageneration.simple; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class Article { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java new file mode 100644 index 0000000000..daea643b1b --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.simple; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class SimpleSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Article.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json new file mode 100644 index 0000000000..d52a527684 --- /dev/null +++ b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json @@ -0,0 +1,54 @@ +{ + "$defs" : { + "Address" : { + "type" : "object", + "properties" : { + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "street" : { + "type" : [ "string", "null" ] + } + }, + "required" : [ "city", "country" ], + "additionalProperties" : false + } + }, + "type" : "object", + "properties" : { + "address" : { + "$ref" : "#/$defs/Address" + }, + "createdAt" : { + "type" : "string", + "readOnly" : true + }, + "email" : { + "type" : "string", + "format" : "email", + "pattern" : "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b" + }, + "friends" : { + "maxItems" : 10, + "type" : "array", + "items" : { + "$ref" : "#" + } + }, + "id" : { + "type" : "string", + "readOnly" : true + }, + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + } + }, + "required" : [ "address", "email", "id", "name", "surname" ], + "additionalProperties" : false +} \ No newline at end of file diff --git a/json-modules/json-arrays/README.md b/json-modules/json-arrays/README.md new file mode 100644 index 0000000000..f119467046 --- /dev/null +++ b/json-modules/json-arrays/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How to Check if a Value Exists in a JSON Array for a Particular Key](https://www.baeldung.com/java-json-array-check-key-value-pair) diff --git a/json-modules/json-arrays/pom.xml b/json-modules/json-arrays/pom.xml new file mode 100644 index 0000000000..10c487fbda --- /dev/null +++ b/json-modules/json-arrays/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + org.baeldung + json-arrays + json-arrays + + + com.baeldung + json-modules + 1.0.0-SNAPSHOT + + + + + org.json + json + ${json.version} + + + com.google.code.gson + gson + ${gson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + javax.json.bind + javax.json.bind-api + ${jsonb-api.version} + + + + + 1.0 + 2.8.5 + 1.1.2 + 2.28.0 + + + diff --git a/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java new file mode 100644 index 0000000000..6e1cbb7ab0 --- /dev/null +++ b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.checkforkey; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Objects; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +public class CheckForKeyUnitTest { + + private final String exampleJson = "[{\"colour\":\"red\"},{\"colour\":\"blue\"},{\"colour\":\"green\"}]"; + + @Test + public void givenJsonArray_whenUsingJackson_thenDetectKeyInArray() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode tree = objectMapper.readTree(exampleJson); + + Stream s = StreamSupport.stream(tree.spliterator(), false); + boolean result = s.map(entry -> entry.get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.asText())); + assertTrue(result); + } + + @Test + public void givenJsonArray_whenUsingGson_thenDetectKeyInArray() { + Gson gson = new Gson(); + JsonArray parsed = gson.fromJson(exampleJson, JsonArray.class); + + Stream s = StreamSupport.stream(parsed.spliterator(), false); + boolean result = s.map(entry -> entry.getAsJsonObject() + .get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.getAsString())); + assertTrue(result); + } + +} diff --git a/json-modules/json-conversion/README.md b/json-modules/json-conversion/README.md index 86e8365c70..a0cf0f6246 100644 --- a/json-modules/json-conversion/README.md +++ b/json-modules/json-conversion/README.md @@ -4,3 +4,4 @@ This module contains articles about JSON Conversions ### Relevant Articles: - [Convert JSON Array to Java List](https://www.baeldung.com/java-convert-json-array-to-list) +- [Reading JSON Documents as Maps and Comparing Them](https://www.baeldung.com/java-json-maps-comparison) diff --git a/json-modules/json-conversion/pom.xml b/json-modules/json-conversion/pom.xml index 1af13cbbcb..638216f4c5 100644 --- a/json-modules/json-conversion/pom.xml +++ b/json-modules/json-conversion/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.baeldung json-conversion @@ -29,11 +29,16 @@ jackson-databind ${jackson.version} + + com.google.guava + guava + ${guava.version} +
- 20211205 2.10.1 + 32.1.2-jre diff --git a/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/FlattenUtils.java b/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/FlattenUtils.java new file mode 100644 index 0000000000..2fd49d99ad --- /dev/null +++ b/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/FlattenUtils.java @@ -0,0 +1,36 @@ +package com.baeldung.jsontomap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FlattenUtils { + public static Map flatten(Map map) { + return flatten(map, null); + } + + private static Map flatten(Map map, String prefix) { + Map flatMap = new HashMap<>(); + map.forEach((key, value) -> { + String newKey = prefix != null ? prefix + "." + key : key; + if (value instanceof Map) { + flatMap.putAll(flatten((Map) value, newKey)); + } else if (value instanceof List) { + // check for list of primitives + Object element = ((List) value).get(0); + if (element instanceof String || element instanceof Number || element instanceof Boolean) { + flatMap.put(newKey, value); + } else { + // check for list of objects + List> list = (List>) value; + for (int i = 0; i < list.size(); i++) { + flatMap.putAll(flatten(list.get(i), newKey + "[" + i + "]")); + } + } + } else { + flatMap.put(newKey, value); + } + }); + return flatMap; + } +} \ No newline at end of file diff --git a/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/JsonUtils.java b/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/JsonUtils.java new file mode 100644 index 0000000000..35339494fb --- /dev/null +++ b/json-modules/json-conversion/src/main/java/com/baeldung/jsontomap/JsonUtils.java @@ -0,0 +1,23 @@ +package com.baeldung.jsontomap; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Map; + +public class JsonUtils { + public static Map jsonFileToMap(String path) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(new File(path), new TypeReference>() {}); + } + + public static Map jsonFileToMapGson(String path) throws IOException { + Gson gson = new Gson(); + return gson.fromJson(new FileReader(path), new TypeToken>() {}.getType()); + } +} diff --git a/json-modules/json-conversion/src/test/java/com/baeldung/jsontomap/JSONComparisonUnitTest.java b/json-modules/json-conversion/src/test/java/com/baeldung/jsontomap/JSONComparisonUnitTest.java new file mode 100644 index 0000000000..908161c258 --- /dev/null +++ b/json-modules/json-conversion/src/test/java/com/baeldung/jsontomap/JSONComparisonUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.jsontomap; + +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JSONComparisonUnitTest { + + @Test + void givenTwoJsonFiles_whenCompared_thenTheyAreDifferent() throws IOException { + Map firstMap = JsonUtils.jsonFileToMap("src/test/resources/first.json"); + Map secondMap = JsonUtils.jsonFileToMap("src/test/resources/second.json"); + + MapDifference difference = Maps.difference(firstMap, secondMap); + difference.entriesDiffering().forEach((key, value) -> { + System.out.println(key + ": " + value.leftValue() + " - " + value.rightValue()); + }); + assertThat(difference.areEqual()).isFalse(); + } + + @Test + void givenTwoJsonFiles_whenFlattenedAndCompared_thenTheyAreDifferent() throws IOException { + Map firstFlatMap = FlattenUtils.flatten(JsonUtils.jsonFileToMap("src/test/resources/first.json")); + Map secondFlatMap = FlattenUtils.flatten(JsonUtils.jsonFileToMap("src/test/resources/second.json")); + + MapDifference difference = Maps.difference(firstFlatMap, secondFlatMap); + difference.entriesDiffering().forEach((key, value) -> { + System.out.println(key + ": " + value.leftValue() + " - " + value.rightValue()); + }); + assertThat(difference.areEqual()).isFalse(); + } +} diff --git a/json-modules/json-conversion/src/test/resources/first.json b/json-modules/json-conversion/src/test/resources/first.json new file mode 100644 index 0000000000..905859c59f --- /dev/null +++ b/json-modules/json-conversion/src/test/resources/first.json @@ -0,0 +1,22 @@ +{ + "name": "John", + "age": 30, + "cars": [ + "Ford", + "BMW" + ], + "address": { + "street": "Second Street", + "city": "New York" + }, + "children": [ + { + "name": "Sara", + "age": 5 + }, + { + "name": "Alex", + "age": 3 + } + ] +} \ No newline at end of file diff --git a/json-modules/json-conversion/src/test/resources/second.json b/json-modules/json-conversion/src/test/resources/second.json new file mode 100644 index 0000000000..503228519f --- /dev/null +++ b/json-modules/json-conversion/src/test/resources/second.json @@ -0,0 +1,22 @@ +{ + "name": "John", + "age": 30, + "cars": [ + "Ford", + "Audi" + ], + "address": { + "street": "Main Street", + "city": "New York" + }, + "children": [ + { + "name": "Peter", + "age": 5 + }, + { + "name": "Cathy", + "age": 10 + } + ] +} \ No newline at end of file diff --git a/json-modules/json/pom.xml b/json-modules/json/pom.xml index 8210f026e7..27c9262279 100644 --- a/json-modules/json/pom.xml +++ b/json-modules/json/pom.xml @@ -68,7 +68,6 @@ 1.0.72 1.0 1.0.1 - 20230227 2.8.5 1.1.2 2.28.0 diff --git a/json-modules/pom.xml b/json-modules/pom.xml index 82314e0edf..7ac6ba19ad 100644 --- a/json-modules/pom.xml +++ b/json-modules/pom.xml @@ -16,6 +16,7 @@ json json-2 + json-arrays json-conversion json-path gson @@ -33,4 +34,8 @@ + + 20230618 + + \ No newline at end of file diff --git a/jws/pom.xml b/jws/pom.xml index 2f01f90721..12aa76127c 100644 --- a/jws/pom.xml +++ b/jws/pom.xml @@ -61,8 +61,4 @@ - - 3.0.2 - - diff --git a/kubernetes-modules/README.md b/kubernetes-modules/README.md new file mode 100644 index 0000000000..cb52c12465 --- /dev/null +++ b/kubernetes-modules/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Guide to Eclipse JKube](https://www.baeldung.com/ops/eclipse-jkube) diff --git a/kubernetes-modules/jkube-demo/pom.xml b/kubernetes-modules/jkube-demo/pom.xml index 7bb662c4a3..6fedc0f24a 100644 --- a/kubernetes-modules/jkube-demo/pom.xml +++ b/kubernetes-modules/jkube-demo/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 com.baeldung diff --git a/kubernetes-modules/pom.xml b/kubernetes-modules/pom.xml index ffe9c42472..9bd623b4f4 100644 --- a/kubernetes-modules/pom.xml +++ b/kubernetes-modules/pom.xml @@ -17,6 +17,7 @@ k8s-intro k8s-admission-controller kubernetes-spring + k8s-java-heap-dump diff --git a/libraries-apache-commons-2/README.md b/libraries-apache-commons-2/README.md index 76105d6ea4..180c84b31c 100644 --- a/libraries-apache-commons-2/README.md +++ b/libraries-apache-commons-2/README.md @@ -4,4 +4,5 @@ This module contains articles about Apache Commons libraries. ### Relevant articles - [Extracting a Tar File in Java](https://www.baeldung.com/java-extract-tar-file) +- [Convert a String with Unicode Encoding to a String of Letters](https://www.baeldung.com/java-convert-string-unicode-encoding) - More articles: [[<--prev]](../libraries-apache-commons) diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml index d771aac9ab..ee9b51e6cc 100644 --- a/libraries-apache-commons-2/pom.xml +++ b/libraries-apache-commons-2/pom.xml @@ -28,12 +28,18 @@ commons-vfs2 ${commons-vfs2.version} + + org.apache.commons + commons-text + ${apache-commons-text.version} + 1.23.0 1.10.13 2.9.0 + 1.10.0 \ No newline at end of file diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java new file mode 100644 index 0000000000..c788f6ee61 --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java @@ -0,0 +1,29 @@ +package com.baeldung.commons.convertunicode; + +import org.apache.commons.text.StringEscapeUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UnicodeConverterUtil { + + public static String decodeWithApacheCommons(String input) { + return StringEscapeUtils.unescapeJava(input); + } + + public static String decodeWithPlainJava(String input) { + Pattern pattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); + Matcher matcher = pattern.matcher(input); + + StringBuilder decodedString = new StringBuilder(); + + while (matcher.find()) { + String unicodeSequence = matcher.group(); + char unicodeChar = (char) Integer.parseInt(unicodeSequence.substring(2), 16); + matcher.appendReplacement(decodedString, Character.toString(unicodeChar)); + } + + matcher.appendTail(decodedString); + return decodedString.toString(); + } +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java new file mode 100644 index 0000000000..f4a9bbcb77 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.commons.convertunicode; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UnicodeConverterUnitTest { + + @Test + public void whenInputHaveUnicodeSequences_ThenDecode() { + String encodedString = "\\u0048\\u0065\\u006C\\u006C\\u006F World"; + String expectedDecodedString = "Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveNoUnicodeSequences_ThenDoNothing() { + String inputString = "Hello World"; + assertEquals(inputString, UnicodeConverterUtil.decodeWithApacheCommons(inputString)); + assertEquals(inputString, UnicodeConverterUtil.decodeWithPlainJava(inputString)); + } + + @Test + public void whenInputHaveUnicodeSequencesInMiddle_ThenDecode() { + String encodedString = "This is a test \\u0069\\u006E the middle."; + String expectedDecodedString = "This is a test in the middle."; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveMultipleUnicodeSequences_ThenDecode() { + String encodedString = "Unicode: \\u0048\\u0065\\u006C\\u006C\\u006F \\u0057\\u006F\\u0072\\u006C\\u0064"; + String expectedDecodedString = "Unicode: Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } +} diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index e19067daa3..0d0ba2dc82 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -86,13 +86,11 @@ spring-web ${spring.version} - org.derive4j derive4j @@ -162,17 +160,6 @@ - - 1.16.1 @@ -181,7 +168,7 @@ 1.0.3 14.0.6.Final 5.3.25 - 4.0.0 + 0.1.0 1.1.0 3.0.0 2.8.4 diff --git a/libraries-data-2/src/main/java/com/baeldung/suanshu/SuanShuMath.java b/libraries-data-2/src/main/java/com/baeldung/suanshu/SuanShuMath.java index a5365871c6..faf254ee97 100644 --- a/libraries-data-2/src/main/java/com/baeldung/suanshu/SuanShuMath.java +++ b/libraries-data-2/src/main/java/com/baeldung/suanshu/SuanShuMath.java @@ -1,23 +1,22 @@ package com.baeldung.suanshu; -/* -import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.Matrix; -import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix; -import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.operation.Inverse; -import com.numericalmethod.suanshu.algebra.linear.vector.doubles.Vector; -import com.numericalmethod.suanshu.algebra.linear.vector.doubles.dense.DenseVector; +import com.numericalmethod.suanshu.matrix.doubles.Matrix; +import com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix; +import com.numericalmethod.suanshu.matrix.doubles.operation.Inverse; +import com.numericalmethod.suanshu.vector.doubles.Vector; +import com.numericalmethod.suanshu.vector.doubles.dense.DenseVector; import com.numericalmethod.suanshu.analysis.function.polynomial.Polynomial; import com.numericalmethod.suanshu.analysis.function.polynomial.root.PolyRoot; import com.numericalmethod.suanshu.analysis.function.polynomial.root.PolyRootSolver; import com.numericalmethod.suanshu.number.complex.Complex; -*/ + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; class SuanShuMath { -/** fixing in JAVA-24004 + private static final Logger log = LoggerFactory.getLogger(SuanShuMath.class); public static void main(String[] args) throws Exception { @@ -139,5 +138,5 @@ class SuanShuMath { List roots = solver.solve(p); log.info("Finding polynomial roots: {}", roots); } -*/ + } diff --git a/libraries-io/README.md b/libraries-io/README.md index 6cfe978d91..a9ca5df3d6 100644 --- a/libraries-io/README.md +++ b/libraries-io/README.md @@ -3,4 +3,4 @@ - [Transferring a File Through SFTP in Java](https://www.baeldung.com/java-file-sftp) - [How to Create Password-Protected Zip Files and Unzip Them in Java](https://www.baeldung.com/java-password-protected-zip-unzip) - +- [How to Create CSV File from POJO with Custom Column Headers and Positions](https://www.baeldung.com/java-create-csv-pojo-customize-columns) diff --git a/libraries-io/pom.xml b/libraries-io/pom.xml index e92f6e11e1..fa89ebeabe 100644 --- a/libraries-io/pom.xml +++ b/libraries-io/pom.xml @@ -5,6 +5,18 @@ 4.0.0 libraries-io libraries-io + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + com.baeldung @@ -34,6 +46,11 @@ zip4j ${zip4j.version} + + com.opencsv + opencsv + ${opencsv.version} + @@ -42,6 +59,10 @@ 0.27.0 2.4 2.9.0 + 5.7.1 + 17 + 17 + UTF-8 \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java new file mode 100644 index 0000000000..b84da6229b --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java @@ -0,0 +1,4 @@ +package com.baeldung.java.io.pojotocsv; + +public record Application(String id, String name, Integer age, String created_at) { +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java new file mode 100644 index 0000000000..a0cd158843 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java @@ -0,0 +1,8 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.CsvBindByName; +import com.opencsv.bean.CsvBindByPosition; + +public record ApplicationWithAnnotation(@CsvBindByName(column = "id", required = true) @CsvBindByPosition(position = 1) String id, @CsvBindByName(column = "name", required = true) @CsvBindByPosition(position = 0) String name, + @CsvBindByName(column = "age", required = true) @CsvBindByPosition(position = 2) Integer age, @CsvBindByName(column = "position", required = true) @CsvBindByPosition(position = 3) String created_at) { +} \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java new file mode 100644 index 0000000000..f66c16beda --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java @@ -0,0 +1,55 @@ +package com.baeldung.java.io.pojotocsv; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +import com.opencsv.CSVWriter; +import com.opencsv.bean.StatefulBeanToCsvBuilder; +import com.opencsv.exceptions.CsvDataTypeMismatchException; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class BeanToCsv { + + public void beanToCSVWithDefault(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withSeparator(',') + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application2.csv")) { + var mappingStrategy = new CustomHeaderStrategy(); + mappingStrategy.setType(Application.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomPositionStrategy(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application3.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderAndPositionStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application4.csv")) { + var mappingStrategy = new CustomColumnPositionStrategy(); + mappingStrategy.setType(ApplicationWithAnnotation.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java new file mode 100644 index 0000000000..204bf3f917 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java @@ -0,0 +1,12 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.ColumnPositionMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomColumnPositionStrategy extends ColumnPositionMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + super.generateHeader(bean); + return super.getColumnMapping(); + } +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java new file mode 100644 index 0000000000..8e81c8ec28 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java @@ -0,0 +1,16 @@ +package com.baeldung.java.io.pojotocsv; + +import java.util.Arrays; + +import com.opencsv.bean.HeaderColumnNameMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomHeaderStrategy extends HeaderColumnNameMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + String[] header = super.generateHeader(bean); + return Arrays.stream(header) + .map(String::toLowerCase) + .toArray(String[]::new); + } +} diff --git a/libraries-io/src/main/resources/application.csv b/libraries-io/src/main/resources/application.csv new file mode 100644 index 0000000000..d4040e18e1 --- /dev/null +++ b/libraries-io/src/main/resources/application.csv @@ -0,0 +1,4 @@ +AGE,CREATED_AT,ID,NAME +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application2.csv b/libraries-io/src/main/resources/application2.csv new file mode 100644 index 0000000000..92bbced703 --- /dev/null +++ b/libraries-io/src/main/resources/application2.csv @@ -0,0 +1,4 @@ +age,created_at,id,name +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application3.csv b/libraries-io/src/main/resources/application3.csv new file mode 100644 index 0000000000..165107b103 --- /dev/null +++ b/libraries-io/src/main/resources/application3.csv @@ -0,0 +1,3 @@ +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/main/resources/application4.csv b/libraries-io/src/main/resources/application4.csv new file mode 100644 index 0000000000..b7999ae227 --- /dev/null +++ b/libraries-io/src/main/resources/application4.csv @@ -0,0 +1,4 @@ +name,id,age,created_at +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java new file mode 100644 index 0000000000..50cd1b1e0e --- /dev/null +++ b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.java.io.pojotocsv; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BeanToCsvUnitTest { + + List applications = new ArrayList<>(); + List applicationsWithAnnotation = new ArrayList<>(); + + @BeforeEach + public void beforeEach() { + applications = List.of(new Application("123", "Sam", 34, "2023-08-11"), new Application("456", "Tam", 44, "2023-02-11"), new Application("890", "Jam", 54, "2023-03-11")); + + applicationsWithAnnotation = List.of(new ApplicationWithAnnotation("123", "Sam", 34, "2023-08-11"), new ApplicationWithAnnotation("456", "Tam", 44, "2023-02-11"), new ApplicationWithAnnotation("789", "Jam", 54, "2023-03-11")); + } + + @Test + public void givenApplicationPOJO_whenUsingDefaultStrategy_thenReceiveCSVFormatWithAscendingOrderOfField() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithDefault(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("AGE,CREATED_AT,ID,NAME"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJO_whenUsingCustomHeaderStrategy_thenReceiveCSVFormatWithCustomHeaders() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderStrategy(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application2.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("age,created_at,id,name"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomPositionStrategy_thenReceiveCSVFormatWithCustomPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application3.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(1)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(2)).isEqualTo("Jam,789,54,2023-03-11"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomHeaderPositionStrategy_thenReceiveCSVFormatWithCustomHeaderPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderAndPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application4.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("name,id,age,created_at"); + assertThat(content.get(1)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(2)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(3)).isEqualTo("Jam,789,54,2023-03-11"); + } + } +} diff --git a/libraries-llms/pom.xml b/libraries-llms/pom.xml new file mode 100644 index 0000000000..3d5ed6830e --- /dev/null +++ b/libraries-llms/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + libraries-llms + libraries-llms + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + + dev.langchain4j + langchain4j + ${langchain4j.version} + + + dev.langchain4j + langchain4j-embeddings + ${langchain4j.version} + + + dev.langchain4j + langchain4j-open-ai + ${langchain4j.version} + + + dev.langchain4j + langchain4j-embeddings-all-minilm-l6-v2 + ${langchain4j.version} + + + + + 0.23.0 + + + \ No newline at end of file diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/ChainWithDocumentLiveTest.java b/libraries-llms/src/test/java/com/baeldung/langchain/ChainWithDocumentLiveTest.java new file mode 100644 index 0000000000..39746ce810 --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/ChainWithDocumentLiveTest.java @@ -0,0 +1,65 @@ +package com.baeldung.langchain; + +import static dev.langchain4j.data.document.FileSystemDocumentLoader.loadDocument; +import static java.time.Duration.ofSeconds; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Paths; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.langchain4j.chain.ConversationalRetrievalChain; +import dev.langchain4j.data.document.Document; +import dev.langchain4j.data.document.splitter.DocumentSplitters; +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.input.PromptTemplate; +import dev.langchain4j.model.openai.OpenAiChatModel; +import dev.langchain4j.retriever.EmbeddingStoreRetriever; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; +import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; + +public class ChainWithDocumentLiveTest { + + private static final Logger logger = LoggerFactory.getLogger(ChainWithDocumentLiveTest.class); + + @Test + public void givenChainWithDocument_whenPrompted_thenValidResponse() { + EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); + + EmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); + + EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() + .documentSplitter(DocumentSplitters.recursive(500, 0)) + .embeddingModel(embeddingModel) + .embeddingStore(embeddingStore) + .build(); + + Document document = loadDocument(Paths.get("src/test/resources/example-files/simpson's_adventures.txt")); + ingestor.ingest(document); + + ChatLanguageModel chatModel = OpenAiChatModel.builder() + .apiKey(Constants.OPENAI_API_KEY) + .timeout(ofSeconds(60)) + .build(); + + ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder() + .chatLanguageModel(chatModel) + .retriever(EmbeddingStoreRetriever.from(embeddingStore, embeddingModel)) + .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) + .promptTemplate(PromptTemplate.from("Answer the following question to the best of your ability: {{question}}\n\nBase your answer on the following information:\n{{information}}")) + .build(); + + String answer = chain.execute("Who is Simpson?"); + + logger.info(answer); + assertNotNull(answer); + } + +} diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithDocumentLiveTest.java b/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithDocumentLiveTest.java new file mode 100644 index 0000000000..41540f4888 --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithDocumentLiveTest.java @@ -0,0 +1,81 @@ +package com.baeldung.langchain; + +import static dev.langchain4j.data.document.FileSystemDocumentLoader.loadDocument; +import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO; +import static java.time.Duration.ofSeconds; +import static java.util.stream.Collectors.joining; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.langchain4j.data.document.Document; +import dev.langchain4j.data.document.DocumentSplitter; +import dev.langchain4j.data.document.splitter.DocumentSplitters; +import dev.langchain4j.data.embedding.Embedding; +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.input.Prompt; +import dev.langchain4j.model.input.PromptTemplate; +import dev.langchain4j.model.openai.OpenAiChatModel; +import dev.langchain4j.model.openai.OpenAiTokenizer; +import dev.langchain4j.store.embedding.EmbeddingMatch; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; + +public class ChatWithDocumentLiveTest { + + private static final Logger logger = LoggerFactory.getLogger(ChatWithDocumentLiveTest.class); + + @Test + public void givenDocument_whenPrompted_thenValidResponse() { + Document document = loadDocument(Paths.get("src/test/resources/example-files/simpson's_adventures.txt")); + DocumentSplitter splitter = DocumentSplitters.recursive(100, 0, new OpenAiTokenizer(GPT_3_5_TURBO)); + List segments = splitter.split(document); + + EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); + List embeddings = embeddingModel.embedAll(segments) + .content(); + EmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); + embeddingStore.addAll(embeddings, segments); + + String question = "Who is Simpson?"; + Embedding questionEmbedding = embeddingModel.embed(question) + .content(); + int maxResults = 3; + double minScore = 0.7; + List> relevantEmbeddings = embeddingStore.findRelevant(questionEmbedding, maxResults, minScore); + + PromptTemplate promptTemplate = PromptTemplate.from("Answer the following question to the best of your ability:\n" + "\n" + "Question:\n" + "{{question}}\n" + "\n" + "Base your answer on the following information:\n" + "{{information}}"); + + String information = relevantEmbeddings.stream() + .map(match -> match.embedded() + .text()) + .collect(joining("\n\n")); + + Map variables = new HashMap<>(); + variables.put("question", question); + variables.put("information", information); + + Prompt prompt = promptTemplate.apply(variables); + ChatLanguageModel chatModel = OpenAiChatModel.builder() + .apiKey(Constants.OPENAI_API_KEY) + .timeout(ofSeconds(60)) + .build(); + AiMessage aiMessage = chatModel.generate(prompt.toUserMessage()) + .content(); + + logger.info(aiMessage.text()); + assertNotNull(aiMessage.text()); + } + +} diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithMemoryLiveTest.java b/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithMemoryLiveTest.java new file mode 100644 index 0000000000..3d265d3f3f --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/ChatWithMemoryLiveTest.java @@ -0,0 +1,43 @@ +package com.baeldung.langchain; + +import static dev.langchain4j.data.message.UserMessage.userMessage; +import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.memory.ChatMemory; +import dev.langchain4j.memory.chat.TokenWindowChatMemory; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import dev.langchain4j.model.openai.OpenAiTokenizer; + +public class ChatWithMemoryLiveTest { + + private static final Logger logger = LoggerFactory.getLogger(ChatWithMemoryLiveTest.class); + + @Test + public void givenMemory_whenPrompted_thenValidResponse() { + ChatLanguageModel model = OpenAiChatModel.withApiKey(Constants.OPENAI_API_KEY); + ChatMemory chatMemory = TokenWindowChatMemory.withMaxTokens(300, new OpenAiTokenizer(GPT_3_5_TURBO)); + + chatMemory.add(userMessage("Hello, my name is Kumar")); + AiMessage answer = model.generate(chatMemory.messages()) + .content(); + logger.info(answer.text()); + chatMemory.add(answer); + assertNotNull(answer.text()); + + chatMemory.add(userMessage("What is my name?")); + AiMessage answerWithName = model.generate(chatMemory.messages()) + .content(); + logger.info(answerWithName.text()); + chatMemory.add(answerWithName); + assertThat(answerWithName.text()).contains("Kumar"); + } + +} diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/Constants.java b/libraries-llms/src/test/java/com/baeldung/langchain/Constants.java new file mode 100644 index 0000000000..380415bf9c --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/Constants.java @@ -0,0 +1,12 @@ +package com.baeldung.langchain; + +public class Constants { + + /** + * A limited access key for access to OpenAI language models can be generated by first + * registering for free at (https://platform.openai.com/signup) and then by navigating + * to "Create new secret key" page at (https://platform.openai.com/account/api-keys). + */ + public static String OPENAI_API_KEY = ""; + +} diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/PromptTemplatesLiveTest.java b/libraries-llms/src/test/java/com/baeldung/langchain/PromptTemplatesLiveTest.java new file mode 100644 index 0000000000..cd2ea642ed --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/PromptTemplatesLiveTest.java @@ -0,0 +1,41 @@ +package com.baeldung.langchain; + +import static dev.langchain4j.model.openai.OpenAiModelName.GPT_3_5_TURBO; +import static org.junit.Assert.assertNotNull; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.input.Prompt; +import dev.langchain4j.model.input.PromptTemplate; +import dev.langchain4j.model.openai.OpenAiChatModel; + +public class PromptTemplatesLiveTest { + + private static final Logger logger = LoggerFactory.getLogger(PromptTemplatesLiveTest.class); + + @Test + public void givenPromptTemplate_whenSuppliedInput_thenValidResponse() { + PromptTemplate promptTemplate = PromptTemplate.from("Tell me a {{adjective}} joke about {{content}}.."); + Map variables = new HashMap<>(); + variables.put("adjective", "funny"); + variables.put("content", "humans"); + Prompt prompt = promptTemplate.apply(variables); + + ChatLanguageModel model = OpenAiChatModel.builder() + .apiKey(Constants.OPENAI_API_KEY) + .modelName(GPT_3_5_TURBO) + .temperature(0.3) + .build(); + + String response = model.generate(prompt.text()); + logger.info(response); + assertNotNull(response); + } + +} diff --git a/libraries-llms/src/test/java/com/baeldung/langchain/ServiceWithToolsLiveTest.java b/libraries-llms/src/test/java/com/baeldung/langchain/ServiceWithToolsLiveTest.java new file mode 100644 index 0000000000..7ebfcba4df --- /dev/null +++ b/libraries-llms/src/test/java/com/baeldung/langchain/ServiceWithToolsLiveTest.java @@ -0,0 +1,49 @@ +package com.baeldung.langchain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.langchain4j.agent.tool.Tool; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.model.openai.OpenAiChatModel; +import dev.langchain4j.service.AiServices; + +public class ServiceWithToolsLiveTest { + + private static final Logger logger = LoggerFactory.getLogger(ServiceWithToolsLiveTest.class); + + static class Calculator { + @Tool("Calculates the length of a string") + int stringLength(String s) { + return s.length(); + } + + @Tool("Calculates the sum of two numbers") + int add(int a, int b) { + return a + b; + } + } + + interface Assistant { + String chat(String userMessage); + } + + @Test + public void givenServiceWithTools_whenPrompted_thenValidResponse() { + Assistant assistant = AiServices.builder(Assistant.class) + .chatLanguageModel(OpenAiChatModel.withApiKey(Constants.OPENAI_API_KEY)) + .tools(new Calculator()) + .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) + .build(); + + String question = "What is the sum of the numbers of letters in the words \"language\" and \"model\"?"; + String answer = assistant.chat(question); + + logger.info(answer); + assertThat(answer).contains("13"); + } + +} diff --git a/libraries-llms/src/test/resources/example-files/simpson's_adventures.txt b/libraries-llms/src/test/resources/example-files/simpson's_adventures.txt new file mode 100644 index 0000000000..ae6de80be0 --- /dev/null +++ b/libraries-llms/src/test/resources/example-files/simpson's_adventures.txt @@ -0,0 +1,28 @@ +Once upon a time in the town of VeggieVille, there lived a cheerful carrot named Simpson. +Simpson was a radiant carrot, always beaming with joy and positivity. +His vibrant orange skin and lush green top were a sight to behold, but it was his infectious laughter and warm personality that really set him apart. + +Simpson had a diverse group of friends, each a vegetable with their own unique characteristics. +There was Bella the blushing beetroot, always ready with a riddle or two; Timmy the timid tomato, a gentle soul with a heart of gold; and Percy the prankster potato, whose jokes always brought a smile to everyone's faces. +Despite their differences, they shared a close bond, their friendship as robust as their natural goodness. + +Their lives were filled with delightful adventures, from playing hide-and-seek amidst the leafy lettuce to swimming in the dewy droplets that pooled on the cabbage leaves. +Their favorite place, though, was the sunlit corner of the vegetable patch, where they would bask in the warmth of the sun, share stories, and have hearty laughs. + +One day, a bunch of pesky caterpillars invaded VeggieVille. +The vegetables were terrified, fearing they would be nibbled to nothingness. +But Simpson, with his usual sunny disposition, had an idea. +He proposed they host a grand feast for the caterpillars, with the juiciest leaves from the outskirts of the town. +Simpson's optimism was contagious, and his friends eagerly joined in to prepare the feast. + +When the caterpillars arrived, they were pleasantly surprised. +They enjoyed the feast and were so impressed with the vegetables' hospitality that they promised not to trouble VeggieVille again. +In return, they agreed to help pollinate the flowers, contributing to a more lush and vibrant VeggieVille. + +Simpson's idea had saved the day, but he humbly attributed the success to their teamwork and friendship. +They celebrated their victory with a grand party, filled with laughter, dance, and merry games. +That night, under the twinkling stars, they made a pact to always stand by each other, come what may. + +From then on, the story of the happy carrot and his friends spread far and wide, a tale of friendship, unity, and positivity. +Simpson, Bella, Timmy, and Percy continued to live their joyful lives, their laughter echoing through VeggieVille. +And so, the tale of the happy carrot and his friends serves as a reminder that no matter the challenge, with optimism, teamwork, and a bit of creativity, anything is possible. \ No newline at end of file diff --git a/libraries-server-2/pom.xml b/libraries-server-2/pom.xml index cf5d016d9f..7377fa3fa9 100644 --- a/libraries-server-2/pom.xml +++ b/libraries-server-2/pom.xml @@ -73,7 +73,6 @@ 9.4.27.v20200227 8.1.11.v20170118 - 3.2.2 \ No newline at end of file diff --git a/libraries/pom.xml b/libraries/pom.xml index 2ab345c469..07a4853728 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -291,7 +291,6 @@ 2.3.0 3.29.2-GA 0.9.12 - 3.0.2 3.6 2.6 diff --git a/lightrun/api-service/.gitignore b/lightrun/lightrun-api-service/.gitignore similarity index 100% rename from lightrun/api-service/.gitignore rename to lightrun/lightrun-api-service/.gitignore diff --git a/lightrun/api-service/pom.xml b/lightrun/lightrun-api-service/pom.xml similarity index 94% rename from lightrun/api-service/pom.xml rename to lightrun/lightrun-api-service/pom.xml index f44ad07edb..b7ed5f951b 100644 --- a/lightrun/api-service/pom.xml +++ b/lightrun/lightrun-api-service/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - api-service + lightrun-api-service 0.0.1-SNAPSHOT - api-service + lightrun-api-service Aggregator Service for LightRun Article diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/ApiServiceApplication.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/ApiServiceApplication.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/ApiServiceApplication.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/ApiServiceApplication.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/RequestIdGenerator.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/RequestIdGenerator.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/RequestIdGenerator.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/RequestIdGenerator.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/RestTemplateConfig.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/RestTemplateConfig.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/RestTemplateConfig.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/RestTemplateConfig.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/WebConfig.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/WebConfig.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/WebConfig.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/WebConfig.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/TaskResponse.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/TaskResponse.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/TaskResponse.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/TaskResponse.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/TasksController.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/TasksController.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/TasksController.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/TasksController.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/UnknownTaskException.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/UnknownTaskException.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/UnknownTaskException.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/UnknownTaskException.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/UserResponse.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/UserResponse.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/http/UserResponse.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/http/UserResponse.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/Task.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/Task.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/Task.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/Task.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/TaskRepository.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/TaskRepository.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/TaskRepository.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/tasks/TaskRepository.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/users/User.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/users/User.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/users/User.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/users/User.java diff --git a/lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/users/UserRepository.java b/lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/users/UserRepository.java similarity index 100% rename from lightrun/api-service/src/main/java/com/baeldung/apiservice/adapters/users/UserRepository.java rename to lightrun/lightrun-api-service/src/main/java/com/baeldung/apiservice/adapters/users/UserRepository.java diff --git a/lightrun/api-service/src/main/resources/application.properties b/lightrun/lightrun-api-service/src/main/resources/application.properties similarity index 100% rename from lightrun/api-service/src/main/resources/application.properties rename to lightrun/lightrun-api-service/src/main/resources/application.properties diff --git a/lightrun/tasks-service/.gitignore b/lightrun/lightrun-tasks-service/.gitignore similarity index 100% rename from lightrun/tasks-service/.gitignore rename to lightrun/lightrun-tasks-service/.gitignore diff --git a/lightrun/tasks-service/pom.xml b/lightrun/lightrun-tasks-service/pom.xml similarity index 96% rename from lightrun/tasks-service/pom.xml rename to lightrun/lightrun-tasks-service/pom.xml index c3542b0089..2689a9794d 100644 --- a/lightrun/tasks-service/pom.xml +++ b/lightrun/lightrun-tasks-service/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - tasks-service + lightrun-tasks-service 0.0.1-SNAPSHOT - tasks-service + lightrun-tasks-service Tasks Service for LightRun Article diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/ArtemisConfig.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/ArtemisConfig.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/ArtemisConfig.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/ArtemisConfig.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/CreateTaskRequest.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/CreateTaskRequest.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/CreateTaskRequest.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/CreateTaskRequest.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/PatchTaskRequest.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/PatchTaskRequest.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/PatchTaskRequest.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/PatchTaskRequest.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TaskResponse.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TaskResponse.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TaskResponse.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TaskResponse.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TasksController.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TasksController.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TasksController.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/TasksController.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/http-client.env.json b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/http-client.env.json similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/http-client.env.json rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/http-client.env.json diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/tasks.http b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/tasks.http similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/tasks.http rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/http/tasks.http diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/jms/JmsConsumer.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/jms/JmsConsumer.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/jms/JmsConsumer.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/jms/JmsConsumer.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TaskRecord.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TaskRecord.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TaskRecord.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TaskRecord.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TasksRepository.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TasksRepository.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TasksRepository.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/adapters/repository/TasksRepository.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/DeletedUserService.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/DeletedUserService.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/DeletedUserService.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/DeletedUserService.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/UnknownTaskException.java b/lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/UnknownTaskException.java similarity index 100% rename from lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/UnknownTaskException.java rename to lightrun/lightrun-tasks-service/src/main/java/com/baeldung/tasksservice/service/UnknownTaskException.java diff --git a/lightrun/tasks-service/src/main/resources/application.properties b/lightrun/lightrun-tasks-service/src/main/resources/application.properties similarity index 100% rename from lightrun/tasks-service/src/main/resources/application.properties rename to lightrun/lightrun-tasks-service/src/main/resources/application.properties diff --git a/lightrun/tasks-service/src/main/resources/db/migration/V1_0_0__create-tasks-table.sql b/lightrun/lightrun-tasks-service/src/main/resources/db/migration/V1_0_0__create-tasks-table.sql similarity index 100% rename from lightrun/tasks-service/src/main/resources/db/migration/V1_0_0__create-tasks-table.sql rename to lightrun/lightrun-tasks-service/src/main/resources/db/migration/V1_0_0__create-tasks-table.sql diff --git a/lightrun/users-service/.gitignore b/lightrun/lightrun-users-service/.gitignore similarity index 100% rename from lightrun/users-service/.gitignore rename to lightrun/lightrun-users-service/.gitignore diff --git a/lightrun/users-service/README.md b/lightrun/lightrun-users-service/README.md similarity index 100% rename from lightrun/users-service/README.md rename to lightrun/lightrun-users-service/README.md diff --git a/lightrun/users-service/pom.xml b/lightrun/lightrun-users-service/pom.xml similarity index 95% rename from lightrun/users-service/pom.xml rename to lightrun/lightrun-users-service/pom.xml index 9560dcf23b..40594db725 100644 --- a/lightrun/users-service/pom.xml +++ b/lightrun/lightrun-users-service/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - users-service + lightrun-users-service 0.0.1-SNAPSHOT - users-service + lightrun-users-service Users Service for LightRun Article diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/JmsConfig.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/JmsConfig.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/JmsConfig.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/JmsConfig.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/UsersServiceApplication.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/UsersServiceApplication.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/UsersServiceApplication.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/UsersServiceApplication.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/CreateUserRequest.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/CreateUserRequest.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/CreateUserRequest.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/CreateUserRequest.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/PatchUserRequest.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/PatchUserRequest.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/PatchUserRequest.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/PatchUserRequest.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/UserResponse.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/UserResponse.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/UserResponse.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/UserResponse.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/UsersController.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/UsersController.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/UsersController.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/UsersController.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/http-client.env.json b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/http-client.env.json similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/http-client.env.json rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/http-client.env.json diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/users.http b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/users.http similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/http/users.http rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/http/users.http diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/jms/JmsSender.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/jms/JmsSender.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/jms/JmsSender.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/jms/JmsSender.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UserRecord.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UserRecord.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UserRecord.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UserRecord.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UsersRepository.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UsersRepository.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UsersRepository.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/adapters/repository/UsersRepository.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/service/UnknownUserException.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/service/UnknownUserException.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/service/UnknownUserException.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/service/UnknownUserException.java diff --git a/lightrun/users-service/src/main/java/com/baeldung/usersservice/service/UsersService.java b/lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/service/UsersService.java similarity index 100% rename from lightrun/users-service/src/main/java/com/baeldung/usersservice/service/UsersService.java rename to lightrun/lightrun-users-service/src/main/java/com/baeldung/usersservice/service/UsersService.java diff --git a/lightrun/users-service/src/main/resources/application.properties b/lightrun/lightrun-users-service/src/main/resources/application.properties similarity index 100% rename from lightrun/users-service/src/main/resources/application.properties rename to lightrun/lightrun-users-service/src/main/resources/application.properties diff --git a/lightrun/users-service/src/main/resources/db/migration/V1_0_0__create-users-table.sql b/lightrun/lightrun-users-service/src/main/resources/db/migration/V1_0_0__create-users-table.sql similarity index 100% rename from lightrun/users-service/src/main/resources/db/migration/V1_0_0__create-users-table.sql rename to lightrun/lightrun-users-service/src/main/resources/db/migration/V1_0_0__create-users-table.sql diff --git a/lightrun/pom.xml b/lightrun/pom.xml index 3fcec48cbd..78534922f6 100644 --- a/lightrun/pom.xml +++ b/lightrun/pom.xml @@ -18,9 +18,9 @@ - tasks-service - users-service - api-service + lightrun-tasks-service + lightrun-users-service + lightrun-api-service \ No newline at end of file diff --git a/linux-bash-modules/linux-bash-text/README.md b/linux-bash-modules/linux-bash-text/README.md index 5423ddf916..7d843af9ea 100644 --- a/linux-bash-modules/linux-bash-text/README.md +++ b/linux-bash-modules/linux-bash-text/README.md @@ -1,3 +1 @@ ### Relevant Articles: - -- [Linux Commands for Appending Multiple Lines to a File](https://www.baeldung.com/linux/appending-multiple-lines-to-file2) diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index a47d0ae89b..32ea358369 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -4,3 +4,4 @@ - [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders) - [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions) - [Log4j Warning: “No Appenders Could Be Found for Logger”](https://www.baeldung.com/log4j-no-appenders-found) +- [A Guide to Log4j and the log4j.properties File in Java](https://www.baeldung.com/java-log4j-properties-guide) diff --git a/logging-modules/log4j2/README.md b/logging-modules/log4j2/README.md index 87e92e0d48..fa7133ffdd 100644 --- a/logging-modules/log4j2/README.md +++ b/logging-modules/log4j2/README.md @@ -9,3 +9,4 @@ - [Log4j 2 Plugins](https://www.baeldung.com/log4j2-plugins) - [Printing Thread Info in Log File Using Log4j2](https://www.baeldung.com/log4j2-print-thread-info) - [Log4j2 – Logging to Both File and Console](https://www.baeldung.com/java-log4j2-file-and-console) +- [Log4j 2 Configuration Using a Properties File](https://www.baeldung.com/java-log4j2-config-with-prop-file) diff --git a/logging-modules/logback/pom.xml b/logging-modules/logback/pom.xml index cddc2e72ea..8df95c18bb 100644 --- a/logging-modules/logback/pom.xml +++ b/logging-modules/logback/pom.xml @@ -71,11 +71,11 @@ runtime - org.projectlombok - lombok - provided + org.projectlombok + lombok + provided ${lombok.version} - + diff --git a/logging-modules/logback/src/test/java/com/baeldung/logback/JSONLayoutIntegrationTest.java b/logging-modules/logback/src/test/java/com/baeldung/logback/JSONLayoutIntegrationTest.java index 06962c1ea1..f012769710 100644 --- a/logging-modules/logback/src/test/java/com/baeldung/logback/JSONLayoutIntegrationTest.java +++ b/logging-modules/logback/src/test/java/com/baeldung/logback/JSONLayoutIntegrationTest.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class JSONLayoutIntegrationTest { private static Logger logger; + private static Logger jsonlogger; private ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream(); private PrintStream ps = new PrintStream(consoleOutput); @@ -23,16 +24,24 @@ public class JSONLayoutIntegrationTest { public void setUp() { // Redirect console output to our stream System.setOut(ps); - logger = LoggerFactory.getLogger("jsonLogger"); } @Test - public void whenLogLayoutInJSON_thenOutputIsCorrectJSON() { + public void givenJsonLayout_whenLogInJSON_thenOutputIsCorrectJSON() { + logger = LoggerFactory.getLogger("jsonLogger"); logger.debug("Debug message"); String currentLog = consoleOutput.toString(); assertTrue(!currentLog.isEmpty() && isValidJSON(currentLog)); } + @Test + public void givenJsonEncoder_whenLogInJSON_thenOutputIsCorrectJSON() { + jsonlogger = LoggerFactory.getLogger("jsonEncoderLogger"); + jsonlogger.debug("Debug message"); + String currentLog = consoleOutput.toString(); + assertTrue(!currentLog.isEmpty() && isValidJSON(currentLog)); + } + public static boolean isValidJSON(String jsonInString) { try { final ObjectMapper mapper = new ObjectMapper(); diff --git a/logging-modules/logback/src/test/resources/logback-test.xml b/logging-modules/logback/src/test/resources/logback-test.xml index 89c0124738..24082a673d 100644 --- a/logging-modules/logback/src/test/resources/logback-test.xml +++ b/logging-modules/logback/src/test/resources/logback-test.xml @@ -19,10 +19,18 @@ + + + + + + + + diff --git a/lombok-modules/lombok-2/README.md b/lombok-modules/lombok-2/README.md index 6d3482d800..83fdb382ee 100644 --- a/lombok-modules/lombok-2/README.md +++ b/lombok-modules/lombok-2/README.md @@ -13,4 +13,5 @@ This module contains articles about Project Lombok. - [@StandardException Annotation in Lombok](https://www.baeldung.com/lombok-standardexception-annotation) - [Lombok EqualsAndHashCode Annotation](https://www.baeldung.com/java-lombok-equalsandhashcode) - [Lombok’s @RequiredArgsConstructor Annotation](https://www.baeldung.com/java-lombok-constructor-annotation) +- [Generate Models Using OpenAPI With Lombok Annotations](https://www.baeldung.com/java-openapi-lombok-create-models) - More articles: [[<-- prev]](../lombok) diff --git a/lombok-modules/lombok-2/pom.xml b/lombok-modules/lombok-2/pom.xml index 88fbaf530f..ea562ad896 100644 --- a/lombok-modules/lombok-2/pom.xml +++ b/lombok-modules/lombok-2/pom.xml @@ -25,10 +25,58 @@ jackson-databind ${jackson.version} + + com.google.code.gson + gson + ${gson.version} + + + javax.annotation + javax.annotation-api + ${javax.annotation} + + + io.swagger + swagger-annotations + ${swagger.annotation} + org.springframework.boot spring-boot-starter-web + + + + org.openapitools + openapi-generator-maven-plugin + ${openapi.version} + + + + generate + + + ${project.basedir}/src/main/resources/bookapi.yml + java + com.baeldung.openapi.model + + @lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor + + false + false + false + + + + + + + + 4.2.3 + 2.10.1 + 1.3.2 + 1.6.2 + \ No newline at end of file diff --git a/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java new file mode 100644 index 0000000000..2da2e74a40 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java @@ -0,0 +1,12 @@ +package com.baeldung.lombok.openapiandlombook; + +@lombok.Data +@lombok.NoArgsConstructor +@lombok.AllArgsConstructor +public class Book { + + private Long id; + private String name; + private String author; + +} diff --git a/lombok-modules/lombok-2/src/main/resources/bookapi.yml b/lombok-modules/lombok-2/src/main/resources/bookapi.yml new file mode 100644 index 0000000000..e9b63b2f85 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/resources/bookapi.yml @@ -0,0 +1,39 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Book Store + license: + name: MIT +paths: + /books: + get: + tags: + - book + summary: Get All Books + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Book' + + 404: + description: Book not found + content: { } +components: + schemas: + Book: + type: object + required: + - id + - name + - author + properties: + id: + type: integer + format: int64 + name: + type: string + author: + type: string diff --git a/lombok-modules/lombok/pom.xml b/lombok-modules/lombok/pom.xml index 6ba90f33b5..a04233bc2b 100644 --- a/lombok-modules/lombok/pom.xml +++ b/lombok-modules/lombok/pom.xml @@ -43,7 +43,6 @@ - edge-SNAPSHOT 1.0.0.Final 1.18.20.0 23.0.0 diff --git a/lombok-modules/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java b/lombok-modules/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java index d9184f605c..a03b262828 100644 --- a/lombok-modules/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java +++ b/lombok-modules/lombok/src/test/java/com/baeldung/lombok/builder/defaultvalue/BuilderWithDefaultValueUnitTest.java @@ -14,7 +14,7 @@ public class BuilderWithDefaultValueUnitTest { } @Test - public void givenBuilderWithDefaultValue_NoArgsWorksAlso() { + public void givenBuilderWithDefaultValue_ThanNoArgsWorksAlso() { Pojo build = new Pojo().toBuilder() .build(); Pojo pojo = new Pojo(); diff --git a/lombok-modules/pom.xml b/lombok-modules/pom.xml index 5100ed1790..46d91462fb 100644 --- a/lombok-modules/pom.xml +++ b/lombok-modules/pom.xml @@ -16,7 +16,7 @@ - + lombok lombok-2 diff --git a/mapstruct/README.md b/mapstruct/README.md index 790b4b1a93..dd2a3bddd8 100644 --- a/mapstruct/README.md +++ b/mapstruct/README.md @@ -11,3 +11,4 @@ This module contains articles about MapStruct. - [Mapping Collections with MapStruct](https://www.baeldung.com/java-mapstruct-mapping-collections) - [Use Mapper in Another Mapper with Mapstruct and Java](https://www.baeldung.com/java-mapstruct-nested-mapping) - [Throw Exception for Unexpected Input for Enum With MapStruct](https://www.baeldung.com/java-mapstruct-enum-unexpected-input-exception) +- [How to Use Conditional Mapping With MapStruct](https://www.baeldung.com/java-mapstruct-bean-types-conditional) diff --git a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java new file mode 100644 index 0000000000..1d7cacaead --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java @@ -0,0 +1,48 @@ +package com.baeldung.expression.dto; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class LicenseDto { + + private UUID id; + + private LocalDateTime startDate; + + private LocalDateTime endDate; + + private String licenseType; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public void setStartDate(LocalDateTime startDate) { + this.startDate = startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + + public String getLicenseType() { + return licenseType; + } + + public void setLicenseType(String licenseType) { + this.licenseType = licenseType; + } + +} diff --git a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java new file mode 100644 index 0000000000..0d8904e220 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java @@ -0,0 +1,53 @@ +package com.baeldung.expression.mapper; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.mapstruct.AfterMapping; +import org.mapstruct.Condition; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +@Mapper +public interface LicenseMapper { + + @Mapping(target = "startDate", expression = "java(mapStartDate(licenseDto))") + @Mapping(target = "endDate", ignore = true) + @Mapping(target = "active", constant = "true") + @Mapping(target = "renewalRequired", conditionExpression = "java(isEndDateInTwoWeeks(licenseDto))", source = ".") + License toLicense(LicenseDto licenseDto); + + @AfterMapping + default void afterMapping(LicenseDto licenseDto, @MappingTarget License license) { + OffsetDateTime endDate = licenseDto.getEndDate() != null ? licenseDto.getEndDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now() + .plusYears(1); + license.setEndDate(endDate); + } + + default OffsetDateTime mapStartDate(LicenseDto licenseDto) { + return licenseDto.getStartDate() != null ? licenseDto.getStartDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now(); + } + + default boolean isEndDateInTwoWeeks(LicenseDto licenseDto) { + return licenseDto.getEndDate() != null && Duration.between(licenseDto.getEndDate(), LocalDateTime.now()) + .toDays() <= 14; + } + + @Condition + default boolean mapsToExpectedLicenseType(String licenseType) { + try { + return licenseType != null && License.LicenseType.valueOf(licenseType) != null; + } catch (IllegalArgumentException e) { + return false; + } + } + +} \ No newline at end of file diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java new file mode 100644 index 0000000000..e36e278a57 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -0,0 +1,71 @@ +package com.baeldung.expression.model; + +import java.time.OffsetDateTime; +import java.util.UUID; + +public class License { + + private UUID id; + + private OffsetDateTime startDate; + + private OffsetDateTime endDate; + + private boolean active; + + private boolean renewalRequired; + + private LicenseType licenseType; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public OffsetDateTime getStartDate() { + return startDate; + } + + public void setStartDate(OffsetDateTime startDate) { + this.startDate = startDate; + } + + public OffsetDateTime getEndDate() { + return endDate; + } + + public void setEndDate(OffsetDateTime endDate) { + this.endDate = endDate; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public boolean isRenewalRequired() { + return renewalRequired; + } + + public void setRenewalRequired(boolean renewalRequired) { + this.renewalRequired = renewalRequired; + } + + public enum LicenseType { + INDIVIDUAL, FAMILY + } + + public LicenseType getLicenseType() { + return licenseType; + } + + public void setLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + } +} \ No newline at end of file diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java new file mode 100644 index 0000000000..d7521e81f5 --- /dev/null +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -0,0 +1,105 @@ +package com.baeldung.expression.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +class LicenseMapperUnitTest { + + LicenseMapper licenseMapper = Mappers.getMapper(LicenseMapper.class); + + @Test + void givenLicenseDtoWithStartDateAndWithoutEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultEndDate() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setStartDate(LocalDateTime.now()); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + } + + @Test + void givenLicenseDtoWithEndDateAndWithoutStartDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultStartDate() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setEndDate(LocalDateTime.now() + .plusYears(2)); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + } + + @Test + void givenLicenseDtoWithoutStartDateAndEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultDetails() { + LicenseDto licenseDto = new LicenseDto(); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + assertThat(license.isActive()).isTrue(); + assertThat(license.isRenewalRequired()).isFalse(); + } + + @Test + void givenLicenseDtoWithEndDateInTwoWeeks_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithRenewalRequiredSetToTrue() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setEndDate(LocalDateTime.now() + .plusDays(10)); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + assertThat(license.isRenewalRequired()).isTrue(); + } + + @Test + void givenLicenseDtoWithoutId_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithValidId() { + LicenseDto licenseDto = new LicenseDto(); + UUID id = UUID.randomUUID(); + licenseDto.setId(id); + licenseDto.setEndDate(LocalDateTime.now() + .plusDays(10)); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + assertThat(license.getId()).isSameAs(id); + } + + @Test + void givenLicenseDtoWithoutLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithInvalidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("invalid_license_type"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithValidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithMatchingLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("INDIVIDUAL"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNotNull(license.getLicenseType()); + assertThat(license.getLicenseType()).isEqualTo(License.LicenseType.INDIVIDUAL); + } + +} \ No newline at end of file diff --git a/maven-modules/compiler-plugin-java-9/pom.xml b/maven-modules/compiler-plugin-java-9/pom.xml index 1063ee2e8f..54ec811374 100644 --- a/maven-modules/compiler-plugin-java-9/pom.xml +++ b/maven-modules/compiler-plugin-java-9/pom.xml @@ -22,7 +22,7 @@ - 3.8.0 + 3.11.0 9 9 diff --git a/maven-modules/host-maven-repo-example/pom.xml b/maven-modules/host-maven-repo-example/pom.xml index d5f36713d0..3bb1d721a8 100644 --- a/maven-modules/host-maven-repo-example/pom.xml +++ b/maven-modules/host-maven-repo-example/pom.xml @@ -18,7 +18,7 @@ org.apache.maven.plugins maven-source-plugin - 3.1.0 + ${maven-source-plugin.version} attach-sources @@ -31,7 +31,7 @@ com.github.github site-maven-plugin - 0.12 + ${site-maven-plugin.version} Maven artifacts for ${project.version} true @@ -56,7 +56,7 @@ maven-deploy-plugin - 2.8.2 + ${maven-deploy-plugin.version} internal.repo::default::file://${project.build.directory}/mvn-artifact @@ -66,7 +66,7 @@ org.apache.maven.plugins maven-source-plugin - 3.1.0 + ${maven-source-plugin.version} attach-sources @@ -106,6 +106,10 @@ github 8 8 + 3.1.0 + 2.8.2 + 3.1.0 + 0.12 \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/README.md b/maven-modules/jacoco-coverage-aggregation/README.md new file mode 100644 index 0000000000..98c3748330 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Maven Multi-Module Project Coverage With Jacoco](https://www.baeldung.com/maven-jacoco-multi-module-project) diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-aggregate-report/pom.xml b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-aggregate-report/pom.xml new file mode 100644 index 0000000000..627a9f3206 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-aggregate-report/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + com.baeldung.jacoco-coverage-aggregation + jacoco-coverage-aggregate-report + jacoco-coverage-aggregate-report + pom + + + com.baeldung + jacoco-coverage-aggregation + 1.0 + + + + + com.baeldung.jacoco-coverage-aggregation + services + ${project.parent.version} + + + com.baeldung.jacoco-coverage-aggregation + controllers + ${project.parent.version} + + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + verify + + report-aggregate + + + + **/jacoco.exec + + + ${project.reporting.outputDirectory}/jacoco-aggregate + + + + + + + + + + 0.8.8 + + + \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/pom.xml b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/pom.xml new file mode 100644 index 0000000000..886e931224 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + com.baeldung.jacoco-coverage-aggregation + jacoco-coverage-controllers-example + jacoco-coverage-controllers-example + jar + + + com.baeldung + jacoco-coverage-aggregation + 1.0 + + + + + com.baeldung.jacoco-coverage-aggregation + services + ${project.parent.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + + integration-test + verify + + + + + + **/*IntegrationTest.java + + + + + + + + 3.0.9 + 3.1.2 + + + \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyApplication.java b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyApplication.java new file mode 100644 index 0000000000..03b8cb6b87 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.coverageaggregation; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MyApplication { + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } +} \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyController.java b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyController.java new file mode 100644 index 0000000000..59217a5b94 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/main/java/com/baeldung/coverageaggregation/MyController.java @@ -0,0 +1,30 @@ +package com.baeldung.coverageaggregation; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +class MyController { + + private final MyService myService; + + public MyController(MyService myService) { + this.myService = myService; + } + + @GetMapping("/tested") + String fullyTested() { + return myService.coveredByUnitAndIntegrationTests(); + } + + @GetMapping("/indirecttest") + String indirectlyTestingServiceMethod() { + return myService.coveredByIntegrationTest(); + } + + @GetMapping("/nottested") + String notTested() { + return myService.notTested(); + } + +} \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/test/java/com/baeldung/coverageaggregation/MyControllerIntegrationTest.java b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/test/java/com/baeldung/coverageaggregation/MyControllerIntegrationTest.java new file mode 100644 index 0000000000..3811f7e150 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-controllers-example/src/test/java/com/baeldung/coverageaggregation/MyControllerIntegrationTest.java @@ -0,0 +1,40 @@ +package com.baeldung.coverageaggregation; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@SpringBootTest(classes = MyApplication.class) +@AutoConfigureMockMvc +class MyControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void whenFullyTested_ThenCorrectText() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/tested")) + .andExpect(MockMvcResultMatchers.status() + .isOk()) + .andExpect(MockMvcResultMatchers.content() + .string("covered by unit and integration tests")); + } + + @Test + void whenIndirectlyTestingServiceMethod_ThenCorrectText() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/indirecttest")) + .andExpect(MockMvcResultMatchers.status() + .isOk()) + .andExpect(MockMvcResultMatchers.content() + .string("covered by integration test")); + } + +} diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/pom.xml b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/pom.xml new file mode 100644 index 0000000000..2c06694b46 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + com.baeldung.jacoco-coverage-aggregation + jacoco-coverage-services-example + jacoco-coverage-services-example + jar + + + com.baeldung + jacoco-coverage-aggregation + 1.0 + + + + + + org.springframework + spring-context + ${spring-context.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter-engine.version} + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + **/*Test.java + + + + + + + + 5.9.2 + 6.0.11 + + + \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/main/java/com/baeldung/coverageaggregation/MyService.java b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/main/java/com/baeldung/coverageaggregation/MyService.java new file mode 100644 index 0000000000..1c19b8d3cd --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/main/java/com/baeldung/coverageaggregation/MyService.java @@ -0,0 +1,25 @@ +package com.baeldung.coverageaggregation; + +import java.lang.String; +import org.springframework.stereotype.Service; + +@Service +class MyService { + + String unitTestedOnly() { + return "unit tested only"; + } + + String coveredByUnitAndIntegrationTests() { + return "covered by unit and integration tests"; + } + + String coveredByIntegrationTest() { + return "covered by integration test"; + } + + String notTested() { + return "not tested"; + } + +} \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/test/java/com/baeldung/coverageaggregation/MyServiceUnitTest.java b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/test/java/com/baeldung/coverageaggregation/MyServiceUnitTest.java new file mode 100644 index 0000000000..017de771bf --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/jacoco-coverage-services-example/src/test/java/com/baeldung/coverageaggregation/MyServiceUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.coverageaggregation; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MyServiceUnitTest { + + MyService myService = new MyService(); + + @Test + void whenUnitTestedOnly_thenCorrectText() { + assertEquals("unit tested only", myService.unitTestedOnly()); + } + + @Test + void whenTestedMethod_thenCorrectText() { + assertEquals("covered by unit and integration tests", myService.coveredByUnitAndIntegrationTests()); + } + +} \ No newline at end of file diff --git a/maven-modules/jacoco-coverage-aggregation/pom.xml b/maven-modules/jacoco-coverage-aggregation/pom.xml new file mode 100644 index 0000000000..70243973e8 --- /dev/null +++ b/maven-modules/jacoco-coverage-aggregation/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + com.baeldung + jacoco-coverage-aggregation + 1.0 + jacoco-coverage-aggregation + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + + jacoco-coverage-services-example + jacoco-coverage-controllers-example + jacoco-coverage-aggregate-report + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + + prepare-agent + + + + + + + + + 0.8.8 + + + \ No newline at end of file diff --git a/maven-modules/maven-build-optimization/.mvn/jvm.config.txt b/maven-modules/maven-build-optimization/.mvn/jvm.config.txt new file mode 100644 index 0000000000..37dd0076c2 --- /dev/null +++ b/maven-modules/maven-build-optimization/.mvn/jvm.config.txt @@ -0,0 +1 @@ +-XX:-TieredCompilation -XX:TieredStopAtLevel=1 \ No newline at end of file diff --git a/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html b/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html new file mode 100644 index 0000000000..807679bbf6 --- /dev/null +++ b/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html @@ -0,0 +1,2542 @@ + + + + + Maven Profiler Report + + + +
+

maven-build-optimization (21,91 s)

+

Run clean install on 2023/08/05 19:34:46 with parameters: {}

+ + +
+

maven-build-optimization (18,81 s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Plugin executionDuration
org.apache.maven.plugins:maven-pmd-plugin:3.19.0:pmd {execution: pmd}10,45 s
org.commonjava.maven.plugins:directory-maven-plugin:0.3.1:directory-of {execution: directories}2,108 s
org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file {execution: install-jar-lib}1,982 s
org.apache.maven.plugins:maven-clean-plugin:3.2.0:clean {execution: default-clean}541,7 ms
org.apache.maven.plugins:maven-install-plugin:2.5.2:install {execution: default-install}22,76 ms
org.apache.maven.plugins:maven-pmd-plugin:3.19.0:check {execution: default}9,651 ms
+
+ + + +
+

Artifact Downloading (168,3 s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArtifactDuration
org.codehaus.plexus:plexus-utils:jar:3.3.01,649 s
javax.inject:javax.inject:jar:11,646 s
org.codehaus.plexus:plexus-resources:jar:1.2.01,643 s
org.apache.maven.doxia:doxia-integration-tools:jar:1.11.11,640 s
org.eclipse.sisu:org.eclipse.sisu.inject:jar:0.3.51,636 s
javax.enterprise:cdi-api:jar:1.21,634 s
javax.annotation:javax.annotation-api:jar:1.21,632 s
org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.51,630 s
org.apache.maven:maven-plugin-api:jar:3.1.01,627 s
org.apache.maven.reporting:maven-reporting-impl:jar:3.2.01,623 s
org.apache.maven.reporting:maven-reporting-api:jar:3.1.11,620 s
commons-collections:commons-collections:jar:3.2.21,618 s
oro:oro:jar:2.0.81,616 s
dom4j:dom4j:jar:1.11,613 s
commons-logging:commons-logging:jar:1.11,611 s
commons-chain:commons-chain:jar:1.11,607 s
commons-digester:commons-digester:jar:1.81,604 s
commons-beanutils:commons-beanutils:jar:1.7.01,602 s
org.apache.velocity:velocity-tools:jar:2.01,600 s
commons-lang:commons-lang:jar:2.41,597 s
org.apache.velocity:velocity:jar:1.71,595 s
org.codehaus.plexus:plexus-velocity:jar:1.21,592 s
org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-301,589 s
org.codehaus.plexus:plexus-i18n:jar:1.0-beta-101,586 s
org.apache.maven.doxia:doxia-module-xhtml5:jar:1.11.11,583 s
org.apache.maven.doxia:doxia-module-xhtml:jar:1.11.11,578 s
org.apache.maven.doxia:doxia-skin-model:jar:1.11.11,572 s
org.apache.httpcomponents:httpcore:jar:4.4.141,569 s
org.apache.commons:commons-text:jar:1.31,566 s
org.apache.maven.doxia:doxia-core:jar:1.11.11,563 s
org.apache.maven.doxia:doxia-site-renderer:jar:1.11.11,560 s
org.apache.maven.doxia:doxia-decoration-model:jar:1.11.11,556 s
org.apache.maven.doxia:doxia-logging-api:jar:1.11.11,553 s
org.apache.maven.doxia:doxia-sink-api:jar:1.11.11,551 s
org.slf4j:jul-to-slf4j:jar:1.7.361,549 s
org.slf4j:slf4j-api:jar:1.7.361,546 s
net.sourceforge.pmd:pmd-jsp:jar:6.49.01,543 s
org.mozilla:rhino:jar:1.7.141,540 s
net.sourceforge.pmd:pmd-javascript:jar:6.49.01,537 s
net.sourceforge.pmd:pmd-java:jar:6.49.01,535 s
net.sourceforge.saxon:saxon:jar:dom:9.1.0.81,533 s
com.google.code.gson:gson:jar:2.8.91,530 s
org.ow2.asm:asm:jar:9.31,528 s
net.sourceforge.saxon:saxon:jar:9.1.0.81,524 s
com.beust:jcommander:jar:1.481,521 s
org.antlr:antlr4-runtime:jar:4.7.21,519 s
net.sourceforge.pmd:pmd-core:jar:6.49.01,516 s
org.apache.commons:commons-lang3:jar:3.12.01,513 s
commons-io:commons-io:jar:2.11.01,511 s
org.apache.maven.shared:maven-common-artifact-filters:jar:3.3.11,508 s
org.codehaus.plexus:plexus-component-annotations:jar:2.1.11,504 s
org.apache.maven:maven-artifact:jar:3.01,501 s
org.codehaus.plexus:plexus-classworlds:jar:2.2.31,498 s
org.sonatype.sisu:sisu-guice:jar:noaop:2.1.71,495 s
org.sonatype.sisu:sisu-inject-bean:jar:1.4.21,481 s
org.sonatype.sisu:sisu-inject-plexus:jar:1.4.21,472 s
org.sonatype.aether:aether-util:jar:1.71,468 s
org.sonatype.aether:aether-api:jar:1.71,465 s
org.sonatype.aether:aether-spi:jar:1.71,462 s
org.sonatype.aether:aether-impl:jar:1.71,459 s
org.apache.maven:maven-aether-provider:jar:3.01,455 s
org.apache.maven:maven-model-builder:jar:3.01,453 s
org.apache.maven:maven-repository-metadata:jar:3.01,450 s
org.apache.maven:maven-settings-builder:jar:3.01,447 s
org.apache.maven:maven-settings:jar:3.01,444 s
org.apache.maven:maven-model:jar:3.01,441 s
org.apache.maven:maven-core:jar:3.01,437 s
org.apache.maven.shared:maven-artifact-transfer:jar:0.13.11,434 s
org.apache.maven.surefire:surefire-logger-api:jar:2.22.21,110 s
org.objenesis:objenesis:jar:3.21,107 s
net.bytebuddy:byte-buddy-agent:jar:1.12.81,104 s
net.bytebuddy:byte-buddy:jar:1.12.81,102 s
org.mockito:mockito-core:jar:4.4.01,097 s
org.hamcrest:hamcrest-all:jar:1.31,094 s
org.hamcrest:hamcrest:jar:2.21,092 s
org.assertj:assertj-core:jar:3.21.01,090 s
org.hamcrest:hamcrest-core:jar:1.31,087 s
junit:junit:jar:4.13.21,081 s
org.junit.vintage:junit-vintage-engine:jar:5.9.21,072 s
org.junit.platform:junit-platform-commons:jar:1.9.21,053 s
org.opentest4j:opentest4j:jar:1.2.01,046 s
org.junit.jupiter:junit-jupiter-api:jar:5.9.21,043 s
org.junit.jupiter:junit-jupiter-params:jar:5.9.21,041 s
org.apiguardian:apiguardian-api:jar:1.1.21,037 s
org.junit.platform:junit-platform-engine:jar:1.9.21,034 s
org.junit.jupiter:junit-jupiter-engine:jar:5.9.21,030 s
org.slf4j:jcl-over-slf4j:jar:1.7.321,027 s
ch.qos.logback:logback-core:jar:1.2.71,025 s
ch.qos.logback:logback-classic:jar:1.2.71,021 s
org.slf4j:slf4j-api:jar:1.7.321,018 s
com.vackosar.gitflowincrementalbuilder:gitflow-incremental-builder:pom:3.12.2912,3 ms
com.jcraft:jsch.agentproxy.sshagent:jar:0.0.9714,0 ms
net.java.dev.jna:jna-platform:jar:4.1.0709,2 ms
net.java.dev.jna:jna:jar:4.1.0700,3 ms
com.jcraft:jsch.agentproxy.pageant:jar:0.0.9696,9 ms
com.jcraft:jsch.agentproxy.jsch:jar:0.0.9691,3 ms
com.jcraft:jsch.agentproxy.usocket-nc:jar:0.0.9687,5 ms
com.jcraft:jsch.agentproxy.usocket-jna:jar:0.0.9681,7 ms
com.jcraft:jsch.agentproxy.core:jar:0.0.9677,3 ms
com.jcraft:jsch.agentproxy.connector-factory:jar:0.0.9673,1 ms
com.jcraft:jzlib:jar:1.1.1669,0 ms
com.jcraft:jsch:jar:0.1.55665,4 ms
org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:jar:5.10.0.202012080955-r662,5 ms
com.googlecode.javaewah:JavaEWAH:jar:1.1.7659,3 ms
org.eclipse.jgit:org.eclipse.jgit:jar:5.10.0.202012080955-r656,1 ms
com.vackosar.gitflowincrementalbuilder:gitflow-incremental-builder:jar:3.12.2653,0 ms
org.apache.maven:maven-model:jar:3.0.3435,3 ms
org.apache.maven:maven-plugin-api:jar:3.0.3430,5 ms
org.sonatype.plexus:plexus-cipher:jar:1.4427,8 ms
org.sonatype.plexus:plexus-sec-dispatcher:jar:1.3424,9 ms
org.codehaus.plexus:plexus-component-annotations:jar:1.5.5421,3 ms
org.codehaus.plexus:plexus-classworlds:jar:2.4418,1 ms
org.codehaus.plexus:plexus-utils:jar:2.0.6414,4 ms
org.codehaus.plexus:plexus-interpolation:jar:1.14411,1 ms
org.sonatype.sisu:sisu-guice:jar:no_aop:2.9.4403,0 ms
org.sonatype.sisu:sisu-inject-bean:jar:2.1.1396,1 ms
org.sonatype.sisu:sisu-inject-plexus:jar:2.1.1392,9 ms
org.sonatype.aether:aether-util:jar:1.11388,1 ms
org.sonatype.aether:aether-api:jar:1.11385,0 ms
org.sonatype.aether:aether-impl:jar:1.11381,0 ms
org.sonatype.aether:aether-spi:jar:1.11377,5 ms
org.apache.maven:maven-aether-provider:jar:3.0.3374,7 ms
org.apache.maven:maven-model-builder:jar:3.0.3371,9 ms
org.apache.maven:maven-artifact:jar:3.0.3369,1 ms
org.apache.maven:maven-repository-metadata:jar:3.0.3365,9 ms
org.apache.maven:maven-settings-builder:jar:3.0.3361,7 ms
org.apache.maven:maven-settings:jar:3.0.3358,7 ms
org.apache.maven:maven-core:jar:3.0.3355,7 ms
org.codehaus.plexus:plexus-utils:jar:3.0.15320,8 ms
com.google.code.findbugs:jsr305:jar:2.0.1312,4 ms
org.apache.maven.shared:maven-shared-utils:jar:0.4309,8 ms
commons-codec:commons-codec:jar:1.6307,2 ms
org.apache.maven:maven-artifact:jar:2.2.1304,6 ms
backport-util-concurrent:backport-util-concurrent:jar:3.1302,0 ms
org.apache.maven:maven-repository-metadata:jar:2.2.1298,3 ms
org.apache.maven:maven-artifact-manager:jar:2.2.1294,0 ms
org.apache.maven:maven-model:jar:2.2.1291,5 ms
classworlds:classworlds:jar:1.1-alpha-2288,9 ms
junit:junit:jar:3.8.1286,4 ms
org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-9-stable-1282,9 ms
org.codehaus.plexus:plexus-interpolation:jar:1.11278,9 ms
org.apache.maven:maven-plugin-registry:jar:2.2.1276,5 ms
org.apache.maven:maven-profile:jar:2.2.1273,8 ms
org.apache.maven:maven-settings:jar:2.2.1271,4 ms
org.apache.maven:maven-project:jar:2.2.1268,8 ms
org.apache.maven:maven-plugin-api:jar:2.2.1265,4 ms
commons-io:commons-io:jar:2.6111,6 ms
org.apache.maven.shared:maven-shared-utils:jar:3.3.4109,0 ms
org.apache.velocity:velocity:pom:1.6.297,59 ms
commons-collections:commons-collections:pom:3.2.284,54 ms
org.apache:apache:pom:576,39 ms
org.eclipse.aether:aether-impl:pom:0.9.0.M277,00 ms
org.eclipse.sisu:org.eclipse.sisu.inject:pom:0.3.572,70 ms
org.eclipse.aether:aether-util:pom:0.9.0.M271,60 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-3070,94 ms
org.codehaus.plexus:plexus-utils:pom:2.0.669,83 ms
org.mozilla:rhino:pom:1.7.1468,12 ms
org.eclipse.jgit:org.eclipse.jgit-parent:pom:5.10.0.202012080955-r67,22 ms
org.codehaus.plexus:plexus:pom:2.0.767,22 ms
oro:oro:pom:2.0.866,76 ms
org.slf4j:slf4j-api:pom:1.7.3262,58 ms
commons-collections:commons-collections:pom:2.062,45 ms
org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:pom:5.10.0.202012080955-r61,11 ms
org.sonatype.aether:aether-impl:pom:1.1161,37 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-9-stable-161,22 ms
com.google.code.findbugs:jsr305:pom:2.0.160,24 ms
com.jcraft:jsch:pom:0.1.4959,02 ms
org.codehaus.plexus:plexus-classworlds:pom:1.2-alpha-958,04 ms
ch.qos.logback:logback-classic:pom:1.2.757,91 ms
org.sonatype.sisu:sisu-guice:pom:2.1.757,63 ms
commons-io:commons-io:pom:2.557,02 ms
commons-beanutils:commons-beanutils:pom:1.657,12 ms
javax.inject:javax.inject:pom:157,82 ms
com.jcraft:jzlib:pom:1.1.156,09 ms
org.jboss.weld:weld-parent:pom:2656,42 ms
org.apache.maven:maven:pom:2.2.155,59 ms
org.apache.maven:maven-project:pom:2.2.155,15 ms
org.slf4j:slf4j-parent:pom:1.7.3255,55 ms
ch.qos.logback:logback-core:pom:1.2.755,62 ms
org.junit.jupiter:junit-jupiter-params:pom:5.9.255,39 ms
org.apache.maven:maven-plugin-api:pom:3.055,91 ms
org.sonatype.oss:oss-parent:pom:355,16 ms
org.apache.maven:maven:pom:3.1.055,12 ms
org.apache:apache:pom:1453,84 ms
org.assertj:assertj-core:pom:3.21.053,16 ms
org.apache.maven.doxia:doxia-logging-api:pom:1.11.153,83 ms
commons-codec:commons-codec:pom:1.652,94 ms
org.apache:apache:pom:1352,42 ms
ch.qos.logback:logback-parent:pom:1.2.752,44 ms
net.sourceforge.pmd:pmd-javascript:pom:6.49.052,50 ms
org.apache.maven:maven-model:pom:3.1.052,30 ms
org.apache.maven:maven-settings:pom:3.1.052,33 ms
com.jcraft:jsch.agentproxy.core:pom:0.0.951,97 ms
org.apache.maven:maven-parent:pom:3551,64 ms
org.apache:apache:pom:651,83 ms
org.codehaus.plexus:plexus-utils:pom:3.3.051,78 ms
org.sonatype.aether:aether-api:pom:1.751,32 ms
org.apache.velocity:velocity:pom:1.751,33 ms
org.apache.maven.shared:maven-artifact-transfer:pom:0.13.150,31 ms
org.junit:junit-bom:pom:5.7.150,17 ms
org.apache.httpcomponents:httpcore:pom:4.4.1450,00 ms
xml-apis:xml-apis:pom:1.0.b250,17 ms
org.apache.maven.reporting:maven-reporting-impl:pom:3.2.050,00 ms
org.apache.maven:maven-core:pom:3.1.050,88 ms
org.apache.maven:maven-core:pom:3.0.348,45 ms
org.apache.maven:maven-parent:pom:3648,84 ms
org.apache.commons:commons-parent:pom:4748,48 ms
net.sourceforge.pmd:pmd-java:pom:6.49.048,23 ms
org.apache.maven.doxia:doxia-core:pom:1.11.148,46 ms
commons-chain:commons-chain:pom:1.148,33 ms
org.eclipse.jgit:org.eclipse.jgit:pom:5.10.0.202012080955-r47,77 ms
com.googlecode.javaewah:JavaEWAH:pom:1.1.747,41 ms
com.jcraft:jsch:pom:0.1.5547,14 ms
org.apache.maven.plugins:maven-clean-plugin:pom:3.2.047,30 ms
org.apache:apache:pom:2547,29 ms
org.apache.maven:maven-profile:pom:2.2.147,30 ms
org.apache.maven:maven-artifact:pom:3.047,23 ms
org.commonjava.maven.plugins:directory-maven-plugin:pom:0.3.146,74 ms
org.apache.maven.plugins:maven-pmd-plugin:jar:3.19.046,85 ms
org.sonatype.sisu:sisu-parent:pom:2.1.146,14 ms
org.apache.maven.doxia:doxia-site-renderer:pom:1.11.146,37 ms
org.apache.httpcomponents:httpcomponents-parent:pom:1146,78 ms
log4j:log4j:pom:1.2.1246,66 ms
commons-digester:commons-digester:pom:1.646,89 ms
org.sonatype.oss:oss-parent:pom:645,87 ms
org.apache.maven:maven-parent:pom:1545,51 ms
org.apache.maven.plugins:maven-install-plugin:pom:2.5.245,87 ms
org.apache.maven:maven-settings-builder:pom:3.0.345,01 ms
org.sonatype.sisu:sisu-inject-bean:pom:2.1.145,81 ms
org.hamcrest:hamcrest-core:pom:1.345,43 ms
org.hamcrest:hamcrest:pom:2.245,94 ms
net.bytebuddy:byte-buddy-agent:pom:1.12.845,38 ms
org.codehaus.plexus:plexus-classworlds:pom:2.2.345,57 ms
net.sourceforge.pmd:pmd:pom:6.49.045,12 ms
org.sonatype.oss:oss-parent:pom:945,17 ms
com.beust:jcommander:pom:1.4845,36 ms
org.apache.maven.doxia:doxia-skin-model:pom:1.11.145,26 ms
avalon-framework:avalon-framework:pom:4.1.345,37 ms
org.apache.commons:commons-parent:pom:4244,20 ms
org.apache.maven:maven-settings:pom:3.0.344,16 ms
org.apache.maven:maven-model:pom:2.2.144,03 ms
org.codehaus.plexus:plexus:pom:6.544,63 ms
org.apache.commons:commons-parent:pom:3944,23 ms
org.slf4j:slf4j-parent:pom:1.7.3644,75 ms
org.ow2.asm:asm:pom:9.344,39 ms
logkit:logkit:pom:1.0.144,09 ms
org.apache.maven.reporting:maven-reporting-api:pom:3.1.144,16 ms
org.apache.maven.shared:maven-shared-components:pom:1544,84 ms
com.jcraft:jsch.agentproxy:pom:0.0.943,31 ms
net.java.dev.jna:jna-platform:pom:4.1.043,11 ms
org.commonjava.maven.plugins:directory-maven-plugin:jar:0.3.143,95 ms
org.apache.maven.plugins:maven-install-plugin:jar:2.5.243,19 ms
org.apache.maven.shared:maven-shared-components:pom:3443,48 ms
org.sonatype.forge:forge-parent:pom:743,50 ms
org.apache.maven:maven-model-builder:pom:3.0.343,32 ms
org.codehaus.plexus:plexus-containers:pom:1.0.343,70 ms
org.junit.jupiter:junit-jupiter-engine:pom:5.9.243,63 ms
net.bytebuddy:byte-buddy-parent:pom:1.12.843,82 ms
org.apache:apache:pom:2143,91 ms
org.apache.httpcomponents:httpcomponents-core:pom:4.4.1443,69 ms
org.apache.maven.doxia:doxia-modules:pom:1.11.143,31 ms
org.codehaus.plexus:plexus-components:pom:1.1.1243,70 ms
commons-collections:commons-collections:pom:3.143,62 ms
org.apache.velocity:velocity-tools:pom:2.043,88 ms
commons-collections:commons-collections:pom:3.243,92 ms
org.eclipse.sisu:sisu-inject:pom:0.3.543,24 ms
org.apache.maven:maven-model-builder:pom:3.1.043,18 ms
org.apache.httpcomponents:httpclient:pom:4.5.1343,56 ms
org.apache.maven.doxia:doxia-integration-tools:pom:1.11.143,28 ms
org.sonatype.oss:oss-parent:pom:542,01 ms
org.apache.maven.plugins:maven-plugins:pom:3542,47 ms
org.apache.maven.plugins:maven-clean-plugin:jar:3.2.042,26 ms
org.apache.maven.plugins:maven-plugins:pom:3742,31 ms
commons-io:commons-io:pom:2.642,61 ms
org.sonatype.sisu.inject:guice-plexus:pom:2.1.142,22 ms
org.sonatype.aether:aether-util:pom:1.1142,96 ms
org.codehaus.plexus:plexus:pom:2.0.242,03 ms
org.apache.maven:maven-parent:pom:2342,40 ms
org.junit:junit-bom:pom:5.8.042,55 ms
org.objenesis:objenesis-parent:pom:3.242,08 ms
org.sonatype.sisu:sisu-inject-bean:pom:1.4.242,36 ms
org.apache.maven:maven-model-builder:pom:3.042,71 ms
org.codehaus.plexus:plexus-container-default:pom:2.1.042,77 ms
org.apache.commons:commons-text:pom:1.342,56 ms
org.apache.commons:commons-parent:pom:4542,72 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1642,98 ms
org.codehaus.plexus:plexus:pom:3.342,67 ms
com.jcraft:jsch.agentproxy.pageant:pom:0.0.941,70 ms
org.apache.maven.plugins:maven-plugins:pom:2541,58 ms
org.apache.maven.shared:maven-shared-utils:pom:3.3.441,60 ms
org.apache.maven:maven-model:pom:3.0.341,28 ms
org.sonatype.plexus:plexus-sec-dispatcher:pom:1.341,49 ms
org.sonatype.forge:forge-parent:pom:441,12 ms
org.codehaus.plexus:plexus:pom:3.3.141,32 ms
org.junit:junit-bom:pom:5.9.241,89 ms
org.hamcrest:hamcrest-all:pom:1.341,23 ms
org.apache.maven:maven-repository-metadata:pom:3.041,58 ms
org.ow2:ow2:pom:1.541,73 ms
org.apache.geronimo.genesis:genesis-default-flava:pom:2.041,83 ms
org.codehaus.plexus:plexus-i18n:pom:1.0-beta-1041,30 ms
org.apache.commons:commons-parent:pom:941,92 ms
commons-logging:commons-logging:pom:1.041,40 ms
dom4j:dom4j:pom:1.141,17 ms
javax.annotation:javax.annotation-api:pom:1.241,69 ms
org.codehaus.plexus:plexus:pom:3.0.141,86 ms
com.jcraft:jsch.agentproxy.connector-factory:pom:0.0.940,94 ms
com.jcraft:jsch.agentproxy.jsch:pom:0.0.940,90 ms
org.sonatype.sisu:sisu-inject-plexus:pom:2.1.140,48 ms
org.sonatype.aether:aether-parent:pom:1.1140,15 ms
classworlds:classworlds:pom:1.1-alpha-240,71 ms
org.apache.maven:maven-aether-provider:pom:3.040,45 ms
org.sonatype.aether:aether-spi:pom:1.740,35 ms
org.apache:apache:pom:1640,00 ms
org.junit:junit-bom:pom:5.7.240,99 ms
org.antlr:antlr4-master:pom:4.7.240,97 ms
org.apache.commons:commons-lang3:pom:3.8.140,64 ms
com.google.code.gson:gson-parent:pom:2.8.940,24 ms
org.apache.xbean:xbean-reflect:pom:3.740,35 ms
org.apache.geronimo.genesis:genesis-java5-flava:pom:2.040,09 ms
org.apache.maven.doxia:doxia-module-xhtml5:pom:1.11.140,48 ms
com.jcraft:jsch.agentproxy.sshagent:pom:0.0.939,63 ms
org.apache.maven:maven-parent:pom:2439,98 ms
org.apache.maven.plugins:maven-pmd-plugin:pom:3.19.039,32 ms
org.apache.maven:maven-parent:pom:3739,06 ms
org.apache:apache:pom:2339,62 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1439,03 ms
org.sonatype.sisu.inject:guice-bean:pom:2.1.139,53 ms
org.sonatype.sisu:sisu-inject:pom:2.1.139,26 ms
org.sonatype.sisu:sisu-guice:pom:2.9.439,61 ms
org.apache.maven:maven-settings:pom:2.2.139,79 ms
org.junit.platform:junit-platform-commons:pom:1.9.239,25 ms
org.apache.maven:maven:pom:3.039,95 ms
org.sonatype.sisu:sisu-parent:pom:1.4.239,06 ms
org.slf4j:slf4j-api:pom:1.7.3639,61 ms
commons-collections:commons-collections:pom:3.2.139,98 ms
org.apache.maven:maven-plugin-api:pom:3.1.039,75 ms
org.eclipse.sisu:org.eclipse.sisu.plexus:pom:0.3.539,14 ms
org.apache.httpcomponents:httpcore:pom:4.4.1339,01 ms
org.apache.maven.reporting:maven-reporting-api:pom:3.039,80 ms
org.apache.maven.doxia:doxia:pom:1.039,41 ms
org.codehaus.plexus:plexus-resources:pom:1.2.039,79 ms
net.java.dev.jna:jna:pom:4.1.038,09 ms
org.apache.maven:maven:pom:3.0.338,51 ms
org.apache:apache:pom:2738,99 ms
org.sonatype.plexus:plexus-cipher:pom:1.438,91 ms
org.apache.maven:maven-artifact:pom:3.0.338,26 ms
org.apache:apache:pom:938,99 ms
org.junit.jupiter:junit-jupiter-api:pom:5.9.238,90 ms
junit:junit:pom:4.13.238,54 ms
org.assertj:assertj-parent-pom:pom:2.2.1338,07 ms
org.apache.maven:maven-parent:pom:3338,50 ms
org.apache.maven:maven-model:pom:3.038,40 ms
org.codehaus.plexus:plexus-containers:pom:2.1.138,59 ms
org.codehaus.plexus:plexus:pom:2.0.638,25 ms
org.apache.maven.shared:maven-common-artifact-filters:pom:3.1.038,98 ms
org.apache.maven:maven-parent:pom:3038,45 ms
org.apache.commons:commons-parent:pom:5238,74 ms
org.apache.geronimo.genesis:genesis:pom:2.038,35 ms
org.codehaus.plexus:plexus:pom:1.0.1038,11 ms
commons-logging:commons-logging:pom:1.138,41 ms
javax.enterprise:cdi-api:pom:1.238,86 ms
org.eclipse.aether:aether-spi:pom:0.9.0.M238,01 ms
org.apache.httpcomponents:httpcomponents-client:pom:4.5.1338,87 ms
org.apache.commons:commons-parent:pom:3438,24 ms
org.apache.maven:maven-parent:pom:1038,57 ms
com.jcraft:jsch.agentproxy.usocket-jna:pom:0.0.937,73 ms
com.jcraft:jsch.agentproxy.usocket-nc:pom:0.0.937,70 ms
org.apache.maven:maven-parent:pom:3437,84 ms
org.apache.maven:maven-aether-provider:pom:3.0.337,14 ms
org.codehaus.plexus:plexus-utils:pom:1.5.1537,16 ms
org.apache.maven:maven-repository-metadata:pom:2.2.137,94 ms
org.apache.maven:maven-plugin-registry:pom:2.2.137,76 ms
org.hamcrest:hamcrest-parent:pom:1.337,16 ms
org.apache.maven.surefire:surefire:pom:2.22.237,51 ms
org.codehaus.plexus:plexus:pom:5.137,75 ms
org.codehaus.plexus:plexus-component-annotations:pom:2.1.137,62 ms
org.slf4j:slf4j-api:pom:1.7.537,15 ms
net.sourceforge.pmd:pmd-core:pom:6.49.037,11 ms
com.google.code.gson:gson:pom:2.8.937,75 ms
org.apache.maven.doxia:doxia-sink-api:pom:1.11.137,14 ms
org.codehaus.plexus:plexus-containers:pom:2.1.037,25 ms
org.apache.xbean:xbean:pom:3.737,25 ms
com.google:google:pom:137,52 ms
org.apache.maven.doxia:doxia-module-xhtml:pom:1.11.137,70 ms
org.codehaus.plexus:plexus-containers:pom:1.0-alpha-3037,07 ms
org.codehaus.plexus:plexus-components:pom:4.037,10 ms
org.eclipse.aether:aether:pom:0.9.0.M237,23 ms
org.apache:apache:pom:1836,22 ms
org.codehaus.plexus:plexus-components:pom:1.1.1836,26 ms
org.codehaus.plexus:plexus-component-annotations:pom:1.5.536,67 ms
org.apache.maven:maven-repository-metadata:pom:3.0.336,72 ms
org.codehaus.plexus:plexus-classworlds:pom:2.436,29 ms
org.sonatype.sisu.inject:guice-parent:pom:2.9.436,18 ms
org.sonatype.aether:aether-api:pom:1.1136,69 ms
org.sonatype.aether:aether-spi:pom:1.1136,84 ms
org.apache.maven:maven-plugin-api:pom:2.2.136,35 ms
org.apache.maven:maven-artifact-manager:pom:2.2.136,45 ms
org.apache.commons:commons-parent:pom:2236,60 ms
org.codehaus.plexus:plexus-utils:pom:3.0.1536,29 ms
org.junit.platform:junit-platform-engine:pom:1.9.236,04 ms
org.mockito:mockito-core:pom:4.4.036,15 ms
org.objenesis:objenesis:pom:3.236,89 ms
org.apache.maven:maven-settings:pom:3.036,73 ms
org.sonatype.sisu.inject:guice-plexus:pom:1.4.236,89 ms
org.apache.maven.shared:maven-shared-utils:pom:3.1.036,08 ms
org.apache.maven.shared:maven-common-artifact-filters:pom:3.3.136,16 ms
net.sourceforge.pmd:pmd-jsp:pom:6.49.036,48 ms
org.apache.maven.doxia:doxia:pom:1.11.136,98 ms
com.google.collections:google-collections:pom:1.036,84 ms
org.apache.maven:maven-repository-metadata:pom:3.1.036,82 ms
org.eclipse.sisu:sisu-plexus:pom:0.3.536,74 ms
net.java:jvnet-parent:pom:336,83 ms
org.codehaus.plexus:plexus-classworlds:pom:2.4.236,24 ms
org.apache.httpcomponents:httpcomponents-core:pom:4.4.1336,86 ms
org.apache:apache:pom:736,60 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-936,51 ms
org.sonatype.forge:forge-parent:pom:635,58 ms
org.apache.maven:maven-parent:pom:1135,64 ms
org.codehaus.plexus:plexus:pom:1.0.435,29 ms
org.codehaus.plexus:plexus-utils:pom:1.0.435,69 ms
backport-util-concurrent:backport-util-concurrent:pom:3.135,38 ms
org.apache.maven.shared:maven-shared-utils:pom:0.435,84 ms
org.slf4j:jcl-over-slf4j:pom:1.7.3235,15 ms
org.opentest4j:opentest4j:pom:1.2.035,58 ms
net.bytebuddy:byte-buddy:pom:1.12.835,52 ms
org.sonatype.sisu:sisu-inject-plexus:pom:1.4.235,46 ms
org.sonatype.sisu:sisu-inject:pom:1.4.235,22 ms
org.apache.maven.shared:maven-shared-components:pom:3635,28 ms
org.apache:apache:pom:2635,25 ms
org.apache.commons:commons-lang3:pom:3.12.035,54 ms
org.antlr:antlr4-runtime:pom:4.7.235,18 ms
net.sourceforge.saxon:saxon:pom:9.1.0.835,76 ms
org.apache:apache:pom:1935,50 ms
org.codehaus.plexus:plexus-classworlds:pom:2.6.035,71 ms
org.apache.maven.doxia:doxia-sitetools:pom:1.11.135,39 ms
commons-digester:commons-digester:pom:1.835,20 ms
commons-logging:commons-logging:pom:1.235,75 ms
commons-codec:commons-codec:pom:1.1135,24 ms
org.apache.maven:maven-parent:pom:1635,28 ms
org.sonatype.oss:oss-parent:pom:734,14 ms
org.codehaus.plexus:plexus-containers:pom:1.5.534,23 ms
org.codehaus.plexus:plexus-components:pom:1.1.1434,12 ms
junit:junit:pom:3.8.134,09 ms
org.apache.maven.shared:maven-shared-components:pom:1934,01 ms
org.sonatype.forge:forge-parent:pom:1034,20 ms
org.apiguardian:apiguardian-api:pom:1.1.234,54 ms
org.junit.vintage:junit-vintage-engine:pom:5.9.234,23 ms
org.apache.maven.surefire:surefire-logger-api:pom:2.22.234,84 ms
org.apache.maven:maven-core:pom:3.034,67 ms
org.sonatype.aether:aether-parent:pom:1.734,08 ms
org.sonatype.aether:aether-util:pom:1.734,82 ms
org.sonatype.aether:aether-impl:pom:1.734,32 ms
org.slf4j:slf4j-parent:pom:1.7.534,23 ms
commons-io:commons-io:pom:2.11.034,39 ms
org.slf4j:jul-to-slf4j:pom:1.7.3634,66 ms
org.apache.maven.doxia:doxia-decoration-model:pom:1.11.134,92 ms
org.codehaus.plexus:plexus:pom:1.0.1134,91 ms
org.codehaus.plexus:plexus-velocity:pom:1.234,82 ms
org.codehaus.plexus:plexus:pom:4.034,51 ms
org.apache:apache:pom:434,13 ms
commons-beanutils:commons-beanutils:pom:1.7.034,92 ms
org.apache.maven:maven-settings-builder:pom:3.1.034,20 ms
org.apache.maven:maven-artifact:pom:3.1.034,42 ms
org.codehaus.plexus:plexus-classworlds:pom:2.5.234,87 ms
org.eclipse.aether:aether-api:pom:0.9.0.M234,42 ms
org.codehaus.plexus:plexus-components:pom:6.634,12 ms
org.codehaus.plexus:plexus:pom:834,82 ms
org.sonatype.spice:spice-parent:pom:1233,99 ms
org.apache.maven:maven-plugin-api:pom:3.0.333,53 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1133,07 ms
org.apache.maven:maven-artifact:pom:2.2.133,82 ms
org.apache.maven:maven-settings-builder:pom:3.033,79 ms
org.apache.maven.shared:maven-shared-components:pom:3333,07 ms
org.apache.maven.shared:maven-shared-components:pom:3033,90 ms
org.apache.commons:commons-lang3:pom:3.733,77 ms
commons-lang:commons-lang:pom:2.433,27 ms
commons-logging:commons-logging:pom:1.0.333,41 ms
commons-collections:commons-collections:pom:2.133,89 ms
org.apache.maven:maven-aether-provider:pom:3.1.033,63 ms
org.sonatype.spice:spice-parent:pom:1732,83 ms
org.sonatype.sisu.inject:guice-bean:pom:1.4.232,52 ms
org.codehaus.plexus:plexus-components:pom:1.332,73 ms
org.apache.maven.doxia:doxia-sink-api:pom:1.032,06 ms
org.codehaus.plexus:plexus-interpolation:pom:1.2632,64 ms
+
+ +
+ +
+ + diff --git a/maven-modules/maven-build-optimization/README.md b/maven-modules/maven-build-optimization/README.md new file mode 100644 index 0000000000..c1764b67ac --- /dev/null +++ b/maven-modules/maven-build-optimization/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How to Speed Up Maven Build](https://www.baeldung.com/maven-fast-build) diff --git a/maven-modules/maven-build-optimization/pom.xml b/maven-modules/maven-build-optimization/pom.xml new file mode 100644 index 0000000000..86d3b2d34f --- /dev/null +++ b/maven-modules/maven-build-optimization/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + maven-build-optimization + 0.0.1-SNAPSHOT + maven-build-optimization + pom + + + com.baeldung + maven-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-profiler-plugin + ${maven-profiler-plugin.version} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + + integration-test + verify + + + + + + + + + + skipITs + + + + org.apache.maven.plugins + maven-failsafe-plugin + + true + + + + + + + + + 3.1.2 + 1.7 + + + \ No newline at end of file diff --git a/maven-modules/maven-builder-plugin/pom.xml b/maven-modules/maven-builder-plugin/pom.xml index f7d6a4e69b..338aafe85d 100644 --- a/maven-modules/maven-builder-plugin/pom.xml +++ b/maven-modules/maven-builder-plugin/pom.xml @@ -12,7 +12,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.2.0 + ${build-helper-maven-plugin.version} add-source @@ -32,6 +32,7 @@ + 3.2.0 1.8 1.8 UTF-8 diff --git a/maven-modules/maven-exec-plugin/pom.xml b/maven-modules/maven-exec-plugin/pom.xml index f0d4706455..1bac52ae2c 100644 --- a/maven-modules/maven-exec-plugin/pom.xml +++ b/maven-modules/maven-exec-plugin/pom.xml @@ -30,7 +30,7 @@ org.codehaus.mojo exec-maven-plugin - 3.0.0 + ${exec-maven-plugin.version} com.baeldung.main.Exec @@ -45,7 +45,8 @@ 1.2.6 - 3.8.1 + 3.11.0 + 3.1.0 1.8 diff --git a/maven-modules/maven-generate-war/pom.xml b/maven-modules/maven-generate-war/pom.xml index cf8952e72f..7de3f15298 100644 --- a/maven-modules/maven-generate-war/pom.xml +++ b/maven-modules/maven-generate-war/pom.xml @@ -43,7 +43,7 @@ maven-war-plugin - 3.3.1 + ${maven-war-plugin.version} @@ -72,7 +72,6 @@ 11 2.17.1 - 3.10.1 11 11 diff --git a/maven-modules/maven-integration-test/pom.xml b/maven-modules/maven-integration-test/pom.xml index 4483bb2d55..ae2eddb40f 100644 --- a/maven-modules/maven-integration-test/pom.xml +++ b/maven-modules/maven-integration-test/pom.xml @@ -76,7 +76,7 @@ maven-compiler-plugin - ${maven.compiler.version} + ${maven-compiler-plugin.version} ${java.version} ${java.version} @@ -103,7 +103,7 @@ maven-failsafe-plugin - ${maven.failsafe.version} + ${maven-failsafe-plugin.version} @@ -267,10 +267,10 @@ - 3.3.2 + 3.4.0 3.0.2 - 3.8.0 - 2.22.0 + 3.11.0 + 3.1.2 1.1 3.0.0 3.0.0 diff --git a/maven-modules/maven-multi-source/pom.xml b/maven-modules/maven-multi-source/pom.xml index d9863b31a9..96b390d75a 100644 --- a/maven-modules/maven-multi-source/pom.xml +++ b/maven-modules/maven-multi-source/pom.xml @@ -18,7 +18,7 @@ maven-compiler-plugin - ${maven.compiler.version} + ${maven-compiler-plugin.version} ${java.version} ${java.version} @@ -30,7 +30,7 @@ org.codehaus.mojo build-helper-maven-plugin - ${maven.build.helper.version} + ${build-helper-maven-plugin.version} generate-sources @@ -80,11 +80,9 @@ 3.0.2 - 3.8.0 - 2.22.0 1.1 3.0.0 - 3.0.0 + 3.0.0 9.4.11.v20180605 2.27 diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module1/pom.xml similarity index 83% rename from maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml rename to maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module1/pom.xml index 67e60fb386..94164b472c 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module1/pom.xml @@ -3,12 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - module1 + parent-pom-module1 pom com.baeldung.maven-parent-pom-resolution - aggregator + maven-parent-pom-aggregator 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/parent-pom-module3/pom.xml similarity index 86% rename from maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml rename to maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/parent-pom-module3/pom.xml index f4e3e81e7d..533157d621 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/parent-pom-module3/pom.xml @@ -3,12 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - module3 + parent-pom-module3 pom com.baeldung.maven-parent-pom-resolution - aggregator + maven-parent-pom-aggregator 1.0.0-SNAPSHOT diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/pom.xml similarity index 72% rename from maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml rename to maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/pom.xml index 9b36ef37fb..9cb4407125 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/parent-pom-module2/pom.xml @@ -3,19 +3,19 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - module2 + parent-pom-module2 pom com.baeldung.maven-parent-pom-resolution - module1 + parent-pom-module1 1.0.0-SNAPSHOT - ../module1/pom.xml + ../parent-pom-module1/pom.xml - module3 + parent-pom-module3 \ No newline at end of file diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/pom.xml similarity index 78% rename from maven-modules/maven-parent-pom-resolution/aggregator/pom.xml rename to maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/pom.xml index dde2c46370..8e3a922e76 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/maven-parent-pom-aggregator/pom.xml @@ -4,19 +4,18 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.maven-parent-pom-resolution - aggregator + maven-parent-pom-aggregator pom com.baeldung maven-parent-pom-resolution 1.0.0-SNAPSHOT - - module1 - module2 + parent-pom-module1 + parent-pom-module2 \ No newline at end of file diff --git a/maven-modules/maven-parent-pom-resolution/pom.xml b/maven-modules/maven-parent-pom-resolution/pom.xml index 8506f1c5fa..fa3ca3dc9a 100644 --- a/maven-modules/maven-parent-pom-resolution/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/pom.xml @@ -9,7 +9,7 @@ pom - aggregator + maven-parent-pom-aggregator disable-plugin-examples @@ -20,10 +20,13 @@ org.apache.maven.plugins maven-dependency-plugin - 3.2.0 + ${maven-dependency-plugin.version} + + 3.2.0 + \ No newline at end of file diff --git a/maven-modules/maven-simple/parent-project/webapp/pom.xml b/maven-modules/maven-simple/parent-project/webapp/pom.xml index ce964c222f..d0596a4503 100644 --- a/maven-modules/maven-simple/parent-project/webapp/pom.xml +++ b/maven-modules/maven-simple/parent-project/webapp/pom.xml @@ -26,8 +26,4 @@ - - 3.3.2 - - \ No newline at end of file diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml index f7bba3a8ff..913421d496 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -19,7 +19,9 @@ compiler-plugin-java-9 dependency-exclusion host-maven-repo-example + jacoco-coverage-aggregation maven-archetype + maven-build-optimization maven-builder-plugin maven-classifier maven-copy-files @@ -45,6 +47,9 @@ version-collision version-overriding-plugins versions-maven-plugin + maven-pom-types + multimodulemavenproject + resume-from diff --git a/maven-modules/resume-from/business/pom.xml b/maven-modules/resume-from/business/pom.xml index 189be12a0f..6c5db6cbe1 100644 --- a/maven-modules/resume-from/business/pom.xml +++ b/maven-modules/resume-from/business/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 business 1.0-SNAPSHOT @@ -24,5 +24,4 @@ 11 - \ No newline at end of file diff --git a/maven-modules/resume-from/pom.xml b/maven-modules/resume-from/pom.xml index 972395cbf2..d653d00d3b 100644 --- a/maven-modules/resume-from/pom.xml +++ b/maven-modules/resume-from/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung resume-from diff --git a/maven-modules/version-overriding-plugins/pom.xml b/maven-modules/version-overriding-plugins/pom.xml index b98a444bd4..d38541d797 100644 --- a/maven-modules/version-overriding-plugins/pom.xml +++ b/maven-modules/version-overriding-plugins/pom.xml @@ -51,7 +51,7 @@ - 3.8.0 + 3.11.0 \ No newline at end of file diff --git a/messaging-modules/apache-camel/pom.xml b/messaging-modules/apache-camel/pom.xml index bb20f178aa..8b49ad4893 100644 --- a/messaging-modules/apache-camel/pom.xml +++ b/messaging-modules/apache-camel/pom.xml @@ -17,30 +17,39 @@ - org.apache.camel - camel-core - ${env.camel.version} + org.apache.camel.springboot + camel-spring-boot-starter + ${camel.version} + + + org.apache.camel.springboot + camel-jackson-starter + ${camel.version} org.apache.camel - camel-spring-javaconfig - ${env.camel.version} + camel-test-spring-junit5 + ${camel.version} + test - org.apache.camel - camel-jackson - ${env.camel.version} + org.junit.platform + junit-platform-launcher + test - org.apache.camel - camel-test - ${env.camel.version} + org.springframework.boot + spring-boot-starter-web + + + org.awaitility + awaitility test - 3.14.7 + 3.21.0 \ No newline at end of file diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java new file mode 100755 index 0000000000..51b2540aa8 --- /dev/null +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.camel.apache; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index ce4d92e8ab..a0571e7083 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -5,14 +5,17 @@ import java.util.Date; import org.apache.camel.Exchange; import org.apache.camel.Processor; +import org.springframework.stereotype.Component; +@Component public class FileProcessor implements Processor { + @Override public void process(Exchange exchange) throws Exception { String originalFileName = (String) exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); Date date = new Date(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String changedFileName = dateFormat.format(date) + originalFileName; exchange.getIn().setHeader(Exchange.FILE_NAME, changedFileName); } diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java index 760f37677b..b57232d41e 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java @@ -1,7 +1,9 @@ package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; +@Component public class FileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; diff --git a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml index f306574868..f6177c69b5 100644 --- a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml +++ b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml @@ -1,11 +1,12 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> - - + + diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index bc0025b263..ab5993d816 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -1,31 +1,65 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.ListJacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.test.annotation.DirtiesContext; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.ListJacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; +@CamelSpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@SpringBootTest(classes = {Application.class, FruitArrayJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitArrayJacksonUnmarshalUnitTest { -public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitArray_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(List.class); String json = readJsonFromFile("/json/fruit-array.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); @SuppressWarnings("unchecked") List fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(List.class); @@ -41,22 +75,10 @@ public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit name", "Apple", fruit.getName()); assertEquals("Fruit id", 101, fruit.getId()); } - - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - - from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) - .to("mock:marshalledObject"); - } - }; - } private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitArrayJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index 2d15ebf46b..8120eeffec 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -1,32 +1,64 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import com.baeldung.camel.apache.jackson.FruitList; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.JacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.JacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; -import com.baeldung.camel.apache.jackson.FruitList; +@CamelSpringBootTest +@SpringBootTest(classes = {Application.class, FruitListJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitListJacksonUnmarshalUnitTest { -public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitList_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(FruitList.class); String json = readJsonFromFile("/json/fruit-list.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); FruitList fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(FruitList.class); assertNotNull("Fruit lists should not be null", fruitList); @@ -43,20 +75,9 @@ public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit id", 101, fruit.getId()); } - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) - .to("mock:marshalledObject"); - } - }; - } - private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitListJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index e4390a95e5..5003021d20 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -1,16 +1,21 @@ package com.apache.camel.file.processor; -import java.io.File; - +import com.baeldung.camel.apache.file.FileProcessor; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; +import org.awaitility.Awaitility; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.baeldung.camel.apache.file.FileProcessor; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class FileProcessorIntegrationTest { @@ -52,7 +57,7 @@ public class FileProcessorIntegrationTest { } @Test - public void moveFolderContentJavaDSLTest() throws Exception { + public void givenJavaDSLRoute_whenCamelStart_thenMoveFolderContent() throws Exception { final CamelContext camelContext = new DefaultCamelContext(); camelContext.addRoutes(new RouteBuilder() { @Override @@ -61,15 +66,26 @@ public class FileProcessorIntegrationTest { } }); camelContext.start(); - Thread.sleep(DURATION_MILIS); + verifyFolderContent(); camelContext.stop(); } @Test - public void moveFolderContentSpringDSLTest() throws InterruptedException { + public void givenSpringDSLRoute_whenCamelStart_thenMoveFolderContent() throws InterruptedException { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); - Thread.sleep(DURATION_MILIS); + verifyFolderContent(); applicationContext.close(); + } + private void verifyFolderContent() { + Date date = new Date(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + File destinationFile1 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File1.txt"); + File destinationFile2 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File2.txt"); + + Awaitility.await().atMost(DURATION_MILIS, TimeUnit.MILLISECONDS).untilAsserted(() -> { + assertThat(destinationFile1.exists()).isTrue(); + assertThat(destinationFile2.exists()).isTrue(); + }); } } \ No newline at end of file diff --git a/messaging-modules/pom.xml b/messaging-modules/pom.xml index 6fd14f7c64..27524637ab 100644 --- a/messaging-modules/pom.xml +++ b/messaging-modules/pom.xml @@ -22,7 +22,7 @@ spring-amqp spring-apache-camel spring-jms - postgres-notify + postgres-notify \ No newline at end of file diff --git a/messaging-modules/postgres-notify/pom.xml b/messaging-modules/postgres-notify/pom.xml index 174d66b7f5..876519f40c 100644 --- a/messaging-modules/postgres-notify/pom.xml +++ b/messaging-modules/postgres-notify/pom.xml @@ -42,37 +42,36 @@ lombok true - + + + 1.8 + + + + + org.springframework.boot + spring-boot-maven-plugin + + + - - 1.8 - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - instance1 - - - - org.springframework.boot - spring-boot-maven-plugin - - -Dserver.port=8081 - - - - - - - + + + instance1 + + + + org.springframework.boot + spring-boot-maven-plugin + + -Dserver.port=8081 + + + + + + + \ No newline at end of file diff --git a/microservices-modules/micronaut/README.md b/microservices-modules/micronaut/README.md index 1ab31d0c0c..f784f8ad70 100644 --- a/microservices-modules/micronaut/README.md +++ b/microservices-modules/micronaut/README.md @@ -5,3 +5,4 @@ This module contains articles about Micronaut. ### Relevant Articles: - [Introduction to Micronaut Framework](https://www.baeldung.com/micronaut) - [Micronaut vs. Spring Boot](https://www.baeldung.com/micronaut-vs-spring-boot) +- [API Versioning in Micronaut](https://www.baeldung.com/java-api-versioning-micronaut) diff --git a/microservices-modules/micronaut/pom.xml b/microservices-modules/micronaut/pom.xml index 716b5497d8..d3f4326a85 100644 --- a/microservices-modules/micronaut/pom.xml +++ b/microservices-modules/micronaut/pom.xml @@ -7,6 +7,7 @@ micronaut 0.1 micronaut + ${packaging} com.baeldung @@ -18,7 +19,7 @@ io.micronaut - bom + micronaut-bom ${micronaut.version} pom import @@ -29,120 +30,136 @@ io.micronaut - http-client + micronaut-runtime + compile + + + io.micronaut + micronaut-jackson-databind + + + + + io.micronaut + micronaut-http-client compile io.micronaut - http-server-netty + micronaut-http-server-netty + compile + + + jakarta.annotation + jakarta.annotation-api compile io.micronaut - inject + micronaut-inject compile io.micronaut - runtime + micronaut-validation compile - - javax.annotation - javax.annotation-api - ${annotation.api.version} - compile - - - io.micronaut - inject-java - provided - ch.qos.logback logback-classic - ${logback.version} runtime - io.projectreactor - reactor-core - ${reactor.version} + io.micronaut.rxjava3 + micronaut-rxjava3 + compile + + + io.micronaut.rxjava3 + micronaut-rxjava3-http-client + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.assertj + assertj-core + test + + + io.micronaut.test + micronaut-test-junit5 + test + + io.micronaut.build + micronaut-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + ${jdk.version} + ${jdk.version} + + -parameters + + + + + + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + + io.micronaut + micronaut-http-validation + ${micronaut.version} + + + + + org.apache.maven.plugins maven-shade-plugin ${shade.plugin.version} - package - - shade - - - - - ${exec.mainClass} - - - - + default-shade + none - - org.codehaus.mojo - exec-maven-plugin - - java - - -classpath - - ${exec.mainClass} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler.plugin.version} - - ${jdk.version} - ${jdk.version} - - -parameters - - - - io.micronaut - inject-java - ${micronaut.version} - - - - - - com.baeldung.micronaut.vs.springboot.CompareApplication - 1.0.0.RC2 + 3.10.1 17 - 1.3.2 - 3.1.6.RELEASE + 17 + jar 3.7.0 - 3.1.0 + netty + 3.2.0 \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java new file mode 100644 index 0000000000..d9e09b1c6e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface BirdCountClient { + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "11") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "10") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "") + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java new file mode 100644 index 0000000000..c836761266 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/bird") +public class BirdCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java new file mode 100644 index 0000000000..3075a135c8 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java @@ -0,0 +1,31 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.annotation.Value; +import io.micronaut.http.HttpRequest; +import io.micronaut.web.router.version.resolution.RequestVersionResolver; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.Optional; + +@Singleton +@Requires(property = "my.router.versioning.enabled", value = "true") +public class CustomVersionResolver implements RequestVersionResolver { + + @Inject + @Value("${micronaut.router.versioning.default-version}") + private String defaultVersion; + + @Override + public Optional resolve(HttpRequest request) { + var apiKey = Optional.ofNullable(request.getHeaders().get("api-key")); + + if (apiKey.isPresent() && !apiKey.get().isEmpty()) { + return Optional.of(Integer.parseInt(apiKey.get()) % 2 == 0 ? "2" : "1"); + } + + return Optional.of(defaultVersion); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java new file mode 100644 index 0000000000..487bff4d57 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface DogCountClient { + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("1") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("2") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java new file mode 100644 index 0000000000..de0f6788cf --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.header.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/dog") +public class DogCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java new file mode 100644 index 0000000000..2332ade98e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java @@ -0,0 +1,23 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface CatCountClient { + + @Get( + uri = "/cat/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable count(@QueryValue("max") @Nullable Integer max, @QueryValue(value = "v", defaultValue = "1") @Nullable Integer version); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java new file mode 100644 index 0000000000..43a34a2272 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java @@ -0,0 +1,37 @@ +package com.baeldung.micronaut.apiversioning.param.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/cat") +public class CatCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max == null ? 10 : max) + ); + } + + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java new file mode 100644 index 0000000000..cdb344b4e5 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java @@ -0,0 +1,39 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface SheepCountClient { + + @Get( + uri = "/v1/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/v2/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java new file mode 100644 index 0000000000..5ee6a2a57d --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java @@ -0,0 +1,26 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/v1/sheep/count") +public class SheepCountControllerV1 { + + @Get( + uri = "{?max}", + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV1(@Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max == null ? 10 : max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java new file mode 100644 index 0000000000..d95f4a3cca --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java @@ -0,0 +1,27 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller +public class SheepCountControllerV2 { + + @Get( + uris = {"/v2/sheep/count", "/sheep/count"}, + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java index 96bc51f235..943b2f703e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java @@ -1,28 +1,27 @@ package com.baeldung.micronaut.helloworld.client; import io.micronaut.http.HttpRequest; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; -import io.micronaut.http.client.RxHttpClient; -import io.reactivex.Single; - -import javax.inject.Singleton; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ConcreteGreetingClient { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { + public ConcreteGreetingClient(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest req = HttpRequest.GET("/greet/" + name); - return httpClient.retrieve(req).blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)).blockingGet(); } public Single greetAsync(String name) { HttpRequest req = HttpRequest.GET("/async/greet/" + name); - return httpClient.retrieve(req).first("An error as occurred"); + return Single.fromPublisher(httpClient.retrieve(req)); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java index 4d86b9dfed..862a822573 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java @@ -3,9 +3,9 @@ package com.baeldung.micronaut.helloworld.server.controller; import com.baeldung.micronaut.helloworld.server.service.GreetingService; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; -import io.reactivex.Single; -import javax.inject.Inject; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Inject; @Controller("/async/greet") public class AsyncGreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java index c890c037e4..ba3b6197d8 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java @@ -7,7 +7,7 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Post; -import javax.inject.Inject; +import jakarta.inject.Inject; @Controller("/greet") public class GreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java index 8ea5172cf6..865ee0b639 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java @@ -2,7 +2,7 @@ package com.baeldung.micronaut.helloworld.server.service; import io.micronaut.context.annotation.Primary; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Primary @Singleton diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java index 1ec53d8b2d..e426c2911e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.helloworld.server.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class SpanishGreetingService implements GreetingService { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java index 4654526b28..0fea9f970b 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java @@ -1,9 +1,11 @@ package com.baeldung.micronaut.vs.springboot; + import io.micronaut.runtime.Micronaut; public class CompareApplication { + public static void main(String[] args) { - Micronaut.run(CompareApplication.class); + Micronaut.run(CompareApplication.class, args); } -} +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java index 6b7ae900be..95e3157bfe 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java @@ -1,46 +1,46 @@ package com.baeldung.micronaut.vs.springboot.client; -import javax.inject.Singleton; - import io.micronaut.http.HttpRequest; -import io.micronaut.http.client.RxHttpClient; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ArithmeticClientImpl { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ArithmeticClientImpl(@Client("/") RxHttpClient httpClient) { + public ArithmeticClientImpl(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String sum(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/sum/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String subtract(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/subtract/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String multiply(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/multiply/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String divide(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/divide/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String memory() { HttpRequest req = HttpRequest.GET("/math/memory"); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java index 5bc0e865e1..b774556ece 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java @@ -3,7 +3,7 @@ package com.baeldung.micronaut.vs.springboot.controller; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; -import javax.inject.Inject; +import jakarta.inject.Inject; import com.baeldung.micronaut.vs.springboot.service.ArithmeticService; diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java index e0e4680495..599a6ee4cf 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.vs.springboot.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class ArithmeticService { diff --git a/microservices-modules/micronaut/src/main/resources/application.yml b/microservices-modules/micronaut/src/main/resources/application.yml index 32daacd4aa..b265d245aa 100644 --- a/microservices-modules/micronaut/src/main/resources/application.yml +++ b/microservices-modules/micronaut/src/main/resources/application.yml @@ -1,5 +1,19 @@ +context-path: / + micronaut: - application: - name: hello-world-server - server: - port: ${random.port} \ No newline at end of file + router: + versioning: + enabled: true + default-version: 2 + parameter: + enabled: true + names: 'v,api-version' + header: + enabled: true + names: + - 'X-API-VERSION' + + application: + name: hello-world-server + server: + port: ${random.port} diff --git a/microservices-modules/micronaut/src/main/resources/logback.xml b/microservices-modules/micronaut/src/main/resources/logback.xml index afaebf8e17..4db42a7916 100644 --- a/microservices-modules/micronaut/src/main/resources/logback.xml +++ b/microservices-modules/micronaut/src/main/resources/logback.xml @@ -8,6 +8,12 @@ + + + diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java new file mode 100644 index 0000000000..a3a547f9e2 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.context.annotation.Property; +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +@Property(name = "my.router.versioning.enabled", value = "true") +class BirdCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private BirdCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java new file mode 100644 index 0000000000..4a47c76943 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class DogCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private DogCountClient dogCountClient; + + @Test + void givenTheCountApi_whenUsingV1ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, dogCountClient.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, dogCountClient.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java new file mode 100644 index 0000000000..266f72eed8 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class CatCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private CatCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, 1).blockingSingle().split(",").length); + Assertions.assertEquals(5, client.count(5, 1).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.count(null, 2).count().blockingGet()); + + Assertions.assertEquals(6, client.count(6, 2).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, null).blockingSingle().split(",").length); + Assertions.assertEquals(6, client.count(6, null).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java new file mode 100644 index 0000000000..e082793fe1 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.stream.Collectors; + +@MicronautTest +class SheepCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + @Inject + private SheepCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + final var actual = client.countV2(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + final var actual = client.countDefault(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java index 336374d5a6..88a9782074 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java @@ -1,31 +1,19 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class ConcreteGreetingClientUnitTest -{ - private EmbeddedServer server; +@MicronautTest +public class ConcreteGreetingClientUnitTest { + @Inject + private EmbeddedApplication application; + @Inject private ConcreteGreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(ConcreteGreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java index c47fb3a31d..5b269531e7 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java @@ -1,30 +1,21 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +@MicronautTest public class GreetingClientUnitTest { - private EmbeddedServer server; + + @Inject + private EmbeddedApplication application; + + @Inject private GreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(GreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java index 9a1b095d22..fa191778f5 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java @@ -1,34 +1,21 @@ package com.baeldung.micronaut.vs.springboot; -import static org.junit.Assert.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import com.baeldung.micronaut.vs.springboot.client.ArithmeticClientImpl; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest public class ArithmeticClientUnitTest { - private EmbeddedServer server; + @Inject + private EmbeddedApplication server; + @Inject private ArithmeticClientImpl client; - @Before - public void setup() { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext() - .getBean(ArithmeticClientImpl.class); - } - - @After - public void cleanup() { - server.stop(); - } - @Test public void givenTwoNumbers_whenAdd_thenCorrectAnswerReturned() { String expected = Float.valueOf(10 + 20).toString(); @@ -56,6 +43,6 @@ public class ArithmeticClientUnitTest { @Test public void whenMemory_thenCorrectAnswerReturned() { String expected = "Initial:"; - assertThat(client.memory(), containsString(expected)); + assertThat(client.memory()).contains(expected); } } diff --git a/microservices-modules/pom.xml b/microservices-modules/pom.xml index 2111390481..a9cd8d2cd9 100644 --- a/microservices-modules/pom.xml +++ b/microservices-modules/pom.xml @@ -22,8 +22,4 @@ rest-express - - 3.3.2 - - \ No newline at end of file diff --git a/microservices-modules/rest-express/pom.xml b/microservices-modules/rest-express/pom.xml index da697fdc56..182d14cfbf 100644 --- a/microservices-modules/rest-express/pom.xml +++ b/microservices-modules/rest-express/pom.xml @@ -144,7 +144,6 @@ 1.0 0.4.8 4.11 - 1.2.1 2.4.1 2.0 diff --git a/muleesb/pom.xml b/muleesb/pom.xml index a2204c15b7..8cdd3400e9 100644 --- a/muleesb/pom.xml +++ b/muleesb/pom.xml @@ -217,6 +217,8 @@ 1.3.6 1.10 2.2.1 + 3.3.2 + 2.5.2 \ No newline at end of file diff --git a/pants/README.md b/pants/README.md new file mode 100644 index 0000000000..a37d2e3d31 --- /dev/null +++ b/pants/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to the Pants Build Tool](https://www.baeldung.com/ops/pants-build-tool-guide) diff --git a/parent-boot-3/README.md b/parent-boot-3/README.md index 738d97bdfd..d0b11d44d8 100644 --- a/parent-boot-3/README.md +++ b/parent-boot-3/README.md @@ -1,3 +1,3 @@ -## Parent Boot 2 +## Parent Boot 3 This is a parent module for all projects using Spring Boot 3. diff --git a/parent-spring-6/pom.xml b/parent-spring-6/pom.xml index 77afe2072a..7aaffb5483 100644 --- a/parent-spring-6/pom.xml +++ b/parent-spring-6/pom.xml @@ -35,7 +35,7 @@ - 6.0.10 + 6.0.12 diff --git a/axon/README.md b/patterns-modules/axon/README.md similarity index 100% rename from axon/README.md rename to patterns-modules/axon/README.md diff --git a/axon/pom.xml b/patterns-modules/axon/pom.xml similarity index 98% rename from axon/pom.xml rename to patterns-modules/axon/pom.xml index 5eed742aab..473a1b0e15 100644 --- a/axon/pom.xml +++ b/patterns-modules/axon/pom.xml @@ -11,7 +11,7 @@ com.baeldung parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-2 + ../../parent-boot-2 diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplication.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/OrderApplication.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/OrderApplication.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/OrderApplication.java diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/DuplicateOrderLineException.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/DuplicateOrderLineException.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/exceptions/DuplicateOrderLineException.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/DuplicateOrderLineException.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/OrderAlreadyConfirmedException.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/OrderAlreadyConfirmedException.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/exceptions/OrderAlreadyConfirmedException.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/OrderAlreadyConfirmedException.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/UnconfirmedOrderException.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/UnconfirmedOrderException.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/exceptions/UnconfirmedOrderException.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/exceptions/UnconfirmedOrderException.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/LegacyQueryHandler.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/LegacyQueryHandler.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/LegacyQueryHandler.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/LegacyQueryHandler.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderResponse.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderResponse.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/OrderResponse.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderResponse.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java b/patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java similarity index 100% rename from axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java rename to patterns-modules/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java diff --git a/axon/src/main/resources/application-mongo.properties b/patterns-modules/axon/src/main/resources/application-mongo.properties similarity index 100% rename from axon/src/main/resources/application-mongo.properties rename to patterns-modules/axon/src/main/resources/application-mongo.properties diff --git a/axon/src/main/resources/application.properties b/patterns-modules/axon/src/main/resources/application.properties similarity index 100% rename from axon/src/main/resources/application.properties rename to patterns-modules/axon/src/main/resources/application.properties diff --git a/spring-ejb-modules/wildfly/wildfly-ejb/src/main/resources/logback.xml b/patterns-modules/axon/src/main/resources/logback.xml similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-ejb/src/main/resources/logback.xml rename to patterns-modules/axon/src/main/resources/logback.xml diff --git a/axon/src/main/resources/order-api.http b/patterns-modules/axon/src/main/resources/order-api.http similarity index 100% rename from axon/src/main/resources/order-api.http rename to patterns-modules/axon/src/main/resources/order-api.http diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java diff --git a/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandlerUnitTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandlerUnitTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandlerUnitTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandlerUnitTest.java diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java b/patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java similarity index 100% rename from axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java rename to patterns-modules/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java diff --git a/axon/src/test/resources/application.properties b/patterns-modules/axon/src/test/resources/application.properties similarity index 100% rename from axon/src/test/resources/application.properties rename to patterns-modules/axon/src/test/resources/application.properties diff --git a/axon/start_axon_server.sh b/patterns-modules/axon/start_axon_server.sh old mode 100755 new mode 100644 similarity index 100% rename from axon/start_axon_server.sh rename to patterns-modules/axon/start_axon_server.sh diff --git a/axon/start_mongo.sh b/patterns-modules/axon/start_mongo.sh old mode 100755 new mode 100644 similarity index 100% rename from axon/start_mongo.sh rename to patterns-modules/axon/start_mongo.sh diff --git a/ddd-contexts/README.md b/patterns-modules/ddd-contexts/README.md similarity index 100% rename from ddd-contexts/README.md rename to patterns-modules/ddd-contexts/README.md diff --git a/ddd-contexts/ddd-contexts-infrastructure/pom.xml b/patterns-modules/ddd-contexts/ddd-contexts-infrastructure/pom.xml similarity index 100% rename from ddd-contexts/ddd-contexts-infrastructure/pom.xml rename to patterns-modules/ddd-contexts/ddd-contexts-infrastructure/pom.xml diff --git a/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java b/patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java similarity index 100% rename from ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java rename to patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java diff --git a/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java b/patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java similarity index 100% rename from ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java rename to patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java diff --git a/ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java b/patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java rename to patterns-modules/ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java diff --git a/ddd-contexts/ddd-contexts-mainapp/pom.xml b/patterns-modules/ddd-contexts/ddd-contexts-mainapp/pom.xml similarity index 100% rename from ddd-contexts/ddd-contexts-mainapp/pom.xml rename to patterns-modules/ddd-contexts/ddd-contexts-mainapp/pom.xml diff --git a/ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java b/patterns-modules/ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java similarity index 100% rename from ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java rename to patterns-modules/ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java diff --git a/ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java b/patterns-modules/ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java rename to patterns-modules/ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/pom.xml b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/pom.xml similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/pom.xml rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/pom.xml diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java diff --git a/ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java b/patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java rename to patterns-modules/ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java diff --git a/ddd-contexts/ddd-contexts-sharedkernel/pom.xml b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/pom.xml similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/pom.xml rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/pom.xml diff --git a/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java diff --git a/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java diff --git a/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java diff --git a/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java diff --git a/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java b/patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java rename to patterns-modules/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/pom.xml b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/pom.xml similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/pom.xml rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/pom.xml diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java diff --git a/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java b/patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java rename to patterns-modules/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java diff --git a/ddd-contexts/pom.xml b/patterns-modules/ddd-contexts/pom.xml similarity index 98% rename from ddd-contexts/pom.xml rename to patterns-modules/ddd-contexts/pom.xml index 961a1d1624..f43581b0c8 100644 --- a/ddd-contexts/pom.xml +++ b/patterns-modules/ddd-contexts/pom.xml @@ -11,7 +11,7 @@ com.baeldung - parent-modules + patterns-modules 1.0.0-SNAPSHOT diff --git a/ddd/README.md b/patterns-modules/ddd/README.md similarity index 100% rename from ddd/README.md rename to patterns-modules/ddd/README.md diff --git a/ddd/pom.xml b/patterns-modules/ddd/pom.xml similarity index 98% rename from ddd/pom.xml rename to patterns-modules/ddd/pom.xml index 443b2b5148..80147c29c6 100644 --- a/ddd/pom.xml +++ b/patterns-modules/ddd/pom.xml @@ -12,7 +12,7 @@ com.baeldung parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-2 + ../../parent-boot-2 diff --git a/ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java similarity index 96% rename from ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java index 3a52fd0440..2d671ff85e 100644 --- a/ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java +++ b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/PersistingDddAggregatesApplication.java @@ -1,12 +1,12 @@ -package com.baeldung.ddd; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication(scanBasePackages = "com.baeldung.ddd.order") -public class PersistingDddAggregatesApplication { - - public static void main(String[] args) { - SpringApplication.run(PersistingDddAggregatesApplication.class, args); - } -} +package com.baeldung.ddd; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "com.baeldung.ddd.order") +public class PersistingDddAggregatesApplication { + + public static void main(String[] args) { + SpringApplication.run(PersistingDddAggregatesApplication.class, args); + } +} diff --git a/ddd/src/main/java/com/baeldung/ddd/order/Order.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/Order.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/Order.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/Order.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/OrderLine.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/OrderLine.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/OrderLine.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/OrderLine.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/Product.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/Product.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/Product.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/Product.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/config/CustomMongoConfiguration.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/config/CustomMongoConfiguration.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/config/CustomMongoConfiguration.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/config/CustomMongoConfiguration.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/AmountBasedDiscountPolicy.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/AmountBasedDiscountPolicy.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/AmountBasedDiscountPolicy.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/AmountBasedDiscountPolicy.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/DiscountPolicy.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/DiscountPolicy.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/DiscountPolicy.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/DiscountPolicy.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/FlatDiscountPolicy.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/FlatDiscountPolicy.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/FlatDiscountPolicy.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/FlatDiscountPolicy.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/Order.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/Order.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/Order.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/Order.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialDiscountPolicy.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialDiscountPolicy.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialDiscountPolicy.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialDiscountPolicy.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialOrder.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialOrder.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialOrder.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/SpecialOrder.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/HtmlOrderViewCreator.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/HtmlOrderViewCreator.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/HtmlOrderViewCreator.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/HtmlOrderViewCreator.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/OrderVisitor.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/OrderVisitor.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/OrderVisitor.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/OrderVisitor.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/Visitable.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/Visitable.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/Visitable.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/doubledispatch/visitor/Visitable.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrder.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrder.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrder.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrder.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderLine.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderLine.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderLine.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderLine.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaOrderRepository.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaProduct.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaProduct.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaProduct.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/jpa/JpaProduct.java diff --git a/ddd/src/main/java/com/baeldung/ddd/order/mongo/OrderMongoRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/mongo/OrderMongoRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/ddd/order/mongo/OrderMongoRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/ddd/order/mongo/OrderMongoRepository.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/DomainLayerApplication.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/DomainLayerApplication.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/DomainLayerApplication.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/DomainLayerApplication.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/cli/CliOrderController.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/cli/CliOrderController.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/application/cli/CliOrderController.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/cli/CliOrderController.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/AddProductRequest.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/AddProductRequest.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/AddProductRequest.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/AddProductRequest.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/CreateOrderRequest.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/CreateOrderRequest.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/CreateOrderRequest.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/request/CreateOrderRequest.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/response/CreateOrderResponse.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/response/CreateOrderResponse.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/application/response/CreateOrderResponse.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/response/CreateOrderResponse.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/rest/OrderController.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/rest/OrderController.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/application/rest/OrderController.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/application/rest/OrderController.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/DomainException.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/DomainException.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/DomainException.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/DomainException.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Order.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Order.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Order.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Order.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderItem.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderItem.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderItem.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderItem.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderStatus.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderStatus.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderStatus.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/OrderStatus.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Product.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Product.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Product.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/Product.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/repository/OrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/repository/OrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/repository/OrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/repository/OrderRepository.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderService.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderService.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderService.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderService.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/OrderService.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/OrderService.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/OrderService.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/domain/service/OrderService.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/BeanConfiguration.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/BeanConfiguration.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/BeanConfiguration.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/BeanConfiguration.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/CassandraConfiguration.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/CassandraConfiguration.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/CassandraConfiguration.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/CassandraConfiguration.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/MongoDBConfiguration.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/MongoDBConfiguration.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/MongoDBConfiguration.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/configuration/MongoDBConfiguration.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/CassandraDbOrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/CassandraDbOrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/CassandraDbOrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/CassandraDbOrderRepository.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderEntity.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderEntity.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderEntity.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderEntity.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderItemEntity.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderItemEntity.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderItemEntity.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/OrderItemEntity.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/SpringDataCassandraOrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/SpringDataCassandraOrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/SpringDataCassandraOrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/cassandra/SpringDataCassandraOrderRepository.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/MongoDbOrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/MongoDbOrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/MongoDbOrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/MongoDbOrderRepository.java diff --git a/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/SpringDataMongoOrderRepository.java b/patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/SpringDataMongoOrderRepository.java similarity index 100% rename from ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/SpringDataMongoOrderRepository.java rename to patterns-modules/ddd/src/main/java/com/baeldung/dddhexagonalspring/infrastracture/repository/mongo/SpringDataMongoOrderRepository.java diff --git a/ddd/src/main/resources/ddd-layers.properties b/patterns-modules/ddd/src/main/resources/ddd-layers.properties similarity index 100% rename from ddd/src/main/resources/ddd-layers.properties rename to patterns-modules/ddd/src/main/resources/ddd-layers.properties diff --git a/ddd/src/test/java/com/baeldung/ddd/order/OrderFixtureUtils.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/OrderFixtureUtils.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/OrderFixtureUtils.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/OrderFixtureUtils.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/DoubleDispatchDiscountPolicyUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/DoubleDispatchDiscountPolicyUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/DoubleDispatchDiscountPolicyUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/DoubleDispatchDiscountPolicyUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/HtmlOrderViewCreatorUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/HtmlOrderViewCreatorUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/HtmlOrderViewCreatorUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/HtmlOrderViewCreatorUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/MethodOverloadExampleUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/MethodOverloadExampleUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/MethodOverloadExampleUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/MethodOverloadExampleUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/SingleDispatchDiscountPolicyUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/SingleDispatchDiscountPolicyUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/SingleDispatchDiscountPolicyUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/doubledispatch/SingleDispatchDiscountPolicyUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/jpa/PersistOrderLiveTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/jpa/PersistOrderLiveTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/jpa/PersistOrderLiveTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/jpa/PersistOrderLiveTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/ddd/order/mongo/OrderMongoLiveTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/mongo/OrderMongoLiveTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/ddd/order/mongo/OrderMongoLiveTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/ddd/order/mongo/OrderMongoLiveTest.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderProvider.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderProvider.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderProvider.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderProvider.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/OrderUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderServiceUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderServiceUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderServiceUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/domain/service/DomainOrderServiceUnitTest.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/CassandraDbOrderRepositoryLiveTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/CassandraDbOrderRepositoryLiveTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/CassandraDbOrderRepositoryLiveTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/CassandraDbOrderRepositoryLiveTest.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryLiveTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryLiveTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryLiveTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryLiveTest.java diff --git a/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java b/patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java similarity index 100% rename from ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java rename to patterns-modules/ddd/src/test/java/com/baeldung/dddhexagonalspring/infrastracture/repository/MongoDbOrderRepositoryUnitTest.java diff --git a/ddd/src/test/resources/com/baeldung/dddhexagonalspring/README.md b/patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/README.md similarity index 100% rename from ddd/src/test/resources/com/baeldung/dddhexagonalspring/README.md rename to patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/README.md diff --git a/ddd/src/test/resources/com/baeldung/dddhexagonalspring/cassandra-init.cql b/patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/cassandra-init.cql similarity index 100% rename from ddd/src/test/resources/com/baeldung/dddhexagonalspring/cassandra-init.cql rename to patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/cassandra-init.cql diff --git a/ddd/src/test/resources/com/baeldung/dddhexagonalspring/docker-compose.yml b/patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/docker-compose.yml similarity index 100% rename from ddd/src/test/resources/com/baeldung/dddhexagonalspring/docker-compose.yml rename to patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/docker-compose.yml diff --git a/ddd/src/test/resources/com/baeldung/dddhexagonalspring/mongo-init.js b/patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/mongo-init.js similarity index 100% rename from ddd/src/test/resources/com/baeldung/dddhexagonalspring/mongo-init.js rename to patterns-modules/ddd/src/test/resources/com/baeldung/dddhexagonalspring/mongo-init.js diff --git a/ddd/src/test/resources/ddd-layers-test.properties b/patterns-modules/ddd/src/test/resources/ddd-layers-test.properties similarity index 100% rename from ddd/src/test/resources/ddd-layers-test.properties rename to patterns-modules/ddd/src/test/resources/ddd-layers-test.properties diff --git a/patterns-modules/design-patterns-creational-2/README.md b/patterns-modules/design-patterns-creational-2/README.md index dc5b2a1861..b7fdb556d1 100644 --- a/patterns-modules/design-patterns-creational-2/README.md +++ b/patterns-modules/design-patterns-creational-2/README.md @@ -1,2 +1,3 @@ ## Relevant Articles - [The Factory Design Pattern in Java](https://www.baeldung.com/java-factory-pattern) +- [Drawbacks of the Singleton Design Pattern](https://www.baeldung.com/java-patterns-singleton-cons) diff --git a/patterns-modules/design-patterns-creational-2/pom.xml b/patterns-modules/design-patterns-creational-2/pom.xml index fe79052a99..27c83c9eb7 100644 --- a/patterns-modules/design-patterns-creational-2/pom.xml +++ b/patterns-modules/design-patterns-creational-2/pom.xml @@ -12,4 +12,13 @@ 1.0.0-SNAPSHOT + + + org.mockito + mockito-inline + ${mockito.version} + test + + + \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/Logger.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/Logger.java new file mode 100644 index 0000000000..31729c29f4 --- /dev/null +++ b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/Logger.java @@ -0,0 +1,38 @@ +package com.baeldung.singleton; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.LocalDateTime; + +public class Logger { + private static volatile Logger instance; + + private PrintWriter fileWriter; + + public static Logger getInstance() { + if (instance == null) { + synchronized (Logger.class) { + if (instance == null) { + instance = new Logger(); + } + } + } + return instance; + } + + private Logger() { + try { + fileWriter = new PrintWriter(new FileWriter("app.log")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void log(String message) { + String log = String.format("[%s]- %s", LocalDateTime.now(), message); + fileWriter.println(log); + fileWriter.flush(); + } + +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/SingletonDemo.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/SingletonDemo.java new file mode 100644 index 0000000000..2ebd6c8ad4 --- /dev/null +++ b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/singleton/SingletonDemo.java @@ -0,0 +1,12 @@ +package com.baeldung.singleton; + +public class SingletonDemo { + + public int sum(int a, int b) { + int result = a + b; + Logger logger = Logger.getInstance(); + logger.log("The sum is " + result); + return result; + } + +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/singleton/SingletonUnitTest.java b/patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/singleton/SingletonUnitTest.java new file mode 100644 index 0000000000..d4154d9396 --- /dev/null +++ b/patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/singleton/SingletonUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.singleton; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + +class SingletonUnitTest { + + @Test + void givenTwoValues_whenSum_thenReturnCorrectResult() { + SingletonDemo singletonDemo = new SingletonDemo(); + int result = singletonDemo.sum(12, 4); + Assertions.assertEquals(16, result); + } + + @Test + void givenMockedLogger_whenSum_thenReturnCorrectResult() { + Logger logger = mock(Logger.class); + + try (MockedStatic loggerMockedStatic = mockStatic(Logger.class)) { + loggerMockedStatic.when(Logger::getInstance).thenReturn(logger); + doNothing().when(logger).log(any()); + + SingletonDemo singletonDemo = new SingletonDemo(); + int result = singletonDemo.sum(12, 4); + Assertions.assertEquals(16, result); + } + } + +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AbstractFactoryRunner.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AbstractFactoryRunner.java new file mode 100644 index 0000000000..59aa3f8040 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AbstractFactoryRunner.java @@ -0,0 +1,8 @@ +package com.baeldung.creational.abstractfactory2; + +public class AbstractFactoryRunner { + + public static void main(String[] args) { + new AnimalAbstractFactory().createAnimal(AnimalType.LAND); + } +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/Animal.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/Animal.java new file mode 100644 index 0000000000..97b444c3e0 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/Animal.java @@ -0,0 +1,13 @@ +package com.baeldung.creational.abstractfactory2; + +public abstract class Animal { + AnimalType type; + AnimalEra era; + String name; + Animal(AnimalType type, AnimalEra era, String name) { + this.type = type; + this.era = era; + this.name = name; + } + abstract void create(); +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalAbstractFactory.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalAbstractFactory.java new file mode 100644 index 0000000000..6d09e1661a --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalAbstractFactory.java @@ -0,0 +1,22 @@ +package com.baeldung.creational.abstractfactory2; + +public class AnimalAbstractFactory { + + Animal animal; + Animal createAnimal(AnimalType type) { + AnimalEra era = getFromConfiguration(); + switch (era) { + case MESOZOIC: + animal = new MesozoicAnimalFactory().createAnimal(type); + break; + case CENOZOIC: + animal = new CenozoicAnimalFactory().createAnimal(type); + break; + } + return null; + } + + AnimalEra getFromConfiguration() { + return AnimalEra.MESOZOIC; + } +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalEra.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalEra.java new file mode 100644 index 0000000000..0ee4deda65 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalEra.java @@ -0,0 +1,6 @@ +package com.baeldung.creational.abstractfactory2; + +public enum AnimalEra { + MESOZOIC, + CENOZOIC +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalType.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalType.java new file mode 100644 index 0000000000..be2f5e2361 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/AnimalType.java @@ -0,0 +1,6 @@ +package com.baeldung.creational.abstractfactory2; + +public enum AnimalType { + LAND, + SKY +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/CenozoicAnimalFactory.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/CenozoicAnimalFactory.java new file mode 100644 index 0000000000..cf28acdd25 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/CenozoicAnimalFactory.java @@ -0,0 +1,23 @@ +package com.baeldung.creational.abstractfactory2; + +public class CenozoicAnimalFactory implements EraAnimalFactory{ + @Override + public LandAnimal makeLandAnimal() { + return new LandAnimal(AnimalEra.CENOZOIC, "Mammoth"); + } + + @Override + public SkyAnimal makeSkyAnimal() { + return new SkyAnimal(AnimalEra.CENOZOIC, "Terror bird"); + } + + Animal createAnimal(AnimalType type) { + switch (type) { + case LAND: + return makeLandAnimal(); + case SKY: + return makeSkyAnimal(); + } + return null; + } +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/EraAnimalFactory.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/EraAnimalFactory.java new file mode 100644 index 0000000000..30c69b4598 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/EraAnimalFactory.java @@ -0,0 +1,7 @@ +package com.baeldung.creational.abstractfactory2; + +public interface EraAnimalFactory { + + LandAnimal makeLandAnimal(); + SkyAnimal makeSkyAnimal(); +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/LandAnimal.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/LandAnimal.java new file mode 100644 index 0000000000..963cd96969 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/LandAnimal.java @@ -0,0 +1,13 @@ +package com.baeldung.creational.abstractfactory2; + +public class LandAnimal extends Animal{ + + LandAnimal(AnimalEra era, String name) { + super(AnimalType.LAND, era, name); + create(); + } + @Override + void create() { + System.out.println("Creating a " + type + " animal: " + name); + } +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/MesozoicAnimalFactory.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/MesozoicAnimalFactory.java new file mode 100644 index 0000000000..dd56669242 --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/MesozoicAnimalFactory.java @@ -0,0 +1,24 @@ +package com.baeldung.creational.abstractfactory2; + +public class MesozoicAnimalFactory implements EraAnimalFactory{ + @Override + public LandAnimal makeLandAnimal() { + return new LandAnimal(AnimalEra.MESOZOIC, "Tyrannosaurus Rex"); + } + + @Override + public SkyAnimal makeSkyAnimal() { + return new SkyAnimal(AnimalEra.MESOZOIC, "Pterodactylus"); + } + + Animal createAnimal(AnimalType type) { + switch (type) { + case LAND: + return makeLandAnimal(); + case SKY: + return makeSkyAnimal(); + } + return null; + } + +} diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/SkyAnimal.java b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/SkyAnimal.java new file mode 100644 index 0000000000..ce27236d7c --- /dev/null +++ b/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/creational/abstractfactory2/SkyAnimal.java @@ -0,0 +1,13 @@ +package com.baeldung.creational.abstractfactory2; + +public class SkyAnimal extends Animal{ + + SkyAnimal(AnimalEra era, String name) { + super(AnimalType.SKY, era, name); + create(); + } + @Override + void create() { + System.out.println("Creating a " + type + " animal: " + name); + } +} diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/bridge/BridgePatternDriver.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/bridge/BridgePatternDriver.java index 31d18a2347..78e20a15be 100644 --- a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/bridge/BridgePatternDriver.java +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/bridge/BridgePatternDriver.java @@ -1,14 +1,16 @@ package com.baeldung.bridge; +import static com.baeldung.util.LoggerUtil.LOG; + public class BridgePatternDriver { public static void main(String[] args) { //a square with red color Shape square = new Square(new Red()); - System.out.println(square.draw()); + LOG.info(square.draw()); //a triangle with blue color Shape triangle = new Triangle(new Blue()); - System.out.println(triangle.draw()); + LOG.info(triangle.draw()); } } diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/FinancialDepartment.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/FinancialDepartment.java index 173281f833..b8ec67afab 100644 --- a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/FinancialDepartment.java +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/FinancialDepartment.java @@ -1,5 +1,7 @@ package com.baeldung.composite; +import static com.baeldung.util.LoggerUtil.LOG; + /** * Created by Gebruiker on 5/1/2018. */ @@ -14,7 +16,7 @@ public class FinancialDepartment implements Department { } public void printDepartmentName() { - System.out.println(getClass().getSimpleName()); + LOG.info(getClass().getSimpleName()); } public Integer getId() { diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/SalesDepartment.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/SalesDepartment.java index 7f5e903100..fdc3076b53 100644 --- a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/SalesDepartment.java +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/composite/SalesDepartment.java @@ -1,5 +1,7 @@ package com.baeldung.composite; +import static com.baeldung.util.LoggerUtil.LOG; + /** * Created by Gebruiker on 5/1/2018. */ @@ -14,7 +16,7 @@ public class SalesDepartment implements Department { } public void printDepartmentName() { - System.out.println(getClass().getSimpleName()); + LOG.info(getClass().getSimpleName()); } public Integer getId() { diff --git a/patterns-modules/design-patterns-structural/src/main/resources/log4jstructuraldp.properties b/patterns-modules/design-patterns-structural/src/main/resources/log4jstructuraldp.properties index 5bc2bfe4b9..d7bfb41d12 100644 --- a/patterns-modules/design-patterns-structural/src/main/resources/log4jstructuraldp.properties +++ b/patterns-modules/design-patterns-structural/src/main/resources/log4jstructuraldp.properties @@ -1,6 +1,6 @@ # Root logger -log4j.rootLogger=INFO, file, stdout +log4j.rootLogger=INFO, stdout # Write to console log4j.appender.stdout=org.apache.log4j.ConsoleAppender diff --git a/patterns-modules/pom.xml b/patterns-modules/pom.xml index add2b0475b..7dd26ac31c 100644 --- a/patterns-modules/pom.xml +++ b/patterns-modules/pom.xml @@ -14,6 +14,12 @@ + axon + clean-architecture + coupling + cqrs-es + ddd + ddd-contexts design-patterns-architectural design-patterns-behavioral design-patterns-behavioral-2 @@ -24,14 +30,11 @@ design-patterns-singleton design-patterns-structural dip - cqrs-es + enterprise-patterns front-controller + idd intercepting-filter solid - clean-architecture - enterprise-patterns - coupling - idd diff --git a/persistence-modules/core-java-persistence-2/README.md b/persistence-modules/core-java-persistence-2/README.md index afabf9ecb3..f9da4947a7 100644 --- a/persistence-modules/core-java-persistence-2/README.md +++ b/persistence-modules/core-java-persistence-2/README.md @@ -9,3 +9,4 @@ - [Get the Number of Rows in a ResultSet](https://www.baeldung.com/java-resultset-number-of-rows) - [Converting a JDBC ResultSet to JSON in Java](https://www.baeldung.com/java-jdbc-convert-resultset-to-json) - [Guide to MicroStream](https://www.baeldung.com/microstream-intro) +- [Executing SQL Script File in Java](https://www.baeldung.com/java-run-sql-script) diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index 0bec7a808f..2013bdb6af 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -70,6 +70,16 @@ ${assertj.version} test + + org.mybatis + mybatis + ${mybatis.version} + + + org.springframework + spring-jdbc + ${spring-jdbc.version} + @@ -80,6 +90,8 @@ 20220320 07.00.00-MS-GA 2.1.214 + 5.3.29 + 3.5.7 \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java new file mode 100644 index 0000000000..8a9bbb6e20 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java @@ -0,0 +1,13 @@ +package com.baeldung.script; + +import org.apache.ibatis.jdbc.ScriptRunner; +import java.sql.Connection; + +public class MyBatisScriptUtility { + public static void runScript(String path, Connection connection) throws Exception { + ScriptRunner scriptRunner = new ScriptRunner(connection); + scriptRunner.setSendFullScript(false); + scriptRunner.setStopOnError(true); + scriptRunner.runScript(new java.io.FileReader(path)); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java new file mode 100644 index 0000000000..cf70dfa890 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java @@ -0,0 +1,29 @@ +package com.baeldung.script; + +import org.springframework.core.io.PathResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; + +import java.sql.Connection; + +public class SpringScriptUtility { + public static void runScript(String path, Connection connection) { + boolean continueOrError = false; + boolean ignoreFailedDrops = false; + String commentPrefix = "--"; + String separator = ";"; + String blockCommentStartDelimiter = "/*"; + String blockCommentEndDelimiter = "*/"; + + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new PathResource(path)), + continueOrError, + ignoreFailedDrops, + commentPrefix, + separator, + blockCommentStartDelimiter, + blockCommentEndDelimiter + ); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java new file mode 100644 index 0000000000..b9da968abe --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java @@ -0,0 +1,74 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SqlScriptBatchExecutor { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutor.class); + private static final Pattern COMMENT_PATTERN = Pattern.compile("--.*|/\\*(.|[\\r\\n])*?\\*/"); + public static void executeBatchedSQL(String scriptFilePath, Connection connection, int batchSize) throws Exception { + List sqlStatements = parseSQLScript(scriptFilePath); + executeSQLBatches(connection, sqlStatements, batchSize); + } + private static List parseSQLScript(String scriptFilePath) throws IOException { + List sqlStatements = new ArrayList<>(); + + try (BufferedReader reader = new BufferedReader(new FileReader(scriptFilePath))) { + StringBuilder currentStatement = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + line = commentMatcher.replaceAll(""); + line = line.trim(); + + if (line.isEmpty()) { + continue; + } + + currentStatement.append(line).append(" "); + + if (line.endsWith(";")) { + sqlStatements.add(currentStatement.toString()); + logger.info(currentStatement.toString()); + currentStatement.setLength(0); + } + } + } catch (IOException e) { + throw e; + } + return sqlStatements; + } + + private static void executeSQLBatches(Connection connection, List sqlStatements, int batchSize) + throws SQLException { + int count = 0; + Statement statement = connection.createStatement(); + + for (String sql : sqlStatements) { + statement.addBatch(sql); + count++; + + if (count % batchSize == 0) { + logger.info("Executing batch"); + statement.executeBatch(); + statement.clearBatch(); + } + } + // Execute any remaining statements + if (count % batchSize != 0) { + statement.executeBatch(); + } + connection.commit(); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java new file mode 100644 index 0000000000..98f82cfbd5 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class MyBatisScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(MyBatisScriptUtilityUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb1"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + MyBatisScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java new file mode 100644 index 0000000000..be6e39ca31 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SpringScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(SpringScriptUtilityUnitTest.class); + + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb2"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SpringScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java new file mode 100644 index 0000000000..3b1210fd00 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SqlScriptBatchExecutorUnitTest { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutorUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb3"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SqlScriptBatchExecutor.executeBatchedSQL(path, connection, 10); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } + +} diff --git a/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql new file mode 100644 index 0000000000..c532458163 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql @@ -0,0 +1,75 @@ +/** +Script Name : Create employees script +Author: Parthiv Pradhan + +**/ + +-- Create the employees table if it doesn't exist +CREATE TABLE employees ( + id INT PRIMARY KEY, + first_name VARCHAR(50), + last_name VARCHAR(50), + department VARCHAR(50), + salary DECIMAL(10, 2) +); + +-- Insert employee records +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (1, 'John', 'Doe', 'HR', 50000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (2, 'Jane', 'Smith', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (3, 'Michael', 'Johnson', 'Finance', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (4, 'Emily', 'Williams', 'Marketing', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (5, 'David', 'Brown', 'IT', 65000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (6, 'Sarah', 'Miller', 'Finance', 58000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (7, 'Robert', 'Jones', 'HR', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (8, 'Jessica', 'Davis', 'Marketing', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (9, 'William', 'Wilson', 'IT', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (10, 'Jennifer', 'Taylor', 'Finance', 57000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (11, 'Daniel', 'Anderson', 'Marketing', 54000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (12, 'Linda', 'Martinez', 'HR', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (13, 'Christopher', 'Lopez', 'IT', 62000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (14, 'Karen', 'Hernandez', 'Finance', 56000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (15, 'Mark', 'Garcia', 'Marketing', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (16, 'Patricia', 'Lee', 'HR', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (17, 'Anthony', 'Clark', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (18, 'Maria', 'Lewis', 'Finance', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (19, 'Paul', 'Walker', 'Marketing', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (20, 'Ruth', 'Young', 'HR', 54000.00); diff --git a/couchbase/.gitignore b/persistence-modules/couchbase/.gitignore similarity index 100% rename from couchbase/.gitignore rename to persistence-modules/couchbase/.gitignore diff --git a/couchbase/README.md b/persistence-modules/couchbase/README.md similarity index 100% rename from couchbase/README.md rename to persistence-modules/couchbase/README.md diff --git a/couchbase/mvnw b/persistence-modules/couchbase/mvnw similarity index 100% rename from couchbase/mvnw rename to persistence-modules/couchbase/mvnw diff --git a/couchbase/mvnw.cmd b/persistence-modules/couchbase/mvnw.cmd similarity index 100% rename from couchbase/mvnw.cmd rename to persistence-modules/couchbase/mvnw.cmd diff --git a/couchbase/pom.xml b/persistence-modules/couchbase/pom.xml similarity index 98% rename from couchbase/pom.xml rename to persistence-modules/couchbase/pom.xml index 823b33ee29..b98c0cc387 100644 --- a/couchbase/pom.xml +++ b/persistence-modules/couchbase/pom.xml @@ -10,7 +10,7 @@ com.baeldung - parent-modules + persistence-modules 1.0.0-SNAPSHOT diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java b/persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java similarity index 100% rename from couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java rename to persistence-modules/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java diff --git a/couchbase/src/main/resources/application.properties b/persistence-modules/couchbase/src/main/resources/application.properties similarity index 100% rename from couchbase/src/main/resources/application.properties rename to persistence-modules/couchbase/src/main/resources/application.properties diff --git a/couchbase/src/main/resources/logback.xml b/persistence-modules/couchbase/src/main/resources/logback.xml similarity index 100% rename from couchbase/src/main/resources/logback.xml rename to persistence-modules/couchbase/src/main/resources/logback.xml diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTestConfig.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTestConfig.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTestConfig.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTestConfig.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceLiveTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceLiveTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceLiveTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLLiveTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceLiveTest.java diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceLiveTest.java b/persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceLiveTest.java similarity index 100% rename from couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceLiveTest.java rename to persistence-modules/couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceLiveTest.java diff --git a/couchbase/src/test/resources/logback.xml b/persistence-modules/couchbase/src/test/resources/logback.xml similarity index 100% rename from couchbase/src/test/resources/logback.xml rename to persistence-modules/couchbase/src/test/resources/logback.xml diff --git a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java index 096faf7984..c25820300e 100644 --- a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java +++ b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java @@ -18,7 +18,7 @@ public class Email { private String address; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "employee_id") + @JoinColumn(name = "employee_id", referencedColumnName = "id") private OfficialEmployee employee; public Long getId() { diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index eaa7b0e765..954f8f40d3 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -82,7 +82,6 @@ 8.0.32 2.6.0 0.9 - 1.14.2 \ No newline at end of file diff --git a/persistence-modules/hibernate-libraries/pom.xml b/persistence-modules/hibernate-libraries/pom.xml index 031d55c17d..3f4da28296 100644 --- a/persistence-modules/hibernate-libraries/pom.xml +++ b/persistence-modules/hibernate-libraries/pom.xml @@ -166,7 +166,6 @@ 3.27.0-GA 2.3.1 2.0.0 - 3.0.2 3.8.1 3.8.1 8.0.19 diff --git a/persistence-modules/hibernate-ogm/src/test/java/com/baeldung/hibernate/ogm/EditorUnitTest.java b/persistence-modules/hibernate-ogm/src/test/java/com/baeldung/hibernate/ogm/EditorUnitTest.java index d7fd49d917..3903e272de 100644 --- a/persistence-modules/hibernate-ogm/src/test/java/com/baeldung/hibernate/ogm/EditorUnitTest.java +++ b/persistence-modules/hibernate-ogm/src/test/java/com/baeldung/hibernate/ogm/EditorUnitTest.java @@ -22,6 +22,7 @@ public class EditorUnitTest { loadAndVerifyTestData(entityManagerFactory, editor); } */ + @Test public void givenNeo4j_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ogm-neo4j"); diff --git a/persistence-modules/java-cassandra/pom.xml b/persistence-modules/java-cassandra/pom.xml index 0dd148e528..6479ae3312 100644 --- a/persistence-modules/java-cassandra/pom.xml +++ b/persistence-modules/java-cassandra/pom.xml @@ -13,26 +13,11 @@ - com.datastax.cassandra cassandra-driver-core ${cassandra-driver-core.version} - true - - - com.google.guava - guava - - - - - org.cassandraunit - cassandra-unit - ${cassandra-unit.version} - - com.datastax.oss java-driver-core @@ -48,32 +33,28 @@ netty-transport ${netty-transport-version} + + org.testcontainers + cassandra + ${cassandra-testcontainer.version} + test + - - - integration-lite-first - - - - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - true - - - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + + + 3.1.2 - 3.1.1.0 4.1.0 + 1.15.3 4.1.71.Final diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/CassandraConnector.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/CassandraConnector.java index 02d63c62f6..7c9a00f088 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/CassandraConnector.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/CassandraConnector.java @@ -5,8 +5,6 @@ import com.datastax.oss.driver.api.core.CqlSessionBuilder; import java.net.InetSocketAddress; -import org.apache.commons.lang3.StringUtils; - public class CassandraConnector { private CqlSession session; @@ -14,11 +12,11 @@ public class CassandraConnector { public void connect(final String node, final Integer port, final String dataCenter) { CqlSessionBuilder builder = CqlSession.builder(); builder.addContactPoint(new InetSocketAddress(node, port)); - if (StringUtils.isNotBlank(dataCenter)) { + if (dataCenter != null && !dataCenter.isEmpty()) { builder.withLocalDatacenter(dataCenter); } - session = builder.build(); + session = builder.build(); } public CqlSession getSession() { diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java index f067ee8b73..57f5d8cf0e 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java @@ -1,5 +1,6 @@ package com.baeldung.datastax.cassandra; +import com.baeldung.cassandra.batch.repository.ProductRepository; import com.baeldung.datastax.cassandra.domain.Video; import com.baeldung.datastax.cassandra.repository.KeyspaceRepository; import com.baeldung.datastax.cassandra.repository.VideoRepository; @@ -30,9 +31,11 @@ public class Application { keyspaceRepository.useKeyspace("testKeyspace"); VideoRepository videoRepository = new VideoRepository(session); + ProductRepository productRepository = new ProductRepository(session); videoRepository.createTable(); + productRepository.createProductTableByName("testKeyspace"); videoRepository.insertVideo(new Video("Video Title 1", Instant.now())); videoRepository.insertVideo(new Video("Video Title 2", Instant.now().minus(1, ChronoUnit.DAYS))); diff --git a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryIntegrationTest.java b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryLiveTest.java similarity index 80% rename from persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryIntegrationTest.java rename to persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryLiveTest.java index 55dc3dad9f..9e6839b2b4 100644 --- a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryIntegrationTest.java +++ b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/batch/epository/ProductRepositoryLiveTest.java @@ -1,24 +1,5 @@ package com.baeldung.cassandra.batch.epository; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.thrift.transport.TTransportException; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runners.MethodSorters; - -import com.baeldung.cassandra.batch.CassandraConnector; import com.baeldung.cassandra.batch.domain.Product; import com.baeldung.cassandra.batch.repository.KeyspaceRepository; import com.baeldung.cassandra.batch.repository.ProductRepository; @@ -26,10 +7,25 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.ColumnDefinition; import com.datastax.oss.driver.api.core.cql.ResultSet; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.testcontainers.containers.CassandraContainer; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class ProductRepositoryIntegrationTest { - +public class ProductRepositoryLiveTest { + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:3.11.2"); private KeyspaceRepository schemaRepository; private ProductRepository productRepository; @@ -39,21 +35,20 @@ public class ProductRepositoryIntegrationTest { private final String KEYSPACE_NAME = "testBaeldungKeyspace"; private final String PRODUCT = "product"; - @BeforeClass - public static void init() throws ConfigurationException, TTransportException, IOException, InterruptedException { - // Start an embedded Cassandra Server - EmbeddedCassandraServerHelper.startEmbeddedCassandra(20000L); - } - @Before public void connect() { - CassandraConnector client = new CassandraConnector(); - client.connect("127.0.0.1", 9142,"datacenter1"); - session = client.getSession(); - schemaRepository = new KeyspaceRepository(client.getSession()); + cassandra.start(); + + this.session = CqlSession + .builder() + .addContactPoint(new InetSocketAddress(cassandra.getHost(),cassandra.getFirstMappedPort())) + .withLocalDatacenter("datacenter1") + .build(); + + schemaRepository = new KeyspaceRepository(this.session); schemaRepository.createKeyspace(KEYSPACE_NAME, 1); schemaRepository.useKeyspace(KEYSPACE_NAME); - productRepository = new ProductRepository(client.getSession()); + productRepository = new ProductRepository(this.session); } @Test @@ -114,14 +109,7 @@ public class ProductRepositoryIntegrationTest { assertEquals(productList.get(0).getPrice(), 12f,0f); assertEquals(productList.get(1).getPrice(), 12f,0f); } - - - @AfterClass - public static void cleanup() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - } - private Product getTestProduct() { Product product = new Product(); product.setProductName("Banana"); diff --git a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryIntegrationTest.java b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryLiveTest.java similarity index 82% rename from persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryIntegrationTest.java rename to persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryLiveTest.java index 62eae94c7c..2fa39113c6 100644 --- a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryIntegrationTest.java +++ b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/BookRepositoryLiveTest.java @@ -1,31 +1,24 @@ package com.baeldung.cassandra.java.client.repository; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.thrift.transport.TTransportException; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.baeldung.cassandra.java.client.CassandraConnector; import com.baeldung.cassandra.java.client.domain.Book; +import com.datastax.driver.core.Cluster; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Session; import com.datastax.driver.core.exceptions.InvalidQueryException; import com.datastax.driver.core.utils.UUIDs; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.CassandraContainer; -public class BookRepositoryIntegrationTest { +import java.util.List; +import java.util.stream.Collectors; - private KeyspaceRepository schemaRepository; +import static org.junit.Assert.*; + +public class BookRepositoryLiveTest { + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:3.11.2"); private BookRepository bookRepository; @@ -35,18 +28,18 @@ public class BookRepositoryIntegrationTest { final String BOOKS = "books"; final String BOOKS_BY_TITLE = "booksByTitle"; - @BeforeClass - public static void init() throws ConfigurationException, TTransportException, IOException, InterruptedException { - // Start an embedded Cassandra Server - EmbeddedCassandraServerHelper.startEmbeddedCassandra(20000L); - } - @Before public void connect() { - CassandraConnector client = new CassandraConnector(); - client.connect("127.0.0.1", 9142); - this.session = client.getSession(); - schemaRepository = new KeyspaceRepository(session); + cassandra.start(); + + this.session = Cluster + .builder() + .addContactPoint(cassandra.getHost()) + .withPort(cassandra.getMappedPort(CassandraContainer.CQL_PORT)) + .build() + .newSession(); + + KeyspaceRepository schemaRepository = new KeyspaceRepository(session); schemaRepository.createKeyspace(KEYSPACE_NAME, "SimpleStrategy", 1); schemaRepository.useKeyspace(KEYSPACE_NAME); bookRepository = new BookRepository(session); @@ -166,9 +159,4 @@ public class BookRepositoryIntegrationTest { session.execute("SELECT * FROM " + KEYSPACE_NAME + "." + BOOKS + ";"); } - - @AfterClass - public static void cleanup() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - } } diff --git a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryIntegrationTest.java b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryLiveTest.java similarity index 61% rename from persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryIntegrationTest.java rename to persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryLiveTest.java index 9df46b3176..3a8411ddce 100644 --- a/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryIntegrationTest.java +++ b/persistence-modules/java-cassandra/src/test/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepositoryLiveTest.java @@ -1,45 +1,38 @@ package com.baeldung.cassandra.java.client.repository; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Session; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.testcontainers.containers.CassandraContainer; -import java.io.IOException; import java.util.List; import java.util.stream.Collectors; -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.thrift.transport.TTransportException; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runners.MethodSorters; - -import com.baeldung.cassandra.java.client.CassandraConnector; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; +import static org.junit.Assert.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class KeyspaceRepositoryIntegrationTest { - +public class KeyspaceRepositoryLiveTest { + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:3.11.2"); private KeyspaceRepository schemaRepository; - private Session session; - @BeforeClass - public static void init() throws ConfigurationException, TTransportException, IOException, InterruptedException { - // Start an embedded Cassandra Server - EmbeddedCassandraServerHelper.startEmbeddedCassandra(20000L); - } - @Before public void connect() { - CassandraConnector client = new CassandraConnector(); - client.connect("127.0.0.1", 9142); - this.session = client.getSession(); + cassandra.start(); + + this.session = Cluster + .builder() + .addContactPoint(cassandra.getHost()) + .withPort(cassandra.getMappedPort(CassandraContainer.CQL_PORT)) + .build() + .newSession(); + schemaRepository = new KeyspaceRepository(session); } @@ -62,16 +55,11 @@ public class KeyspaceRepositoryIntegrationTest { public void whenDeletingAKeyspace_thenDoesNotExist() { String keyspaceName = "testBaeldungKeyspace"; - // schemaRepository.createKeyspace(keyspaceName, "SimpleStrategy", 1); + schemaRepository.createKeyspace(keyspaceName, "SimpleStrategy", 1); schemaRepository.deleteKeyspace(keyspaceName); ResultSet result = session.execute("SELECT * FROM system_schema.keyspaces;"); boolean isKeyspaceCreated = result.all().stream().anyMatch(r -> r.getString(0).equals(keyspaceName.toLowerCase())); assertFalse(isKeyspaceCreated); } - - @AfterClass - public static void cleanup() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - } } diff --git a/persistence-modules/java-jpa-2/pom.xml b/persistence-modules/java-jpa-2/pom.xml index 34e7f9f349..77d9590d65 100644 --- a/persistence-modules/java-jpa-2/pom.xml +++ b/persistence-modules/java-jpa-2/pom.xml @@ -156,7 +156,6 @@ 4.0.1 2.2 - 3.5.1 3.3.3 3.0.0 5.0.0 diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml index 20143af9f0..0237da7ece 100644 --- a/persistence-modules/java-jpa-3/pom.xml +++ b/persistence-modules/java-jpa-3/pom.xml @@ -88,7 +88,6 @@ 2.7.4 8.0.21 2.2 - 3.5.1 3.3.3 3.0.0 2.1.214 diff --git a/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java deleted file mode 100644 index 8591dd3a8d..0000000000 --- a/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.baeldung.neo4j; - - -import static org.neo4j.configuration.GraphDatabaseSettings.DEFAULT_DATABASE_NAME; - -import java.io.File; -import java.time.Duration; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.neo4j.configuration.GraphDatabaseSettings; -import org.neo4j.dbms.api.DatabaseManagementService; -import org.neo4j.dbms.api.DatabaseManagementServiceBuilder; -import org.neo4j.graphdb.GraphDatabaseService; -import org.neo4j.graphdb.Label; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.NotFoundException; -import org.neo4j.graphdb.RelationshipType; -import org.neo4j.graphdb.Result; -import org.neo4j.graphdb.Transaction; - -/** - * To run this test you will need to have an instance of the docker running on your machine (Docker desktop - for Windows and Docker instance for linux) - * After your docker instance is up run this test - */ -public class Neo4jLiveTest { - - private static GraphDatabaseService graphDb; - private static Transaction transaction; - private static DatabaseManagementService managementService; - - @Before - public void setUp() { - managementService = new DatabaseManagementServiceBuilder(new File("data/cars").toPath()) - .setConfig( GraphDatabaseSettings.transaction_timeout, Duration.ofSeconds( 60 ) ) - .setConfig( GraphDatabaseSettings.preallocate_logical_logs, false ).build(); - graphDb = managementService.database( DEFAULT_DATABASE_NAME ); - } - - @After - public void tearDown() { - managementService.shutdown(); - } - - @Test - public void testPersonCar() { - transaction = graphDb.beginTx(); - Node car = transaction.createNode(Label.label("Car")); - car.setProperty("make", "tesla"); - car.setProperty("model", "model3"); - - Node owner = transaction.createNode(Label.label("Person")); - owner.setProperty("firstName", "baeldung"); - owner.setProperty("lastName", "baeldung"); - - owner.createRelationshipTo(car, RelationshipType.withName("owner")); - - Result result = transaction.execute("MATCH (c:Car) <-[owner]- (p:Person) " + - "WHERE c.make = 'tesla'" + - "RETURN p.firstName, p.lastName"); - - Map firstResult = result.next(); - - Assert.assertEquals("baeldung", firstResult.get("p.firstName")); - } - - @Test - public void testCreateNode() { - transaction = graphDb.beginTx(); - Result result = transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"})" + - "RETURN baeldung"); - - Map firstResult = result.next(); - Node firstNode = (Node) firstResult.get("baeldung"); - - Assert.assertEquals(firstNode.getProperty("name"), "Baeldung"); - } - - @Test - public void testCreateNodeAndLink() { - transaction = graphDb.beginTx(); - Result result = transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - Map firstResult = result.next(); - - Assert.assertTrue(firstResult.containsKey("baeldung")); - Assert.assertTrue(firstResult.containsKey("tesla")); - } - - @Test - public void testFindAndReturn() { - transaction = graphDb.beginTx(); - transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - Result result = transaction.execute("MATCH (company:Company)-[:owns]-> (car:Car)" + - "WHERE car.make='tesla' and car.model='modelX'" + - "RETURN company.name"); - - Map firstResult = result.next(); - - Assert.assertEquals(firstResult.get("company.name"), "Baeldung"); - } - - @Test - public void testUpdate() { - transaction = graphDb.beginTx(); - transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - Result result = transaction.execute("MATCH (car:Car)" + - "WHERE car.make='tesla'" + - " SET car.milage=120" + - " SET car :Car:Electro" + - " SET car.model=NULL" + - " RETURN car"); - - Map firstResult = result.next(); - Node car = (Node) firstResult.get("car"); - - Assert.assertEquals(car.getProperty("milage"), 120L); - Assert.assertEquals(car.getLabels(), Arrays.asList(Label.label("Car"), Label.label("Electro"))); - - try { - car.getProperty("model"); - Assert.fail(); - } catch (NotFoundException e) { - // expected - } - } - - @Test - public void testDelete() { - transaction = graphDb.beginTx(); - transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - transaction.execute("MATCH (company:Company)" + - " WHERE company.name='Baeldung'" + - " DELETE company"); - - Result result = transaction.execute("MATCH (company:Company)" + - " WHERE company.name='Baeldung'" + - " RETURN company"); - - Assert.assertFalse(result.hasNext()); - } - - @Test - public void testBindings() { - transaction = graphDb.beginTx(); - Map params = new HashMap<>(); - params.put("name", "baeldung"); - params.put("make", "tesla"); - params.put("model", "modelS"); - - Result result = transaction.execute("CREATE (baeldung:Company {name:$name}) " + - "-[:owns]-> (tesla:Car {make: $make, model: $model})" + - "RETURN baeldung, tesla", params); - - Map firstResult = result.next(); - Assert.assertTrue(firstResult.containsKey("baeldung")); - Assert.assertTrue(firstResult.containsKey("tesla")); - - Node car = (Node) firstResult.get("tesla"); - Assert.assertEquals(car.getProperty("model"), "modelS"); - } -} diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 24a55491d3..eb4b212771 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -21,6 +21,7 @@ blaze-persistence core-java-persistence core-java-persistence-2 + couchbase elasticsearch flyway flyway-repair @@ -35,6 +36,7 @@ hibernate-queries hibernate-enterprise influxdb + java-cassandra java-cockroachdb java-jdbi java-jpa @@ -85,7 +87,7 @@ spring-data-jpa-query-3 spring-data-jpa-repo spring-data-jpa-repo-2 - spring-data-jpa-repo-4 + spring-data-jpa-repo-4 spring-data-jdbc spring-data-keyvalue spring-data-mongodb @@ -100,19 +102,24 @@ spring-data-shardingsphere + spring-hibernate-6 spring-jpa spring-jpa-2 spring-jdbc + spring-jdbc-2 spring-jooq spring-mybatis spring-persistence-simple spring-data-yugabytedb - fauna spring-data-rest java-mongodb questdb neo4j + rethinkdb + scylladb + spring-data-cassandra-2 + spring-data-jpa-repo-3 diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java similarity index 96% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java index 244959d854..0e6cdae2b4 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java @@ -10,7 +10,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating inserting data. */ -public class InsertIntegrationTest extends TestBase { +public class InsertIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java similarity index 97% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java index 263dda9bc6..626d15bcb6 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** * Some tests demonstrating querying data. */ -public class QueryIntegrationTest extends TestBase { +public class QueryIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java similarity index 98% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java index 4ca147cf68..bc105d2e4f 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java @@ -13,7 +13,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating streaming live changes to data. */ -public class StreamingIntegrationTest extends TestBase { +public class StreamingIntegrationLiveTest extends TestBase { @Test public void getLiveInserts() throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java similarity index 94% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java index d60e500373..7bffb189b3 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java @@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** * Some tests demonstrating working with tables. */ -public class TablesIntegrationTest extends TestBase { +public class TablesIntegrationLiveTest extends TestBase { @Test public void createTable() { diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java similarity index 96% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java index 39fad3a878..d47caa0b5e 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java @@ -8,7 +8,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating updating data. */ -public class UpdateIntegrationTest extends TestBase { +public class UpdateIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/spring-boot-persistence-4/pom.xml b/persistence-modules/spring-boot-persistence-4/pom.xml index 99c39e205d..7a6c2d2b17 100644 --- a/persistence-modules/spring-boot-persistence-4/pom.xml +++ b/persistence-modules/spring-boot-persistence-4/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.boot.persistence spring-boot-persistence-4 diff --git a/persistence-modules/spring-boot-persistence-h2/pom.xml b/persistence-modules/spring-boot-persistence-h2/pom.xml index f643db2260..3c4bf888b3 100644 --- a/persistence-modules/spring-boot-persistence-h2/pom.xml +++ b/persistence-modules/spring-boot-persistence-h2/pom.xml @@ -11,9 +11,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -44,12 +44,19 @@ db-util ${db-util.version} + + + + org.hibernate.orm + hibernate-core + 6.3.1.Final + com.baeldung.h2db.demo.server.SpringBootApp - 1.0.4 + 1.0.7 \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2/exceptions/models/User.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2/exceptions/models/User.java index e54e725fd0..e1ae3c7cf0 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2/exceptions/models/User.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2/exceptions/models/User.java @@ -1,7 +1,7 @@ package com.baeldung.h2.exceptions.models; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Entity public class User { diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java index 7402312e1c..3416cba154 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java @@ -3,15 +3,15 @@ package com.baeldung.h2db.demo.client; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; -import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.PropertySource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; +import jakarta.annotation.PostConstruct; + @SpringBootApplication @ComponentScan("com.baeldung.h2db.demo.client") public class ClientSpringBootApp { diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java index e75b42a934..2a1eb66b22 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java @@ -3,7 +3,7 @@ package com.baeldung.h2db.demo.server; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.h2.tools.Server; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/Document.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/Document.java index 9d69e7eb58..e737722ad4 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/Document.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/Document.java @@ -1,13 +1,14 @@ package com.baeldung.h2db.lazy_load_no_trans.entity; +import jakarta.persistence.Column; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.Immutable; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Entity @Getter @@ -22,5 +23,6 @@ public class Document { private String title; + @Column(name="user_id") private Long userId; } diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/User.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/User.java index ae9cb9e4e8..b46903e589 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/User.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/lazy_load_no_trans/entity/User.java @@ -8,10 +8,10 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.Immutable; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.OneToMany; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.List; diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/notnull/models/Item.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/notnull/models/Item.java index d2c4015b86..d36c763f0f 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/notnull/models/Item.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/notnull/models/Item.java @@ -1,9 +1,10 @@ package com.baeldung.h2db.notnull.models; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; + import java.math.BigDecimal; @Entity diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Country.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Country.java index d6edab9421..c8bec1e908 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Country.java +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/Country.java @@ -1,9 +1,9 @@ package com.baeldung.h2db.springboot.models; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import java.util.Objects; @Table(name = "countries") diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties index b030527cca..df322cd15e 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties index 972a7bb0f3..e5c488f3be 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/data-trans.sql b/persistence-modules/spring-boot-persistence-h2/src/main/resources/data-trans.sql index 2b4aa92542..7031d3ac02 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/data-trans.sql +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/data-trans.sql @@ -4,9 +4,9 @@ insert into "user" values (103, 'user3', 'comment3'); insert into "user" values (104, 'user4', 'comment4'); insert into "user" values (105, 'user5', 'comment5'); -insert into "document" values (1, 'doc1', 101); -insert into "document" values (2, 'doc2', 101); -insert into "document" values (3, 'doc3', 101); -insert into "document" values (4, 'doc4', 101); -insert into "document" values (5, 'doc5', 102); -insert into "document" values (6, 'doc6', 102); \ No newline at end of file +insert into "document" ("id","title","user_id") values (1, 'doc1', 101); +insert into "document" ("id","title","user_id") values (2, 'doc2', 101); +insert into "document" ("id","title","user_id") values (3, 'doc3', 101); +insert into "document" ("id","title","user_id") values (4, 'doc4', 101); +insert into "document" ("id","title","user_id") values (5, 'doc5', 102); +insert into "document" ("id","title","user_id") values (6, 'doc6', 102); \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/h2db/notnull/ItemIntegrationTest.java b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/h2db/notnull/ItemIntegrationTest.java index 0e2e5e3319..1213df4780 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/h2db/notnull/ItemIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/h2db/notnull/ItemIntegrationTest.java @@ -2,16 +2,17 @@ package com.baeldung.h2db.notnull; import com.baeldung.h2db.notnull.daos.ItemRepository; import com.baeldung.h2db.notnull.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; +import jakarta.validation.ConstraintViolationException; + @RunWith(SpringRunner.class) @SpringBootTest(classes = NotNullVsNullableApplication.class) public class ItemIntegrationTest { @@ -21,8 +22,8 @@ public class ItemIntegrationTest { @Test public void shouldNotAllowToPersistNullItemsPrice() { - assertThatThrownBy(() -> itemRepository.save(new Item())) - .hasRootCauseInstanceOf(ConstraintViolationException.class) - .hasStackTraceContaining("must not be null"); + assertThatThrownBy(() -> itemRepository.save(new Item())).hasRootCauseInstanceOf(ConstraintViolationException.class) + .hasStackTraceContaining("propertyPath=price") + .hasStackTraceContaining("null"); } } diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml index c48525673a..3f144bae54 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml +++ b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml @@ -9,27 +9,12 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 - - org.mongodb - mongodb-driver-sync - ${mongodb-driver.version} - - - org.mongodb - mongodb-driver-core - ${mongodb-driver.version} - - - org.mongodb - bson - ${mongodb-driver.version} - org.springframework.boot spring-boot-starter-web @@ -37,16 +22,6 @@ org.springframework.boot spring-boot-starter-data-mongodb - - - org.mongodb - mongodb-driver-sync - - - org.mongodb - mongodb-driver-core - - org.mongodb @@ -57,12 +32,13 @@ de.flapdoodle.embed de.flapdoodle.embed.mongo test + ${de.flapdoodle.embed.mongo.version} - 1.7.3 - 4.9.1 + com.baeldung.boot.atlassearch.MongoDbAtlasSearchApplication + 1.8.0 + 4.9.2 - diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java new file mode 100644 index 0000000000..afaf524829 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.atlassearch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MongoDbAtlasSearchApplication { + + public static void main(String... args) { + SpringApplication.run(MongoDbAtlasSearchApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java new file mode 100644 index 0000000000..cb4fae89e4 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.boot.atlassearch.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class IndexConfig { + + @Value("${com.baeldung.atlas-search.index.query}") + private String queryIndex; + + @Value("${com.baeldung.atlas-search.index.facet}") + private String facetIndex; + + public String getFacetIndex() { + return facetIndex; + } + + public String getQueryIndex() { + return queryIndex; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java new file mode 100644 index 0000000000..55d47759d5 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java @@ -0,0 +1,183 @@ +package com.baeldung.boot.atlassearch.service; + +import static com.mongodb.client.model.Aggregates.facet; +import static com.mongodb.client.model.Aggregates.limit; +import static com.mongodb.client.model.Aggregates.project; +import static com.mongodb.client.model.Aggregates.replaceWith; +import static com.mongodb.client.model.Aggregates.search; +import static com.mongodb.client.model.Aggregates.searchMeta; +import static com.mongodb.client.model.Aggregates.skip; +import static com.mongodb.client.model.Projections.excludeId; +import static com.mongodb.client.model.Projections.fields; +import static com.mongodb.client.model.Projections.include; +import static com.mongodb.client.model.Projections.metaSearchScore; +import static com.mongodb.client.model.search.SearchCount.total; +import static com.mongodb.client.model.search.SearchFacet.combineToBson; +import static com.mongodb.client.model.search.SearchFacet.numberFacet; +import static com.mongodb.client.model.search.SearchFacet.stringFacet; +import static com.mongodb.client.model.search.SearchOperator.compound; +import static com.mongodb.client.model.search.SearchOperator.numberRange; +import static com.mongodb.client.model.search.SearchOperator.of; +import static com.mongodb.client.model.search.SearchOperator.text; +import static com.mongodb.client.model.search.SearchOptions.searchOptions; +import static com.mongodb.client.model.search.SearchPath.fieldPath; +import static java.util.Arrays.asList; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.logging.log4j.LogManager; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.atlassearch.config.IndexConfig; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Facet; +import com.mongodb.client.model.search.SearchScore; + +@Service +public class MovieAtlasSearchService { + + @Autowired + private IndexConfig config; + + private final MongoCollection collection; + + public MovieAtlasSearchService(MongoTemplate mongoTemplate) { + MongoDatabase database = mongoTemplate.getDb(); + this.collection = database.getCollection("movies"); + } + + public static void debug(List pipeline) { + StringBuilder builder = new StringBuilder("["); + final AtomicBoolean first = new AtomicBoolean(true); + pipeline.forEach(stage -> { + builder.append((first.get() ? "" : ",") + + stage.toBsonDocument() + ); + + first.set(false); + }); + builder.append("]"); + + LogManager.getLogger(MovieAtlasSearchService.class) + .debug(builder.toString()); + } + + public Document late90sMovies(int skip, int limit, String keywords, SearchScore modifier) { + List pipeline = asList( + search( + compound() + .must(asList( + numberRange( + fieldPath("year")) + .gteLt(1995, 2000) + )) + .should(asList( + text( + fieldPath("fullplot"), keywords + ) + .score(modifier) + )), + searchOptions() + .index(config.getQueryIndex()) + ), + project(fields( + excludeId(), + include("title", "year", "fullplot", "imdb.rating"), + metaSearchScore("score") + )), + facet( + new Facet("rows", + skip(skip), + limit(limit) + ), + new Facet("totalRows", + replaceWith("$$SEARCH_META"), + limit(1) + ) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } + + public Document countLate90sMovies(String keywords) { + List pipeline = asList( + searchMeta( + compound() + .must(asList( + numberRange( + fieldPath("year")) + .gteLt(1995, 2000), + text( + fieldPath("fullplot"), keywords + ) + )), + searchOptions() + .index(config.getQueryIndex()) + .count(total()) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } + + public Collection moviesByKeywords(String keywords) { + List pipeline = asList( + search( + text( + fieldPath("fullplot"), keywords + ), + searchOptions() + .index(config.getQueryIndex()) + ), + project(fields( + excludeId(), + include("title", "year", "fullplot", "imdb.rating") + )) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .into(new ArrayList()); + } + + public Document genresThroughTheDecades(String genre) { + List pipeline = asList( + searchMeta(of( + new Document("facet", + new Document("operator", + text( + fieldPath("genres"), genre + ) + ).append("facets", combineToBson(asList( + stringFacet("genresFacet", + fieldPath("genres") + ).numBuckets(5), + numberFacet("yearFacet", + fieldPath("year"), + asList(1900, 1930, 1960, 1990, 2020) + ) + ))) + )), + searchOptions() + .index(config.getFacetIndex()) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java new file mode 100644 index 0000000000..4c41915347 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.atlassearch.web; + +import java.util.Collection; + +import org.bson.Document; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.atlassearch.service.MovieAtlasSearchService; +import com.mongodb.client.model.search.SearchScore; + +@RestController +@RequestMapping("/movies") +public class MovieAtlasSearchController { + + @Autowired + private MovieAtlasSearchService service; + + @GetMapping("with/{keywords}") + Collection getMoviesWithKeywords(@PathVariable String keywords) { + return service.moviesByKeywords(keywords); + } + + @GetMapping("90s/with/{keywords}/count") + Document getCount90sMoviesWithKeywords(@PathVariable String keywords) { + return service.countLate90sMovies(keywords); + } + + @GetMapping("90s/{skip}/{limit}/with/{keywords}") + Document getMoviesUsingScoreBoost(@PathVariable int skip, @PathVariable int limit, @PathVariable String keywords) { + return service.late90sMovies(skip, limit, keywords, SearchScore.boost(2)); + } + + @PostMapping("90s/{skip}/{limit}/with/{keywords}") + Document getMoviesUsingScoringFunction(@RequestBody String jsonFunction, @PathVariable int skip, @PathVariable int limit, @PathVariable String keywords) { + return service.late90sMovies(skip, limit, keywords, SearchScore.of(new Document("function", Document.parse(jsonFunction)))); + } + + @GetMapping("by-genre/{genre}") + Document getMoviesWithFacets(@PathVariable String genre) { + return service.genresThroughTheDecades(genre); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties index 8309c4461f..02ba79e336 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties @@ -1 +1,4 @@ spring.application.name=spring-boot-persistence-mongodb-3 + +com.baeldung.atlas-search.index.query=idx-queries +com.baeldung.atlas-search.index.facet=idx-facets \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java new file mode 100644 index 0000000000..190ebc19d9 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java @@ -0,0 +1,67 @@ +package com.baeldung.boot.atlassearch; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.bson.Document; +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.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.atlassearch.service.MovieAtlasSearchService; +import com.mongodb.client.model.search.SearchScore; + +@DirtiesContext +@RunWith(SpringRunner.class) +@TestPropertySource("/embedded.properties") +@SpringBootTest(classes = MongoDbAtlasSearchApplication.class) +public class MovieAtlasSearchServiceLiveTest { + + @Autowired + private MovieAtlasSearchService service; + + @Test + public void givenScoreBoost_thenFirstItemContainsPlot() { + final String plot = "space"; + + Document movies = service.late90sMovies(0, 1, plot, SearchScore.boost(2)); + + assertTrue(movies.getList("rows", Document.class) + .iterator() + .next() + .getString("fullplot") + .contains(plot)); + } + + @Test + public void givenFacetOperator_thenCorrespondingBucketsReturned() { + final String genre = "Sci-Fi"; + + Document meta = service.genresThroughTheDecades(genre); + + Long lowerBound = meta + .get("count", Document.class) + .getLong("lowerBound"); + + Document genresFacetFirstBucket = meta.get("facet", Document.class) + .get("genresFacet", Document.class) + .getList("buckets", Document.class) + .iterator() + .next(); + + Document yearFacetFirstBucket = meta.get("facet", Document.class) + .get("yearFacet", Document.class) + .getList("buckets", Document.class) + .iterator() + .next(); + + assertEquals(lowerBound, genresFacetFirstBucket.getLong("count")); + assertEquals(genre, genresFacetFirstBucket.getString("_id")); + assertNotNull(yearFacetFirstBucket); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties index cd1c1d43c7..f47eca5023 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties @@ -1,4 +1,4 @@ -spring.mongodb.embedded.version=4.4.9 +spring.mongodb.embedded.version=4.9.2 #spring.data.mongodb.uri=changeit #spring.data.mongodb.database=changeit diff --git a/persistence-modules/spring-boot-persistence/pom.xml b/persistence-modules/spring-boot-persistence/pom.xml index 58b4dd8b9e..3c77386ddd 100644 --- a/persistence-modules/spring-boot-persistence/pom.xml +++ b/persistence-modules/spring-boot-persistence/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -49,10 +49,7 @@ mysql mysql-connector-java - - - javax.validation - validation-api + ${mysql-connector-java.version} org.xerial @@ -66,11 +63,17 @@ org.hsqldb hsqldb + + jakarta.validation + jakarta.validation-api + 2.23.0 2.0.1.Final + 8.0.31 + com.baeldung.boot.Application \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java index d3a09c08ff..96cb9ae975 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java @@ -13,7 +13,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java index 736c12fb07..ba75269c29 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java @@ -1,8 +1,8 @@ package com.baeldung.boot.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; /** * @author paullatzelsperger diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java index 59227f6412..fcea52221f 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java @@ -1,11 +1,11 @@ package com.baeldung.boot.domain; -import static javax.persistence.GenerationType.IDENTITY; +import static jakarta.persistence.GenerationType.IDENTITY; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; @Entity public class Country { diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Employee.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Employee.java index 07e69a6f62..cef959fbfd 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Employee.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Employee.java @@ -1,9 +1,9 @@ package com.baeldung.boot.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; /** * @author harshavs diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/GenericEntity.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/GenericEntity.java index a2a676200a..ba38aadeef 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/GenericEntity.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/GenericEntity.java @@ -1,9 +1,9 @@ package com.baeldung.boot.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class GenericEntity { diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java index bdbe75cd0c..a5a6fb0160 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java @@ -1,9 +1,9 @@ package com.baeldung.boot.domain; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "users") diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java index 00e90a5ec9..cef2241cdd 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java @@ -1,9 +1,9 @@ package com.baeldung.boot.naming.entity; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.OneToMany; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.util.List; @Entity diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java index 7711156864..3bbe0069a8 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java @@ -1,8 +1,8 @@ package com.baeldung.boot.naming.entity; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.ManyToOne; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; @Entity public class Preference { diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dataloading/model/Country.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dataloading/model/Country.java index 692d48caf0..db5b242e69 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dataloading/model/Country.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dataloading/model/Country.java @@ -1,11 +1,11 @@ package com.baeldung.dataloading.model; -import static javax.persistence.GenerationType.IDENTITY; +import static jakarta.persistence.GenerationType.IDENTITY; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; @Entity public class Country { diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/controllers/UserController.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/controllers/UserController.java index c55f1083ba..afc548f700 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/controllers/UserController.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/controllers/UserController.java @@ -2,7 +2,7 @@ package com.baeldung.springbootcrudapp.application.controllers; import com.baeldung.springbootcrudapp.application.repositories.UserRepository; import com.baeldung.springbootcrudapp.application.entities.User; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/entities/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/entities/User.java index 145f251158..4120c505a6 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/entities/User.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootcrudapp/application/entities/User.java @@ -1,10 +1,10 @@ package com.baeldung.springbootcrudapp.application.entities; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.validation.constraints.NotBlank; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotBlank; @Entity public class User { diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootdatasourceconfig/application/entities/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootdatasourceconfig/application/entities/User.java index 84a9ae74ff..e35879fdd2 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootdatasourceconfig/application/entities/User.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springbootdatasourceconfig/application/entities/User.java @@ -1,10 +1,10 @@ package com.baeldung.springbootdatasourceconfig.application.entities; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "users") diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java index 7562c072c7..5afc55a09b 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java @@ -1,8 +1,8 @@ package com.baeldung.springboothibernate.application.models; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; @Entity public class Book { diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java index 2feee10980..2922bb9167 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java @@ -35,13 +35,13 @@ public class LegacyJpaImplNamingIntegrationTest extends NamingConfig { String tableNameCreated = table.getName(); boolean columnNameIsQuoted = table - .getColumn(3) + .getColumn(2) .isQuoted(); String physicalNameCreated = table - .getColumn(3) + .getColumn(2) .getName(); String implicitNameCreated = table - .getColumn(2) + .getColumn(3) .getName(); SoftAssertions.assertSoftly(softly -> { diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java index c5c320f70c..4fb13a1798 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java @@ -16,10 +16,6 @@ import com.baeldung.boot.naming.entity.Account; @RunWith(SpringRunner.class) @DataJpaTest -@TestPropertySource(properties = { - "spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy", - "spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" -}) @Import(Config.class) public class SpringBootDefaultNamingIntegrationTest extends NamingConfig { diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java index ef978e5a98..8269e6c34a 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java @@ -1,6 +1,5 @@ package com.baeldung.boot.naming; -import com.baeldung.boot.naming.MetadataExtractorIntegrator; import com.baeldung.boot.naming.NamingConfig.Config; import com.baeldung.boot.naming.entity.Preference; @@ -47,7 +46,7 @@ public class StrategyLegacyHbmImplIntegrationTest extends NamingConfig { String implicitNameExpected = "account"; String implicitNameCreated = preferenceTable - .getColumn(3) + .getColumn(1) .getName(); String tableNameCreated = accountPreferencesTable.getName(); diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java index 515350fe0a..2a90f36a7c 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java @@ -12,7 +12,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; diff --git a/persistence-modules/spring-data-cassandra-2/README.md b/persistence-modules/spring-data-cassandra-2/README.md index 3f49d6ae93..0578dcc429 100644 --- a/persistence-modules/spring-data-cassandra-2/README.md +++ b/persistence-modules/spring-data-cassandra-2/README.md @@ -2,3 +2,4 @@ - [Using Test Containers With Spring Data Cassandra](https://www.baeldung.com/spring-data-cassandra-test-containers) - [Cassandra – Object Mapping with DataStax Java Driver](https://www.baeldung.com/cassandra-object-mapping-datastax-java-driver) +- [Query With IN Clause in Spring Data Cassandra](https://www.baeldung.com/spring-cassandra-query-in-clause) diff --git a/persistence-modules/spring-data-cassandra-2/pom.xml b/persistence-modules/spring-data-cassandra-2/pom.xml index 740c04d2a0..01b5ce5ed6 100644 --- a/persistence-modules/spring-data-cassandra-2/pom.xml +++ b/persistence-modules/spring-data-cassandra-2/pom.xml @@ -65,6 +65,18 @@ java-driver-mapper-runtime 4.15.0 + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + @@ -88,10 +100,10 @@ 11 - 3.1.11 - 1.15.3 + 3.4.15 + 1.19.0 1.1.0 - 5.6.2 + 5.9.3 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java similarity index 56% rename from spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java rename to persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java index a7967c73cb..ecc50cbf40 100644 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java @@ -1,12 +1,12 @@ -package com.baeldung.listvalidation; - +package org.baeldung.cassandra.inquery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class SpringJobApplicationDemoApp { +public class CassandraApplication { + public static void main(String[] args) { - SpringApplication.run(SpringJobApplicationDemoApp.class, args); + SpringApplication.run(CassandraApplication.class, args); } } diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java new file mode 100644 index 0000000000..c9007e8405 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java @@ -0,0 +1,49 @@ +package org.baeldung.cassandra.inquery.model; + +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; +import org.springframework.data.cassandra.core.mapping.Column; +import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.core.mapping.Table; + +import java.util.Objects; +import java.util.UUID; + +@Table +public class Product { + + @PrimaryKeyColumn(name = "product_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED) + private UUID productId; + + @PrimaryKeyColumn(name = "product_name", ordinal = 1, type = PrimaryKeyType.CLUSTERED) + private String productName; + + @Column("description") + private String description; + + @Column("price") + private double price; + + public Product(UUID productId, String productName, String description, double price) { + this.productId = productId; + this.productName = productName; + this.description = description; + this.price = price; + } + + public String getProductName() { + return productName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Product product = (Product) o; + return productId.equals(product.productId) && productName.equals(product.productName); + } + + @Override + public int hashCode() { + return Objects.hash(productId, productName); + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java new file mode 100644 index 0000000000..176ca4d786 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java @@ -0,0 +1,20 @@ +package org.baeldung.cassandra.inquery.repository; + +import org.baeldung.cassandra.inquery.model.Product; +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.data.cassandra.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; + +@Repository +public interface ProductRepository extends CassandraRepository { + + @Query("select * from product where product_id in :productIds") + List findByProductIds(@Param("productIds") List productIds); + + @Query("select * from product where product_id = :productId and product_name in :productNames") + List findByProductIdAndNames(@Param("productId") UUID productId, @Param("productNames") List productNames); +} diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java new file mode 100644 index 0000000000..3d99782afd --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java @@ -0,0 +1,117 @@ +package org.baeldung.cassandra.inquery; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.utils.UUIDs; +import org.baeldung.cassandra.inquery.model.Product; +import org.baeldung.cassandra.inquery.repository.ProductRepository; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +/** + * This live test requires a running Docker instance so that a Cassandra container can be created + */ +@Testcontainers +@SpringBootTest +class ProductRepositoryNestedLiveTest { + + private static final String KEYSPACE_NAME = "mynamespace"; + + @Container + private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2") + .withExposedPorts(9042); + + @BeforeAll + static void setupCassandraConnectionProperties() { + System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME); + System.setProperty("spring.data.cassandra.contact-points", cassandra.getHost()); + System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042))); + createKeyspace(cassandra.getCluster()); + } + + static void createKeyspace(Cluster cluster) { + try (Session session = cluster.connect()) { + session.execute("CREATE KEYSPACE IF NOT EXISTS " + KEYSPACE_NAME + " WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};"); + } + } + + @Nested + class ApplicationContextLiveTest { + @Test + void givenCassandraContainer_whenSpringContextIsBootstrapped_thenContainerIsRunningWithNoExceptions() { + assertThat(cassandra.isRunning()).isTrue(); + } + } + + @Nested + class ProductRepositoryLiveTest { + + @Autowired + private ProductRepository productRepository; + + @Test + void givenValidProductsIsFetched_whenFindByProductIdsIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + UUID productId3 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId2, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId3, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId3, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product3, product4)); + + List existingProducts = productRepository.findByProductIds(List.of(productId1, productId2)); + assertEquals(2, existingProducts.size()); + assertTrue(existingProducts.contains(product1)); + assertTrue(existingProducts.contains(product2)); + } + + @Test + void givenExistingProducts_whenFindByIdAndNamesIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId1, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId2, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId2, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product3, product4)); + + List existingProducts = productRepository.findByProductIdAndNames(productId1, + List.of(product1.getProductName(), product2.getProductName())); + assertEquals(2, existingProducts.size()); + assertTrue(existingProducts.contains(product1)); + assertTrue(existingProducts.contains(product2)); + } + + @Test + void givenNonExistingProductName_whenFindByIdAndNamesIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId1, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId2, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId2, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product4)); + + List existingProducts = productRepository.findByProductIdAndNames(productId1, + List.of(product3.getProductName())); + assertEquals(0, existingProducts.size()); + } + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java index b61663d622..50681d36c5 100644 --- a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java @@ -1,7 +1,8 @@ package org.baeldung.objectmapper; -import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.api.core.CqlSession; +import java.net.InetSocketAddress; +import java.util.List; + import org.baeldung.objectmapper.dao.CounterDao; import org.baeldung.objectmapper.dao.UserDao; import org.baeldung.objectmapper.entity.Counter; @@ -14,7 +15,8 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.List; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; @Testcontainers @SpringBootTest @@ -23,35 +25,30 @@ public class MapperLiveTest { private static final String KEYSPACE_NAME = "baeldung"; @Container - private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2") - .withExposedPorts(9042); + private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2").withExposedPorts(9042); + @BeforeAll static void setupCassandraConnectionProperties() { System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME); - System.setProperty("spring.data.cassandra.contact-points", cassandra.getContainerIpAddress()); + System.setProperty("spring.data.cassandra.contact-points", cassandra.getHost()); System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042))); + setupCassandra(new InetSocketAddress(cassandra.getHost(), cassandra.getMappedPort(9042)), cassandra.getLocalDatacenter()); } static UserDao userDao; static CounterDao counterDao; - @BeforeAll - static void setup() { - setupCassandraConnectionProperties(); - CqlSession session = CqlSession.builder().build(); + static void setupCassandra(InetSocketAddress cassandraEndpoint, String localDataCenter) { + CqlSession session = CqlSession.builder() + .withLocalDatacenter(localDataCenter) + .addContactPoint(cassandraEndpoint) + .build(); - String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + - "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; + String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; String useKeyspace = "USE baeldung;"; - String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + - "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + - "(id int, username text, user_age int, role text, writetime bigint, department text, " + - "PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createCounter = "CREATE TABLE IF NOT EXISTS counter " + - "(id text, count counter, PRIMARY KEY (id));"; + String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + "(id int, username text, user_age int, role text, writetime bigint, department text, " + "PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createCounter = "CREATE TABLE IF NOT EXISTS counter " + "(id text, count counter, PRIMARY KEY (id));"; session.execute(createKeyspace); session.execute(useKeyspace); @@ -75,22 +72,25 @@ public class MapperLiveTest { @Test void givenCounter_whenIncrement_thenIncremented() { Counter users = counterDao.getCounterById("users"); - long initialCount = users != null ? users.getCount(): 0; + long initialCount = users != null ? users.getCount() : 0; counterDao.incrementCounter("users", 1); users = counterDao.getCounterById("users"); - long finalCount = users != null ? users.getCount(): 0; + long finalCount = users != null ? users.getCount() : 0; Assertions.assertEquals(finalCount - initialCount, 1); } @Test void givenUser_whenGetUsersOlderThan_thenRetrieved() { - User user = new User(2, "JaneDoe", 20); + User user = new User(2, "JaneDoe", 32); + User userTwo = new User(3, "JohnDoe", 20); userDao.insertUser(user); - List retrievedUsers = userDao.getUsersOlderThanAge(30).all(); - Assertions.assertEquals(retrievedUsers.size(), 1); + userDao.insertUser(userTwo); + List retrievedUsers = userDao.getUsersOlderThanAge(30) + .all(); + Assertions.assertEquals(1, retrievedUsers.size()); } } \ No newline at end of file diff --git a/persistence-modules/spring-data-couchbase-2/src/test/docker/Dockerfile b/persistence-modules/spring-data-couchbase-2/src/test/docker/Dockerfile new file mode 100644 index 0000000000..1dffcb31f1 --- /dev/null +++ b/persistence-modules/spring-data-couchbase-2/src/test/docker/Dockerfile @@ -0,0 +1,4 @@ +FROM couchbase/server:community-5.0.1 + +COPY configure.sh /configure.sh +CMD ["/configure.sh"] \ No newline at end of file diff --git a/persistence-modules/spring-data-couchbase-2/src/test/docker/configure.sh b/persistence-modules/spring-data-couchbase-2/src/test/docker/configure.sh new file mode 100644 index 0000000000..c2b62dba7c --- /dev/null +++ b/persistence-modules/spring-data-couchbase-2/src/test/docker/configure.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +function retry() { + for i in $(seq 1 10); do + $1 "$2" + if [[ $? == 0 ]]; then + return 0 + fi + sleep 1 + done + return 1 +} + +function bucketCreate(){ + couchbase-cli bucket-create -c localhost -u Administrator -p password \ + --bucket="$1" \ + --bucket-type=couchbase \ + --bucket-ramsize=512 \ + --bucket-replica=1 \ + --wait + if [[ $? != 0 ]]; then + return 1 + fi +} + +function userCreate(){ + createOutput=$(couchbase-cli user-manage -c localhost -u Administrator -p password \ + --set --rbac-username "$1" --rbac-password "$1" \ + --roles admin --auth-domain local) + if [[ $? != 0 ]]; then + echo $createOutput >&2 + return 1 + fi +} + +function clusterUp(){ + # wait for service to come up + until $(curl --output /dev/null --silent --head --fail http://localhost:8091); do + printf '.' + sleep 1 + done + + # initialize cluster + initOutput=$(couchbase-cli cluster-init -c localhost \ + --cluster-username=Administrator \ + --cluster-password=password \ + --cluster-port=8091 \ + --services=data,index,query,fts \ + --cluster-ramsize=1024 \ + --cluster-index-ramsize=256 \ + --cluster-fts-ramsize=256 \ + --index-storage-setting=default) + if [[ $? != 0 ]]; then + echo $initOutput >&2 + return 1 + fi +} + +function main(){ + set -ex + echo "Couchbase UI :8091" + echo "Couchbase logs /opt/couchbase/var/lib/couchbase/logs" + ./entrypoint.sh couchbase-server & + if [[ $? != 0 ]]; then + echo "Couchbase startup failed. Exiting." >&2 + exit 1 + fi + + clusterUp + if [[ $? != 0 ]]; then + echo "Cluster init failed. Exiting." >&2 + exit 1 + fi + + retry userCreate baeldung + if [[ $? != 0 ]]; then + echo "User create failed. Exiting." >&2 + exit 1 + fi + + retry userCreate baeldung2 + if [[ $? != 0 ]]; then + echo "User create failed. Exiting." >&2 + exit 1 + fi + + retry bucketCreate baeldung + if [[ $? != 0 ]]; then + echo "Bucket create failed. Exiting." >&2 + exit 1 + fi + + retry bucketCreate baeldung2 + if [[ $? != 0 ]]; then + echo "Bucket create failed. Exiting." >&2 + exit 1 + fi + + set +ex + + # entrypoint.sh launches the server but since config.sh is pid 1 we keep it + # running so that the docker container does not exit. + wait +} + +main \ No newline at end of file diff --git a/persistence-modules/spring-data-couchbase-2/src/test/docker/dockerbuild.sh b/persistence-modules/spring-data-couchbase-2/src/test/docker/dockerbuild.sh new file mode 100644 index 0000000000..37add165c6 --- /dev/null +++ b/persistence-modules/spring-data-couchbase-2/src/test/docker/dockerbuild.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# setup +set -ex +docker rm couchbase_container -f + +# main +docker build -t couchbase_image . + +# cleanup +set +ex + +# run +docker run -d --name couchbase_container -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase_image diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/SpringContextLiveTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/SpringContextLiveTest.java index 553520e6e6..74dccbadd0 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/SpringContextLiveTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/SpringContextLiveTest.java @@ -12,16 +12,10 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution /** * This LiveTest requires: * - * 1- Couchbase instance running (e.g. with `docker run -d --name db -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase`) - * - * - * 2- Couchbase configured with (we can use the console in localhost:8091): - * - * 2.1- Buckets: named 'baeldung' and 'baeldung2' - * - * 2.2- Security: users 'baeldung' and 'baeldung2'. Note: in newer versions an empty password is not allowed, then we have to change the passwords in the project) - * - * 2.3- Spacial View: Add new spacial view (in Index tab) in document 'campus_spatial', view 'byLocation' with the following function: + * 1- Couchbase 5 instance Running and Configured. + * It's enough to execute the "dockerbuild.sh" script in the test/docker folder. + * + * 2.1- Spacial View: Add new spacial view (in Index tab) in document 'campus_spatial', view 'byLocation' with the following function: * {@code * function (doc) { * if (doc.location && @@ -30,8 +24,9 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution * } * }} * - * 2.4- MapReduce Views: Add new views in document 'campus': - * 2.4.1- view 'all' with function: + * 2.2- MapReduce Views: Add new views in document 'campus': + * + * 2.2.1- view 'all' with function: * {@code * function (doc, meta) { * if(doc._class == "com.baeldung.spring.data.couchbase.model.Campus") { @@ -39,7 +34,7 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution * } * }} * - * 2.4.2- view 'byName' with function: + * 2.2.2- view 'byName' with function: * {@code * function (doc, meta) { * if(doc._class == "com.baeldung.spring.data.couchbase.model.Campus" && diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/CustomTypeKeyCouchbaseConfig.java b/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/CustomTypeKeyCouchbaseConfig.java deleted file mode 100644 index eacecb4e1e..0000000000 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/CustomTypeKeyCouchbaseConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.spring.data.couchbase; - -import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; - -public class CustomTypeKeyCouchbaseConfig extends MyCouchbaseConfig { - - @Override - public String getConnectionString() { - return NODE_LIST; - } - - @Override - public String getUserName() { - return BUCKET_USERNAME; - } - - @Override - public String getPassword() { - return BUCKET_PASSWORD; - } - - @Override - public String typeKey() { - return MappingCouchbaseConverter.TYPEKEY_SYNCGATEWAY_COMPATIBLE; - } -} diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/ReadYourOwnWritesCouchbaseConfig.java b/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/ReadYourOwnWritesCouchbaseConfig.java deleted file mode 100644 index 33a6c4f091..0000000000 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/com/baeldung/spring/data/couchbase/ReadYourOwnWritesCouchbaseConfig.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.baeldung.spring.data.couchbase; - -import com.couchbase.client.java.query.QueryScanConsistency; - -public class ReadYourOwnWritesCouchbaseConfig extends MyCouchbaseConfig { - - @Override - public QueryScanConsistency getDefaultConsistency() { - return QueryScanConsistency.REQUEST_PLUS; - } -} diff --git a/persistence-modules/spring-data-elasticsearch/pom.xml b/persistence-modules/spring-data-elasticsearch/pom.xml index 8e5e8ab7c7..6535b9ac4b 100644 --- a/persistence-modules/spring-data-elasticsearch/pom.xml +++ b/persistence-modules/spring-data-elasticsearch/pom.xml @@ -8,77 +8,58 @@ com.baeldung - parent-spring-5 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-spring-5 + ../../parent-boot-3 - - org.springframework - spring-web - ${spring.version} - org.springframework.data spring-data-elasticsearch ${spring-data-elasticsearch.version} - - org.elasticsearch - elasticsearch - ${elasticsearch.version} - - - com.alibaba - fastjson - ${fastjson.version} - + + + + + + + + + + + + org.elasticsearch.client elasticsearch-rest-high-level-client 7.17.11 - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - org.projectlombok lombok 1.18.28 - org.locationtech.spatial4j - spatial4j - ${spatial4j.version} - - - org.locationtech.jts - jts-core - ${jts.version} - - - xerces - xercesImpl - - - - - org.springframework - spring-test - ${spring.version} - test + org.springframework.boot + spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-maven-plugin + + + + 5.1.2 8.9.0 - 2.0.37 - 0.8 - 1.18.2 2.15.2 diff --git a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..c95b7cb5cb --- /dev/null +++ b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/Application.java @@ -0,0 +1,12 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Location.java b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Location.java new file mode 100644 index 0000000000..cdc8f8b255 --- /dev/null +++ b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Location.java @@ -0,0 +1,16 @@ +package com.baeldung.elasticsearch; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Location { + + private String name; + private List location; +} diff --git a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java index d51d1a0576..9a01af84e7 100644 --- a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java +++ b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java @@ -12,8 +12,6 @@ import java.util.Date; public class Person { private int age; - private String fullName; - private Date dateOfBirth; } diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java index 0d4117c75e..e0656db04e 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java @@ -15,18 +15,18 @@ import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.rest_client.RestClientTransport; import lombok.extern.slf4j.Slf4j; + import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; -import org.junit.Before; -import org.junit.Test; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.StringReader; import java.util.Date; import java.util.List; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * This Manual test requires: Elasticsearch instance running on localhost:9200. @@ -35,41 +35,35 @@ import static org.junit.Assert.assertEquals; * docker run -d --name elastic-test -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:8.9.0 */ @Slf4j -@Disabled("Manual test") public class ElasticSearchManualTest { private ElasticsearchClient client = null; - @Before + @BeforeEach public void setUp() throws IOException { - RestClient restClient = RestClient - .builder(HttpHost.create("http://localhost:9200")) - .build(); + RestClient restClient = RestClient.builder(HttpHost.create("http://localhost:9200")) + .build(); ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); client = new ElasticsearchClient(transport); Person person1 = new Person(10, "John Doe", new Date()); Person person2 = new Person(25, "Janette Doe", new Date()); Person person3 = new Person(8, "Mark Doe", new Date()); - client.index(builder -> builder - .index("person") - .id(person1.getFullName()) - .document(person1)); - client.index(builder -> builder - .index("person") - .id(person2.getFullName()) - .document(person2)); - client.index(builder -> builder - .index("person") - .id(person3.getFullName()) - .document(person3)); + client.index(builder -> builder.index("person") + .id(person1.getFullName()) + .document(person1)); + client.index(builder -> builder.index("person") + .id(person2.getFullName()) + .document(person2)); + client.index(builder -> builder.index("person") + .id(person3.getFullName()) + .document(person3)); } @Test public void givenJsonDocument_whenJavaObject_thenIndexDocument() throws Exception { Person person = new Person(20, "Mark Doe", new Date(1471466076564L)); - IndexResponse response = client.index(i -> i - .index("person") - .id(person.getFullName()) - .document(person)); + IndexResponse response = client.index(i -> i.index("person") + .id(person.getFullName()) + .document(person)); log.info("Indexed with version: {}", response.version()); assertEquals(Result.Created, response.result()); @@ -81,10 +75,9 @@ public class ElasticSearchManualTest { public void givenJsonString_whenJavaObject_thenIndexDocument() throws Exception { String jsonString = "{\"age\":10,\"dateOfBirth\":1471466076564,\"fullName\":\"John Doe\"}"; StringReader stringReader = new StringReader(jsonString); - IndexResponse response = client.index(i -> i - .index("person") - .id("John Doe") - .withJson(stringReader)); + IndexResponse response = client.index(i -> i.index("person") + .id("John Doe") + .withJson(stringReader)); log.info("Indexed with version: {}", response.version()); assertEquals("person", response.index()); assertEquals("John Doe", response.id()); @@ -93,9 +86,8 @@ public class ElasticSearchManualTest { @Test public void givenDocumentId_whenJavaObject_thenDeleteDocument() throws Exception { String documentId = "Mark Doe"; - DeleteResponse response = client.delete(i -> i - .index("person") - .id(documentId)); + DeleteResponse response = client.delete(i -> i.index("person") + .id(documentId)); assertEquals(Result.Deleted, response.result()); assertEquals("Mark Doe", response.id()); } @@ -103,24 +95,23 @@ public class ElasticSearchManualTest { @Test public void givenSearchRequest_whenMatch_thenReturnAllResults() throws Exception { String searchText = "John"; - SearchResponse searchResponse = client.search(s -> s - .index("person") - .query(q -> q - .match(t -> t - .field("fullName") - .query(searchText))), Person.class); + SearchResponse searchResponse = client.search(s -> s.index("person") + .query(q -> q.match(t -> t.field("fullName") + .query(searchText))), Person.class); - List> hits = searchResponse.hits().hits(); + List> hits = searchResponse.hits() + .hits(); assertEquals(1, hits.size()); - assertEquals("John Doe", hits.get(0).source().getFullName()); + assertEquals("John Doe", hits.get(0) + .source() + .getFullName()); } @Test public void givenGetRequest_whenMatch_thenReturnAllResults() throws IOException { String documentId = "John Doe"; - GetResponse getResponse = client.get(s -> s - .index("person") - .id(documentId), Person.class); + GetResponse getResponse = client.get(s -> s.index("person") + .id(documentId), Person.class); Person source = getResponse.source(); assertEquals("John Doe", source.getFullName()); } @@ -128,47 +119,58 @@ public class ElasticSearchManualTest { @Test public void givenSearchRequest_whenMatchAndRange_thenReturnAllResults() throws Exception { String searchText = "John"; - SearchResponse searchResponse = client.search(s -> s - .index("person") - .query(q -> q - .match(t -> t - .field("fullName").query(searchText))) - .query(q -> q - .range(range -> range - .field("age").from("1").to("10"))), - Person.class); + SearchResponse searchResponse = client.search(s -> s.index("person") + .query(q -> q.match(t -> t.field("fullName") + .query(searchText))) + .query(q -> q.range(range -> range.field("age") + .from("1") + .to("10"))), Person.class); - List> hits = searchResponse.hits().hits(); + List> hits = searchResponse.hits() + .hits(); assertEquals(1, hits.size()); - assertEquals("John Doe", hits.get(0).source().getFullName()); + assertEquals("John Doe", hits.get(0) + .source() + .getFullName()); } - @Test public void givenMultipleQueries_thenReturnResults() throws Exception { - Query ageQuery = RangeQuery.of(r -> r.field("age").from("5").to("15"))._toQuery(); - SearchResponse response1 = client.search(s -> s.query(q -> q.bool(b -> b - .must(ageQuery))), Person.class); - response1.hits().hits().forEach(hit -> log.info("Response 1: {}", hit.source())); + Query ageQuery = RangeQuery.of(r -> r.field("age") + .from("5") + .to("15")) + ._toQuery(); + SearchResponse response1 = client.search(s -> s.query(q -> q.bool(b -> b.must(ageQuery))), Person.class); + response1.hits() + .hits() + .forEach(hit -> log.info("Response 1: {}", hit.source())); - Query fullNameQuery = MatchQuery.of(m -> m.field("fullName").query("John"))._toQuery(); - SearchResponse response2 = client.search(s -> s.query(q -> q.bool(b -> b - .must(fullNameQuery))), Person.class); - response2.hits().hits().forEach(hit -> log.info("Response 2: {}", hit.source())); - Query doeContainsQuery = SimpleQueryStringQuery.of(q -> q.query("*Doe"))._toQuery(); - SearchResponse response3 = client.search(s -> s.query(q -> q.bool(b -> b - .must(doeContainsQuery))), Person.class); - response3.hits().hits().forEach(hit -> log.info("Response 3: {}", hit.source())); + Query fullNameQuery = MatchQuery.of(m -> m.field("fullName") + .query("John")) + ._toQuery(); + SearchResponse response2 = client.search(s -> s.query(q -> q.bool(b -> b.must(fullNameQuery))), Person.class); + response2.hits() + .hits() + .forEach(hit -> log.info("Response 2: {}", hit.source())); + Query doeContainsQuery = SimpleQueryStringQuery.of(q -> q.query("*Doe")) + ._toQuery(); + SearchResponse response3 = client.search(s -> s.query(q -> q.bool(b -> b.must(doeContainsQuery))), Person.class); + response3.hits() + .hits() + .forEach(hit -> log.info("Response 3: {}", hit.source())); - Query simpleStringQuery = SimpleQueryStringQuery.of(q -> q.query("+John -Doe OR Janette"))._toQuery(); - SearchResponse response4 = client.search(s -> s.query(q -> q.bool(b -> b - .must(simpleStringQuery))), Person.class); - response4.hits().hits().forEach(hit -> log.info("Response 4: {}", hit.source())); + Query simpleStringQuery = SimpleQueryStringQuery.of(q -> q.query("+John -Doe OR Janette")) + ._toQuery(); + SearchResponse response4 = client.search(s -> s.query(q -> q.bool(b -> b.must(simpleStringQuery))), Person.class); + response4.hits() + .hits() + .forEach(hit -> log.info("Response 4: {}", hit.source())); - SearchResponse response5 = client.search(s -> s.query(q -> q.bool(b -> b - .must(ageQuery) - .must(fullNameQuery) - .must(simpleStringQuery))), Person.class); - response5.hits().hits().forEach(hit -> log.info("Response 5: {}", hit.source())); + SearchResponse response5 = client.search(s -> s.query(q -> q.bool(b -> b.must(ageQuery) + .must(fullNameQuery) + .must(simpleStringQuery))), Person.class); + response5.hits() + .hits() + .forEach(hit -> log.info("Response 5: {}", hit.source())); } } diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java index abe10f4607..51e6ebca70 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java @@ -1,199 +1,198 @@ package com.baeldung.elasticsearch; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import co.elastic.clients.elasticsearch.ElasticsearchClient; +import co.elastic.clients.elasticsearch._types.GeoShapeRelation; +import co.elastic.clients.elasticsearch.core.IndexResponse; +import co.elastic.clients.elasticsearch.core.SearchRequest; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; +import co.elastic.clients.json.JsonData; +import co.elastic.clients.json.jackson.JacksonJsonpMapper; +import co.elastic.clients.transport.ElasticsearchTransport; +import co.elastic.clients.transport.rest_client.RestClientTransport; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; +import java.io.StringReader; import java.util.List; -import java.util.stream.Collectors; -import com.baeldung.spring.data.es.config.Config; +import lombok.extern.slf4j.Slf4j; -import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; -import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.action.index.IndexResponse; -import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestHighLevelClient; -import org.elasticsearch.client.indices.CreateIndexRequest; -import org.elasticsearch.common.geo.GeoPoint; -import org.elasticsearch.common.geo.ShapeRelation; -import org.elasticsearch.common.unit.DistanceUnit; -import org.elasticsearch.index.query.GeoShapeQueryBuilder; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.builder.SearchSourceBuilder; -import org.elasticsearch.xcontent.XContentType; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.locationtech.jts.geom.Coordinate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.apache.http.HttpHost; +import org.elasticsearch.client.RestClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * This Manual test requires: Elasticsearch instance running on localhost:9200. - * - * The following docker command can be used: docker run -d --name es762 -p - * 9200:9200 -e "discovery.type=single-node" elasticsearch:7.6.2 + *

+ * The following docker command can be used: docker run -d --name elastic-test -p 9200:9200 -e + * "discovery.type=single-node" -e "xpack.security.enabled=false" + * docker.elastic.co/elasticsearch/elasticsearch:8.9.0 */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = Config.class) -public class GeoQueriesManualTest { + +@Slf4j +class GeoQueriesManualTest { private static final String WONDERS_OF_WORLD = "wonders-of-world"; - @Autowired - private RestHighLevelClient client; + private ElasticsearchClient client; - @Before + @BeforeEach public void setUp() throws Exception { - String jsonObject = "{\"properties\":{\"name\":{\"type\":\"text\",\"index\":false},\"region\":{\"type\":\"geo_shape\"},\"location\":{\"type\":\"geo_point\"}}}"; - - CreateIndexRequest req = new CreateIndexRequest(WONDERS_OF_WORLD); - req.mapping(jsonObject, XContentType.JSON); - + RestClient restClient = RestClient.builder(HttpHost.create("http://localhost:9200")) + .build(); + ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); + client = new ElasticsearchClient(transport); + log.info("Creating index: {}", WONDERS_OF_WORLD); client.indices() - .create(req, RequestOptions.DEFAULT); - } - -// @Test -// public void givenGeoShapeData_whenExecutedGeoShapeQuery_thenResultNonEmpty() throws IOException { -// String jsonObject = "{\"name\":\"Agra\",\"region\":{\"type\":\"envelope\",\"coordinates\":[[75,30.2],[80.1, 25]]}}"; -// IndexRequest indexRequest = new IndexRequest(WONDERS_OF_WORLD); -// indexRequest.source(jsonObject, XContentType.JSON); -// IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); -// -// String tajMahalId = response.getId(); -// -// RefreshRequest refreshRequest = new RefreshRequest(WONDERS_OF_WORLD); -// client.indices() -// .refresh(refreshRequest, RequestOptions.DEFAULT); -// -// Coordinate topLeft = new Coordinate(74, 31.2); -// Coordinate bottomRight = new Coordinate(81.1, 24); -// -// GeoShapeQueryBuilder qb = QueryBuilders.geoShapeQuery("region", new EnvelopeBuilder(topLeft, bottomRight).buildGeometry()); -// qb.relation(ShapeRelation.INTERSECTS); -// -// SearchSourceBuilder source = new SearchSourceBuilder().query(qb); -// SearchRequest searchRequest = new SearchRequest(WONDERS_OF_WORLD); -// searchRequest.source(source); -// -// SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); -// -// List ids = Arrays.stream(searchResponse.getHits() -// .getHits()) -// .map(SearchHit::getId) -// .collect(Collectors.toList()); -// -// assertTrue(ids.contains(tajMahalId)); -// } - - @Test - public void givenGeoPointData_whenExecutedGeoBoundingBoxQuery_thenResultNonEmpty() throws Exception { - String jsonObject = "{\"name\":\"Pyramids of Giza\",\"location\":[31.131302,29.976480]}"; - - IndexRequest indexRequest = new IndexRequest(WONDERS_OF_WORLD); - indexRequest.source(jsonObject, XContentType.JSON); - IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); - - String pyramidsOfGizaId = response.getId(); - - RefreshRequest refreshRequest = new RefreshRequest(WONDERS_OF_WORLD); - client.indices() - .refresh(refreshRequest, RequestOptions.DEFAULT); - - QueryBuilder qb = QueryBuilders.geoBoundingBoxQuery("location") - .setCorners(31, 30, 28, 32); - - SearchSourceBuilder source = new SearchSourceBuilder().query(qb); - SearchRequest searchRequest = new SearchRequest(WONDERS_OF_WORLD); - searchRequest.source(source); - - SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); - - List ids = Arrays.stream(searchResponse.getHits() - .getHits()) - .map(SearchHit::getId) - .collect(Collectors.toList()); - assertTrue(ids.contains(pyramidsOfGizaId)); + .create(builder -> builder.index(WONDERS_OF_WORLD) + .mappings(typeMapping -> typeMapping.properties("region", region -> region.geoShape(gs -> gs)) + .properties("location", location -> location.geoPoint(gp -> gp)))); } @Test - public void givenGeoPointData_whenExecutedGeoDistanceQuery_thenResultNonEmpty() throws Exception { - String jsonObject = "{\"name\":\"Lighthouse of alexandria\",\"location\":[31.131302,29.976480]}"; + void givenGeoShapeData_whenExecutedGeoShapeQuery_thenResultNonEmpty() throws IOException { + String jsonObject = """ + { + "name":"Agra", + "region":{ + "type":"envelope", + "coordinates":[[75,30.2],[80.1,25]] + } + } + """; + IndexResponse response = client.index(idx -> idx.index(WONDERS_OF_WORLD) + .withJson(new StringReader(jsonObject))); - IndexRequest indexRequest = new IndexRequest(WONDERS_OF_WORLD); - indexRequest.source(jsonObject, XContentType.JSON); - IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); - - String lighthouseOfAlexandriaId = response.getId(); - - RefreshRequest refreshRequest = new RefreshRequest(WONDERS_OF_WORLD); + String tajMahalId = response.id(); client.indices() - .refresh(refreshRequest, RequestOptions.DEFAULT); + .refresh(); - QueryBuilder qb = QueryBuilders.geoDistanceQuery("location") - .point(29.976, 31.131) - .distance(10, DistanceUnit.MILES); + StringReader jsonData = new StringReader(""" + { + "type":"envelope", + "coordinates": [[74.0, 31.2], [81.1, 24.0 ] ] + } + """); - SearchSourceBuilder source = new SearchSourceBuilder().query(qb); - SearchRequest searchRequest = new SearchRequest(WONDERS_OF_WORLD); - searchRequest.source(source); - - SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); - - List ids = Arrays.stream(searchResponse.getHits() - .getHits()) - .map(SearchHit::getId) - .collect(Collectors.toList()); - assertTrue(ids.contains(lighthouseOfAlexandriaId)); + SearchRequest searchRequest = new SearchRequest.Builder().query(query -> query.bool(boolQuery -> boolQuery.filter(query1 -> query1.geoShape(geoShapeQuery -> geoShapeQuery.field("region") + .shape(geoShapeFieldQuery -> geoShapeFieldQuery.relation(GeoShapeRelation.Within) + .shape(JsonData.from(jsonData))))))) + .build(); + log.info("Search request: {}", searchRequest); + SearchResponse search = client.search(searchRequest, Object.class); + log.info("Search response: {}", search); + List searchResults = search.hits() + .hits() + .stream() + .map(Hit::id) + .toList(); + assertTrue(searchResults.contains(tajMahalId)); } @Test - public void givenGeoPointData_whenExecutedGeoPolygonQuery_thenResultNonEmpty() throws Exception { - String jsonObject = "{\"name\":\"The Great Rann of Kutch\",\"location\":[69.859741,23.733732]}"; + void givenGeoPointData_whenExecutedGeoBoundingBoxQuery_thenResultNonEmpty() throws Exception { + Location pyramidsOfGiza = new Location("Pyramids of Giza", List.of(31.1328, 29.9761)); + IndexResponse response = client.index(builder -> builder.index(WONDERS_OF_WORLD) + .document(pyramidsOfGiza)); - IndexRequest indexRequest = new IndexRequest(WONDERS_OF_WORLD); - indexRequest.source(jsonObject, XContentType.JSON); - IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); + String pyramidsOfGizaId = response.id(); - String greatRannOfKutchid = response.getId(); - - RefreshRequest refreshRequest = new RefreshRequest(WONDERS_OF_WORLD); + log.info("Indexed pyramid of Giza: {}", pyramidsOfGizaId); client.indices() - .refresh(refreshRequest, RequestOptions.DEFAULT); + .refresh(); - List allPoints = new ArrayList(); - allPoints.add(new GeoPoint(22.733, 68.859)); - allPoints.add(new GeoPoint(24.733, 68.859)); - allPoints.add(new GeoPoint(23, 70.859)); - QueryBuilder qb = QueryBuilders.geoPolygonQuery("location", allPoints); - - SearchSourceBuilder source = new SearchSourceBuilder().query(qb); - SearchRequest searchRequest = new SearchRequest(WONDERS_OF_WORLD); - searchRequest.source(source); - - SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); - - List ids = Arrays.stream(searchResponse.getHits() - .getHits()) - .map(SearchHit::getId) - .collect(Collectors.toList()); - assertTrue(ids.contains(greatRannOfKutchid)); + SearchRequest.Builder builder = new SearchRequest.Builder().index(WONDERS_OF_WORLD); + builder.query(query -> query.geoBoundingBox(geoBoundingBoxQuery -> geoBoundingBoxQuery.field("location") + .boundingBox(geoBounds -> geoBounds.tlbr(bl4 -> bl4.topLeft(geoLocation -> geoLocation.coords(List.of(30.0, 31.0))) + .bottomRight(geoLocation -> geoLocation.coords(List.of(32.0, 28.0))))))); + SearchRequest build = builder.build(); + log.info("Search request: {}", build); + SearchResponse searchResponse = client.search(build, Location.class); + log.info("Search response: {}", searchResponse); + List returnedLocations = searchResponse.hits() + .hits() + .stream() + .map(Hit::source) + .toList(); + assertEquals(pyramidsOfGiza, returnedLocations.get(0)); } - @After + @Test + void givenGeoPointData_whenExecutedGeoDistanceQuery_thenResultNonEmpty() throws Exception { + String jsonObject = """ + { + "name":"Lighthouse of alexandria", + "location":{ "lat": 31.2139, "lon": 29.8856 } + } + """; + IndexResponse response = client.index(idx -> idx.index(WONDERS_OF_WORLD) + .withJson(new StringReader(jsonObject))); + + String lightHouseOfAlexandriaId = response.id(); + client.indices() + .refresh(); + SearchRequest searchRequest = new SearchRequest.Builder().index(WONDERS_OF_WORLD) + .query(query -> query.geoDistance(geoDistanceQuery -> geoDistanceQuery.field("location") + .distance("10 miles") + .location(geoLocation -> geoLocation.latlon(latLonGeoLocation -> latLonGeoLocation.lon(29.88) + .lat(31.21))))) + .build(); + log.info("Search request: {}", searchRequest); + SearchResponse search = client.search(searchRequest, Object.class); + log.info("Search response: {}", search); + List ids = search.hits() + .hits() + .stream() + .map(Hit::id) + .toList(); + assertTrue(ids.contains(lightHouseOfAlexandriaId)); + } + + @Test + void givenGeoPointData_whenExecutedGeoPolygonQuery_thenResultNonEmpty() throws Exception { + String jsonObject = """ + { + "name":"The Great Rann polygonPoints Kutch", + "location":{"lon": 69.859741, "lat": 23.733732} + } + """; + IndexResponse response = client.index(idx -> idx.index(WONDERS_OF_WORLD) + .withJson(new StringReader(jsonObject))); + String greatRannOfKutchid = response.id(); + client.indices() + .refresh(); + log.info("Indexed greatRannOfKutchid: {}", greatRannOfKutchid); + + JsonData jsonData = JsonData.fromJson(""" + { + "type":"polygon", + "coordinates":[[[68.859,22.733],[68.859,24.733],[70.859,23]]] + } + """); + + SearchRequest build = new SearchRequest.Builder().query(query -> query.bool(boolQuery -> boolQuery.filter(query1 -> query1.geoShape(geoShapeQuery -> geoShapeQuery.field("location") + .shape(geoShapeFieldQuery -> geoShapeFieldQuery.relation(GeoShapeRelation.Within) + .shape(jsonData)))))) + .build(); + log.info("Search request: {}", build); + SearchResponse search = client.search(build, Object.class); + log.info("Search response: {}", search); + List searchResults = search.hits() + .hits() + .stream() + .map(Hit::id) + .toList(); + assertTrue(searchResults.contains(greatRannOfKutchid)); + } + + @AfterEach public void destroy() throws Exception { - DeleteIndexRequest deleteIndex = new DeleteIndexRequest(WONDERS_OF_WORLD); client.indices() - .delete(deleteIndex, RequestOptions.DEFAULT); + .delete(builder -> builder.index(WONDERS_OF_WORLD)); } } diff --git a/persistence-modules/spring-data-jpa-enterprise/pom.xml b/persistence-modules/spring-data-jpa-enterprise/pom.xml index 16294cd3cc..6bd89032fa 100644 --- a/persistence-modules/spring-data-jpa-enterprise/pom.xml +++ b/persistence-modules/spring-data-jpa-enterprise/pom.xml @@ -54,6 +54,11 @@ spring-security-test test + + org.postgresql + postgresql + runtime + org.testcontainers @@ -61,6 +66,12 @@ ${testcontainers.version} test + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + @@ -87,7 +98,7 @@ 1.3.1.Final - 1.17.3 + 1.19.1 \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties index 0ca1872207..875253c79e 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties @@ -12,4 +12,5 @@ spring.datasource.url=jdbc:h2:mem:baeldung spring.jpa.show-sql=false #hibernate.dialect=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.id.new_generator_mappings=false \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java index e8841d921c..45be598153 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java @@ -1,8 +1,9 @@ package com.baeldung.boot.daos; -import org.junit.After; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -25,6 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.*; +@SpringBootTest public class UserRepositoryCommon { final String USER_EMAIL = "email@example.com"; @@ -274,7 +276,7 @@ public class UserRepositoryCommon { .getName()).isEqualTo(USER_NAME_ADAM); } - @Test(expected = PropertyReferenceException.class) + @Test public void givenUsersInDB_WhenFindAllSortWithFunction_ThenThrowException() { userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); @@ -282,10 +284,7 @@ public class UserRepositoryCommon { userRepository.findAll(Sort.by(Sort.Direction.ASC, "name")); - List usersSortByNameLength = userRepository.findAll(Sort.by("LENGTH(name)")); - - assertThat(usersSortByNameLength.get(0) - .getName()).isEqualTo(USER_NAME_ADAM); + assertThrows(PropertyReferenceException.class, () -> userRepository.findAll(Sort.by("LENGTH(name)"))); } @Test @@ -556,7 +555,7 @@ public class UserRepositoryCommon { assertEquals(0, nativeQuery.getResultList().get(0)); } - @After + @AfterEach public void cleanUp() { userRepository.deleteAll(); } diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java index 1b1d264574..c4d9d65746 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java @@ -2,11 +2,10 @@ package com.baeldung.boot.daos; import com.baeldung.boot.Application; import com.baeldung.boot.domain.User; -import org.junit.Test; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; @@ -16,7 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Created by adam. */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) @DirtiesContext public class UserRepositoryIntegrationTest extends UserRepositoryCommon { diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java index 99eabc8271..056b3cea28 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java @@ -3,14 +3,15 @@ package com.baeldung.boot.daos; import com.baeldung.boot.Application; import com.baeldung.boot.domain.User; import com.baeldung.util.BaeldungPostgresqlContainer; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import java.time.LocalDate; @@ -19,12 +20,12 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Created by adam. */ -@RunWith(SpringRunner.class) +@Testcontainers @SpringBootTest(classes = Application.class) @ActiveProfiles({"tc", "tc-auto"}) public class UserRepositoryTCAutoLiveTest extends UserRepositoryCommon { - @ClassRule + @Container public static PostgreSQLContainer postgreSQLContainer = BaeldungPostgresqlContainer.getInstance(); @Test diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java index c976590966..f4af7284bd 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java @@ -1,21 +1,21 @@ package com.baeldung.boot.daos; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.transaction.annotation.Transactional; + import com.baeldung.boot.Application; import com.baeldung.boot.daos.user.UserRepository; import com.baeldung.boot.domain.User; -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.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDate; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) @ActiveProfiles("tc-jdbc") @SpringBootTest(classes = Application.class) public class UserRepositoryTCJdbcLiveTest { diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java index be8843c166..33f4bbeeff 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java @@ -1,33 +1,29 @@ package com.baeldung.boot.daos; -import com.baeldung.boot.Application; -import com.baeldung.boot.domain.User; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.transaction.annotation.Transactional; -import org.testcontainers.containers.PostgreSQLContainer; - -import java.time.LocalDate; - import static org.assertj.core.api.Assertions.assertThat; -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class) +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.transaction.annotation.Transactional; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import com.baeldung.boot.domain.User; + +@Testcontainers +@SpringBootTest @ActiveProfiles("tc") -@ContextConfiguration(initializers = {UserRepositoryTCLiveTest.Initializer.class}) public class UserRepositoryTCLiveTest extends UserRepositoryCommon { - @ClassRule + @Container public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:11.1") - .withDatabaseName("integration-tests-db") + .withDatabaseName("integration-tests-db") .withUsername("sa") .withPassword("sa"); @@ -45,14 +41,10 @@ public class UserRepositoryTCLiveTest extends UserRepositoryCommon { assertThat(updatedUsersSize).isEqualTo(2); } - static class Initializer - implements ApplicationContextInitializer { - public void initialize(ConfigurableApplicationContext configurableApplicationContext) { - TestPropertyValues.of( - "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(), - "spring.datasource.username=" + postgreSQLContainer.getUsername(), - "spring.datasource.password=" + postgreSQLContainer.getPassword() - ).applyTo(configurableApplicationContext.getEnvironment()); - } + @DynamicPropertySource + static void registerPgProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl); + registry.add("spring.datasource.username", postgreSQLContainer::getUsername); + registry.add("spring.datasource.password", postgreSQLContainer::getPassword); } } diff --git a/persistence-modules/spring-data-jpa-query-2/pom.xml b/persistence-modules/spring-data-jpa-query-2/pom.xml index c74c35c37b..1282d1d8a0 100644 --- a/persistence-modules/spring-data-jpa-query-2/pom.xml +++ b/persistence-modules/spring-data-jpa-query-2/pom.xml @@ -1,16 +1,16 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-data-jpa-query-2 spring-data-jpa-query-2 com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -38,6 +38,7 @@ mysql mysql-connector-java + 3.1.12 com.google.guava @@ -50,12 +51,19 @@ ${tomcat-dbcp.version} - org.hibernate + org.hibernate.orm hibernate-core + 6.3.1.Final - org.hibernate + org.hibernate.orm hibernate-envers + 6.3.1.Final + + + org.apache.commons + commons-lang3 + 3.13.0 org.springframework diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/OrderDetail.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/OrderDetail.java index f4a9b8a678..70349a664d 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/OrderDetail.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/OrderDetail.java @@ -1,6 +1,6 @@ package com.baeldung.hibernate.fetching.model; -import javax.persistence.*; +import jakarta.persistence.*; import java.io.Serializable; import java.sql.Date; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserEager.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserEager.java index 9fda4c43bb..d273f942a5 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserEager.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserEager.java @@ -1,6 +1,6 @@ package com.baeldung.hibernate.fetching.model; -import javax.persistence.*; +import jakarta.persistence.*; import java.io.Serializable; import java.util.HashSet; import java.util.Set; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserLazy.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserLazy.java index a78eaa4ac0..6d18b2517c 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserLazy.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/hibernate/fetching/model/UserLazy.java @@ -1,6 +1,6 @@ package com.baeldung.hibernate.fetching.model; -import javax.persistence.*; +import jakarta.persistence.*; import java.io.Serializable; import java.util.HashSet; import java.util.Set; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/dao/common/AbstractJpaDao.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/dao/common/AbstractJpaDao.java index 79bdd86658..d43ee46844 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/dao/common/AbstractJpaDao.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/dao/common/AbstractJpaDao.java @@ -3,12 +3,12 @@ package com.baeldung.persistence.dao.common; import java.io.Serializable; import java.util.List; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.TypedQuery; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; public class AbstractJpaDao extends AbstractDao implements IOperations { diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Bar.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Bar.java index 0ceb2d5626..15a4fdb3ca 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Bar.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Bar.java @@ -3,29 +3,29 @@ package com.baeldung.persistence.model; import com.google.common.collect.Sets; import org.hibernate.annotations.OrderBy; import org.hibernate.envers.Audited; -import org.jboss.logging.Logger; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.PrePersist; -import javax.persistence.PreRemove; -import javax.persistence.PreUpdate; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreRemove; +import jakarta.persistence.PreUpdate; import java.io.Serializable; import java.util.Date; import java.util.Set; +import java.util.logging.Logger; @Entity @NamedQuery(name = "Bar.findAll", query = "SELECT b FROM Bar b") @@ -33,7 +33,7 @@ import java.util.Set; @EntityListeners(AuditingEntityListener.class) public class Bar implements Serializable { - private static final Logger LOGGER = Logger.getLogger(Bar.class); + private static final Logger LOGGER = Logger.getLogger(Bar.class.toString()); public enum OPERATION { INSERT, UPDATE, DELETE; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Child.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Child.java index 19cfb2e237..9a1f95c019 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Child.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Child.java @@ -2,10 +2,10 @@ package com.baeldung.persistence.model; import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.OneToOne; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; @Entity public class Child implements Serializable { diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Foo.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Foo.java index ac79653b2b..b7e8adba42 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Foo.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Foo.java @@ -2,20 +2,20 @@ package com.baeldung.persistence.model; import java.io.Serializable; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedNativeQueries; -import javax.persistence.NamedNativeQuery; -import javax.persistence.NamedStoredProcedureQuery; -import javax.persistence.ParameterMode; -import javax.persistence.StoredProcedureParameter; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedNativeQueries; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.NamedStoredProcedureQuery; +import jakarta.persistence.ParameterMode; +import jakarta.persistence.StoredProcedureParameter; import org.hibernate.envers.Audited; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Parent.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Parent.java index fa6948990b..4149a0b883 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Parent.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Parent.java @@ -2,12 +2,12 @@ package com.baeldung.persistence.model; import java.io.Serializable; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; @Entity public class Parent implements Serializable { diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Person.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Person.java index 6a95a7acf5..3766639975 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Person.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/persistence/model/Person.java @@ -1,8 +1,8 @@ package com.baeldung.persistence.model; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; @Entity public class Person { diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/User.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/User.java index 179dbf2ae7..648b06cf5f 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/User.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/User.java @@ -1,6 +1,6 @@ package com.baeldung.spring.data.jpa.query; -import javax.persistence.*; +import jakarta.persistence.*; import java.time.LocalDate; import java.util.List; import java.util.Objects; diff --git a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/UserRepositoryCustomImpl.java b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/UserRepositoryCustomImpl.java index 033f61fdd3..54cea74e04 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/UserRepositoryCustomImpl.java +++ b/persistence-modules/spring-data-jpa-query-2/src/main/java/com/baeldung/spring/data/jpa/query/UserRepositoryCustomImpl.java @@ -1,8 +1,8 @@ package com.baeldung.spring.data.jpa.query; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.criteria.*; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.criteria.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/JPABarAuditIntegrationTest.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/JPABarAuditIntegrationTest.java index f591773cde..d9ab75af2c 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/JPABarAuditIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/JPABarAuditIntegrationTest.java @@ -4,8 +4,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; import org.junit.After; import org.junit.AfterClass; @@ -30,15 +30,15 @@ import com.baeldung.spring.config.PersistenceTestConfig; @ContextConfiguration(classes = { PersistenceTestConfig.class }, loader = AnnotationConfigContextLoader.class) public class JPABarAuditIntegrationTest { - private static Logger logger = LoggerFactory.getLogger(JPABarAuditIntegrationTest.class); + private static final Logger logger = LoggerFactory.getLogger(JPABarAuditIntegrationTest.class); @BeforeClass - public static void setUpBeforeClass() throws Exception { + public static void setUpBeforeClass() { logger.info("setUpBeforeClass()"); } @AfterClass - public static void tearDownAfterClass() throws Exception { + public static void tearDownAfterClass(){ logger.info("tearDownAfterClass()"); } diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/SpringDataJPABarAuditIntegrationTest.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/SpringDataJPABarAuditIntegrationTest.java index 0603067810..0d22562a93 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/SpringDataJPABarAuditIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/audit/SpringDataJPABarAuditIntegrationTest.java @@ -3,8 +3,8 @@ package com.baeldung.persistence.audit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; import org.junit.After; import org.junit.AfterClass; @@ -29,7 +29,7 @@ import com.baeldung.spring.config.PersistenceTestConfig; @ContextConfiguration(classes = { PersistenceTestConfig.class }, loader = AnnotationConfigContextLoader.class) public class SpringDataJPABarAuditIntegrationTest { - private static Logger logger = LoggerFactory.getLogger(SpringDataJPABarAuditIntegrationTest.class); + private static final Logger logger = LoggerFactory.getLogger(SpringDataJPABarAuditIntegrationTest.class); @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -37,7 +37,7 @@ public class SpringDataJPABarAuditIntegrationTest { } @AfterClass - public static void tearDownAfterClass() throws Exception { + public static void tearDownAfterClass(){ logger.info("tearDownAfterClass()"); } diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooFixtures.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooFixtures.java index a7763bb0f8..92a9d8e2ec 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooFixtures.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooFixtures.java @@ -17,7 +17,7 @@ public class FooFixtures { private static final Logger LOGGER = LoggerFactory.getLogger(FooFixtures.class); - private SessionFactory sessionFactory; + private final SessionFactory sessionFactory; public FooFixtures(final SessionFactory sessionFactory) { super(); @@ -28,8 +28,8 @@ public class FooFixtures { // API public void createBars() { - Session session = null; - Transaction tx = null; + Session session; + Transaction tx; session = sessionFactory.openSession(); tx = session.getTransaction(); try { @@ -39,13 +39,13 @@ public class FooFixtures { bar.setName("Bar_" + i); final Foo foo = new Foo("Foo_" + (i + 120)); foo.setBar(bar); - session.save(foo); + session.persist(foo); final Foo foo2 = new Foo(null); if (i % 2 == 0) { foo2.setName("LuckyFoo" + (i + 120)); } foo2.setBar(bar); - session.save(foo2); + session.persist(foo2); bar.getFooSet().add(foo); bar.getFooSet().add(foo2); session.merge(bar); @@ -53,16 +53,12 @@ public class FooFixtures { tx.commit(); session.flush(); } catch (final HibernateException he) { - if (tx != null) { - tx.rollback(); - } + tx.rollback(); LOGGER.error("Not able to open session", he); } catch (final Exception e) { LOGGER.error(e.getLocalizedMessage(), e); } finally { - if (session != null) { - session.close(); - } + session.close(); } } @@ -86,23 +82,18 @@ public class FooFixtures { try { tx.begin(); for (final Foo foo : fooList) { - - session.save(foo.getBar()); - session.save(foo); + session.persist(foo.getBar()); + session.persist(foo); } tx.commit(); session.flush(); } catch (final HibernateException he) { - if (tx != null) { - tx.rollback(); - } + tx.rollback(); LOGGER.error("Not able to open session", he); } catch (final Exception e) { LOGGER.error(e.getLocalizedMessage(), e); } finally { - if (session != null) { - session.close(); - } + session.close(); } } diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java index fd7bc4aabf..528eed9d8d 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java @@ -1,19 +1,19 @@ package com.baeldung.persistence.hibernate; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.lessThan; -import static org.junit.Assert.assertThat; import java.util.List; -import org.hibernate.Criteria; -import org.hibernate.Query; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.hibernate.criterion.Projections; +import org.hibernate.query.Query; +import org.hibernate.query.SelectionQuery; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -28,6 +28,8 @@ import com.baeldung.persistence.service.IFooService; import com.baeldung.spring.config.PersistenceTestConfig; import com.google.common.collect.Lists; +import jakarta.persistence.criteria.CriteriaQuery; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { PersistenceTestConfig.class }, loader = AnnotationConfigContextLoader.class) public class FooPaginationPersistenceIntegrationTest { @@ -40,8 +42,6 @@ public class FooPaginationPersistenceIntegrationTest { private Session session; - // tests - @Before public final void before() { final int minimalNumberOfEntities = 25; @@ -59,20 +59,17 @@ public class FooPaginationPersistenceIntegrationTest { session.close(); } - // tests - @Test public final void whenContextIsBootstrapped_thenNoExceptions() { // } - @SuppressWarnings("unchecked") @Test public final void whenRetrievingPaginatedEntities_thenCorrectSize() { final int pageNumber = 1; final int pageSize = 10; - final Query query = session.createQuery("From Foo"); + final Query query = session.createQuery("From Foo",Foo.class); query.setFirstResult((pageNumber - 1) * pageSize); query.setMaxResults(pageSize); final List fooList = query.list(); @@ -80,19 +77,18 @@ public class FooPaginationPersistenceIntegrationTest { assertThat(fooList, hasSize(pageSize)); } - @SuppressWarnings("unchecked") @Test public final void whenRetrievingAllPages_thenCorrect() { int pageNumber = 1; final int pageSize = 10; final String countQ = "Select count (f.id) from Foo f"; - final Query countQuery = session.createQuery(countQ); + final Query countQuery = session.createQuery(countQ, Long.class); final Long countResult = (Long) countQuery.uniqueResult(); final List fooList = Lists.newArrayList(); int totalEntities = 0; - final Query query = session.createQuery("From Foo"); + final Query query = session.createQuery("From Foo", Foo.class); while (totalEntities < countResult) { query.setFirstResult((pageNumber - 1) * pageSize); query.setMaxResults(pageSize); @@ -102,17 +98,16 @@ public class FooPaginationPersistenceIntegrationTest { } } - @SuppressWarnings("unchecked") @Test public final void whenRetrievingLastPage_thenCorrectSize() { final int pageSize = 10; final String countQ = "Select count (f.id) from Foo f"; - final Query countQuery = session.createQuery(countQ); - final Long countResults = (Long) countQuery.uniqueResult(); + final Query countQuery = session.createQuery(countQ, Long.class); + final Long countResults = countQuery.uniqueResult(); final int lastPageNumber = (int) (Math.ceil(countResults / pageSize)); - final Query selectQuery = session.createQuery("From Foo"); + final Query selectQuery = session.createQuery("From Foo",Foo.class); selectQuery.setFirstResult((lastPageNumber - 1) * pageSize); selectQuery.setMaxResults(pageSize); final List lastPage = selectQuery.list(); @@ -126,9 +121,9 @@ public class FooPaginationPersistenceIntegrationTest { public final void givenUsingTheScrollableApi_whenRetrievingPaginatedData_thenCorrect() { final int pageSize = 10; final String hql = "FROM Foo f order by f.name"; - final Query query = session.createQuery(hql); + final Query query = session.createQuery(hql,Foo.class); - final ScrollableResults resultScroll = query.scroll(ScrollMode.FORWARD_ONLY); + final ScrollableResults resultScroll = query.scroll(ScrollMode.FORWARD_ONLY); // resultScroll.last(); // final int totalResults = resultScroll.getRowNumber() + 1; @@ -138,7 +133,7 @@ public class FooPaginationPersistenceIntegrationTest { final List fooPage = Lists.newArrayList(); int i = 0; while (pageSize > i++) { - fooPage.add((Foo) resultScroll.get(0)); + fooPage.add((Foo) resultScroll.get()); if (!resultScroll.next()) { break; } @@ -147,36 +142,42 @@ public class FooPaginationPersistenceIntegrationTest { assertThat(fooPage, hasSize(lessThan(10 + 1))); } - @SuppressWarnings("unchecked") @Test public final void givenUsingTheCriteriaApi_whenRetrievingFirstPage_thenCorrect() { final int pageSize = 10; - final Criteria criteria = session.createCriteria(Foo.class); - criteria.setFirstResult(0); - criteria.setMaxResults(pageSize); - final List firstPage = criteria.list(); + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + + SelectionQuery query = session.createQuery(selectQuery); + query.setFirstResult(0); + query.setMaxResults(pageSize); + final List firstPage = query.list(); assertThat(firstPage, hasSize(pageSize)); } - @SuppressWarnings("unchecked") @Test public final void givenUsingTheCriteriaApi_whenRetrievingPaginatedData_thenCorrect() { - final Criteria criteriaCount = session.createCriteria(Foo.class); - criteriaCount.setProjection(Projections.rowCount()); - final Long count = (Long) criteriaCount.uniqueResult(); + + HibernateCriteriaBuilder qb = session.getCriteriaBuilder(); + CriteriaQuery cq = qb.createQuery(Long.class); + cq.select(qb.count(cq.from(Foo.class))); + final Long count = session.createQuery(cq).getSingleResult(); int pageNumber = 1; final int pageSize = 10; final List fooList = Lists.newArrayList(); - final Criteria criteria = session.createCriteria(Foo.class); + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + SelectionQuery query = session.createQuery(selectQuery); + int totalEntities = 0; while (totalEntities < count.intValue()) { - criteria.setFirstResult((pageNumber - 1) * pageSize); - criteria.setMaxResults(pageSize); - fooList.addAll(criteria.list()); + query.setFirstResult((pageNumber - 1) * pageSize); + query.setMaxResults(pageSize); + fooList.addAll(query.list()); totalEntities = fooList.size(); pageNumber++; } diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java index 6078eb3af0..7e2d23da96 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java @@ -2,15 +2,17 @@ package com.baeldung.persistence.hibernate; import static org.junit.Assert.assertNull; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Set; -import org.hibernate.Criteria; -import org.hibernate.NullPrecedence; -import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.hibernate.criterion.Order; +import org.hibernate.query.NullPrecedence; +import org.hibernate.query.Order; +import org.hibernate.query.Query; +import org.hibernate.query.SortDirection; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -26,6 +28,8 @@ import com.baeldung.persistence.model.Bar; import com.baeldung.persistence.model.Foo; import com.baeldung.spring.config.PersistenceTestConfig; +import jakarta.persistence.criteria.CriteriaQuery; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { PersistenceTestConfig.class }, loader = AnnotationConfigContextLoader.class) @SuppressWarnings("unchecked") @@ -91,7 +95,7 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenHQlSortingByOneAttribute_andOrderDirection_thenPrintSortedResults() { final String hql = "FROM Foo f ORDER BY f.name ASC"; - final Query query = session.createQuery(hql); + Query query = session.createQuery(hql, Foo.class); final List fooList = query.list(); for (final Foo foo : fooList) { LOGGER.debug("Name: {}, Id: {}", foo.getName(), foo.getId()); @@ -101,7 +105,7 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenHQlSortingByMultipleAttributes_thenSortedResults() { final String hql = "FROM Foo f ORDER BY f.name, f.id"; - final Query query = session.createQuery(hql); + Query query = session.createQuery(hql, Foo.class); final List fooList = query.list(); for (final Foo foo : fooList) { LOGGER.debug("Name: {}, Id: {}", foo.getName(), foo.getId()); @@ -111,7 +115,7 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenHQlSortingByMultipleAttributes_andOrderDirection_thenPrintSortedResults() { final String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC"; - final Query query = session.createQuery(hql); + Query query = session.createQuery(hql, Foo.class); final List fooList = query.list(); for (final Foo foo : fooList) { LOGGER.debug("Name: {}, Id: {}", foo.getName(), foo.getId()); @@ -120,9 +124,12 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenHQLCriteriaSortingByOneAttr_thenPrintSortedResults() { - final Criteria criteria = session.createCriteria(Foo.class, "FOO"); - criteria.addOrder(Order.asc("id")); - final List fooList = criteria.list(); + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + Query query = session.createQuery(selectQuery); + + query.setOrder(Collections.singletonList(Order.asc(Foo.class,"id"))); + final List fooList = query.list(); for (final Foo foo : fooList) { LOGGER.debug("Id: {}, FirstName: {}", foo.getId(), foo.getName()); } @@ -130,10 +137,16 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenHQLCriteriaSortingByMultipAttr_thenSortedResults() { - final Criteria criteria = session.createCriteria(Foo.class, "FOO"); - criteria.addOrder(Order.asc("name")); - criteria.addOrder(Order.asc("id")); - final List fooList = criteria.list(); + + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + Query query = session.createQuery(selectQuery); + + List> orderBy = new ArrayList<>(2); + orderBy.add(Order.asc(Foo.class,"name")); + orderBy.add(Order.asc(Foo.class,"id")); + query.setOrder(orderBy); + final List fooList = query.list(); for (final Foo foo : fooList) { LOGGER.debug("Id: {}, FirstName: {}", foo.getId(), foo.getName()); } @@ -141,9 +154,15 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenCriteriaSortingStringNullsLastAsc_thenNullsLast() { - final Criteria criteria = session.createCriteria(Foo.class, "FOO"); - criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST)); - final List fooList = criteria.list(); + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + Query query = session.createQuery(selectQuery); + + List> orderBy = new ArrayList<>(2); + orderBy.add(Order.by(Foo.class,"name", SortDirection.ASCENDING, NullPrecedence.LAST)); + query.setOrder(orderBy); + + final List fooList = query.list(); assertNull(fooList.get(fooList.toArray().length - 1).getName()); for (final Foo foo : fooList) { LOGGER.debug("Id: {}, FirstName: {}", foo.getId(), foo.getName()); @@ -152,9 +171,15 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenCriteriaSortingStringNullsFirstDesc_thenNullsFirst() { - final Criteria criteria = session.createCriteria(Foo.class, "FOO"); - criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST)); - final List fooList = criteria.list(); + CriteriaQuery selectQuery = session.getCriteriaBuilder().createQuery(Foo.class); + selectQuery.from(Foo.class); + Query query = session.createQuery(selectQuery); + + List> orderBy = new ArrayList<>(2); + orderBy.add(Order.by(Foo.class,"name", SortDirection.ASCENDING, NullPrecedence.FIRST)); + query.setOrder(orderBy); + + final List fooList = query.list(); assertNull(fooList.get(0).getName()); for (final Foo foo : fooList) { LOGGER.debug("Id: {}, FirstName: {}", foo.getId(), foo.getName()); @@ -164,7 +189,7 @@ public class FooSortingPersistenceIntegrationTest { @Test public final void whenSortingBars_thenBarsWithSortedFoos() { final String hql = "FROM Bar b ORDER BY b.id"; - final Query query = session.createQuery(hql); + final Query query = session.createQuery(hql, Bar.class); final List barList = query.list(); for (final Bar bar : barList) { final Set fooSet = bar.getFooSet(); diff --git a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/service/FooStoredProceduresLiveTest.java b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/service/FooStoredProceduresLiveTest.java index f6dedfc6de..d8216fc072 100644 --- a/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/service/FooStoredProceduresLiveTest.java +++ b/persistence-modules/spring-data-jpa-query-2/src/test/java/com/baeldung/persistence/service/FooStoredProceduresLiveTest.java @@ -5,14 +5,14 @@ import static org.junit.Assert.assertEquals; import java.util.List; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.StoredProcedureQuery; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.StoredProcedureQuery; -import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.exception.SQLGrammarException; +import org.hibernate.query.Query; import org.junit.After; import org.junit.Assume; import org.junit.Before; @@ -59,22 +59,22 @@ public class FooStoredProceduresLiveTest { private boolean getFoosByNameExists() { try { - Query sqlQuery = session.createSQLQuery("CALL GetAllFoos()").addEntity(Foo.class); + Query sqlQuery = session.createNativeQuery("CALL GetFoosByName()",Foo.class); sqlQuery.list(); return true; } catch (SQLGrammarException e) { - LOGGER.error("WARNING : GetFoosByName() Procedure is may be missing ", e); + LOGGER.error("WARNING : GetFoosByName() Procedure may be missing ", e); return false; } } private boolean getAllFoosExists() { try { - Query sqlQuery = session.createSQLQuery("CALL GetAllFoos()").addEntity(Foo.class); + Query sqlQuery = session.createNativeQuery("CALL GetAllFoos()",Foo.class); sqlQuery.list(); return true; } catch (SQLGrammarException e) { - LOGGER.error("WARNING : GetAllFoos() Procedure is may be missing ", e); + LOGGER.error("WARNING : GetAllFoos() Procedure may be missing ", e); return false; } } @@ -90,9 +90,9 @@ public class FooStoredProceduresLiveTest { fooService.create(new Foo(randomAlphabetic(6))); - // Stored procedure getAllFoos using createSQLQuery - Query sqlQuery = session.createSQLQuery("CALL GetAllFoos()").addEntity(Foo.class); - @SuppressWarnings("unchecked") + // Stored procedure getAllFoos using createQuery + Query sqlQuery = session.createNativeQuery("CALL GetAllFoos()", Foo.class); + List allFoos = sqlQuery.list(); for (Foo foo : allFoos) { LOGGER.info("getAllFoos() SQL Query result : {}", foo.getName()); @@ -100,8 +100,8 @@ public class FooStoredProceduresLiveTest { assertEquals(allFoos.size(), fooService.findAll().size()); // Stored procedure getAllFoos using a Named Query - Query namedQuery = session.getNamedQuery("callGetAllFoos"); - @SuppressWarnings("unchecked") + Query namedQuery = session.createNamedQuery("callGetAllFoos", Foo.class); + List allFoos2 = namedQuery.list(); for (Foo foo : allFoos2) { LOGGER.info("getAllFoos() NamedQuery result : {}", foo.getName()); @@ -110,6 +110,7 @@ public class FooStoredProceduresLiveTest { StoredProcedureQuery spQuery = entityManager.createNamedStoredProcedureQuery("GetAllFoos"); + @SuppressWarnings("unchecked") List allFoos3 = spQuery.getResultList(); for (Foo foo : allFoos3) { LOGGER.info("getAllFoos() StoredProcedureQuery result : {}", foo.getName()); @@ -124,16 +125,16 @@ public class FooStoredProceduresLiveTest { fooService.create(new Foo("NewFooName")); // Stored procedure getFoosByName using createSQLQuery() - Query sqlQuery = session.createSQLQuery("CALL GetFoosByName(:fooName)").addEntity(Foo.class).setParameter("fooName", "NewFooName"); - @SuppressWarnings("unchecked") + Query sqlQuery = session.createNativeQuery("CALL GetFoosByName(:fooName)", Foo.class).setParameter("fooName", "NewFooName"); + List allFoosByName = sqlQuery.list(); for (Foo foo : allFoosByName) { LOGGER.info("getFoosByName() using SQL Query : found => {}", foo.toString()); } // Stored procedure getFoosByName using getNamedQuery() - Query namedQuery = session.getNamedQuery("callGetFoosByName").setParameter("fooName", "NewFooName"); - @SuppressWarnings("unchecked") + Query namedQuery = session.createQuery("callGetFoosByName", Foo.class).setParameter("fooName", "NewFooName"); + List allFoosByName2 = namedQuery.list(); for (Foo foo : allFoosByName2) { LOGGER.info("getFoosByName() using Native Query : found => {}", foo.toString()); @@ -142,6 +143,7 @@ public class FooStoredProceduresLiveTest { StoredProcedureQuery spQuery = entityManager. createNamedStoredProcedureQuery("GetFoosByName") .setParameter("fooName", "NewFooName"); + @SuppressWarnings("unchecked") List allFoosByName3 = spQuery.getResultList(); assertEquals(1, allFoosByName3.size()); for (Foo foo : allFoosByName3) { diff --git a/persistence-modules/spring-data-jpa-query/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java b/persistence-modules/spring-data-jpa-query/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java index 14d5403cb5..7b5a307b81 100644 --- a/persistence-modules/spring-data-jpa-query/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java +++ b/persistence-modules/spring-data-jpa-query/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java @@ -12,6 +12,9 @@ interface PassengerRepository extends JpaRepository, CustomPass Passenger findTopByOrderBySeatNumberAsc(); List findByOrderBySeatNumberAsc(); + + //The Limit type is a new feature in Spring Data JPA version 3.2 + //List findByOrderBySeatNumberAsc(Limit limit); List findByFirstNameIgnoreCase(String firstName); diff --git a/persistence-modules/spring-data-jpa-repo-3/pom.xml b/persistence-modules/spring-data-jpa-repo-3/pom.xml index 207e753ecd..211e8a2d96 100644 --- a/persistence-modules/spring-data-jpa-repo-3/pom.xml +++ b/persistence-modules/spring-data-jpa-repo-3/pom.xml @@ -32,5 +32,8 @@ test + + com.baeldung.spring.data.jpa.naturalid.Application + diff --git a/persistence-modules/spring-data-jpa-repo-3/src/main/java/com/baeldung/spring/data/jpa/listrepositories/entity/Library.java b/persistence-modules/spring-data-jpa-repo-3/src/main/java/com/baeldung/spring/data/jpa/listrepositories/entity/Library.java index 04c0ad5e0a..724adc3aad 100644 --- a/persistence-modules/spring-data-jpa-repo-3/src/main/java/com/baeldung/spring/data/jpa/listrepositories/entity/Library.java +++ b/persistence-modules/spring-data-jpa-repo-3/src/main/java/com/baeldung/spring/data/jpa/listrepositories/entity/Library.java @@ -19,7 +19,7 @@ public class Library { private List addresses = new ArrayList<>(); @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER) - @CollectionTable(name = "book", joinColumns = @JoinColumn(name = "library_id")) + @CollectionTable(name = "books", joinColumns = @JoinColumn(name = "library_id")) @Column(name = "book", nullable = false) private List books = new ArrayList<>(); diff --git a/persistence-modules/spring-data-jpa-repo-3/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-repo-3/src/main/resources/application.properties index cd6dbe3994..37f37d548d 100644 --- a/persistence-modules/spring-data-jpa-repo-3/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-repo-3/src/main/resources/application.properties @@ -1,5 +1,5 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=none - +spring.jpa.generate-ddl=true logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE diff --git a/persistence-modules/spring-data-jpa-repo-3/src/test/java/com/baeldung/spring/data/jpa/listrepositories/repository/BookPagingAndSortingRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-3/src/test/java/com/baeldung/spring/data/jpa/listrepositories/repository/BookPagingAndSortingRepositoryIntegrationTest.java index 8f34e43e3f..9ea865c04f 100644 --- a/persistence-modules/spring-data-jpa-repo-3/src/test/java/com/baeldung/spring/data/jpa/listrepositories/repository/BookPagingAndSortingRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-repo-3/src/test/java/com/baeldung/spring/data/jpa/listrepositories/repository/BookPagingAndSortingRepositoryIntegrationTest.java @@ -21,13 +21,13 @@ public class BookPagingAndSortingRepositoryIntegrationTest { @Test public void givenDbContainsBooks_whenfindBooksByAuthor_thenReturnBooksByAuthor() { - Book book1 = new Book("Spring Data", "John Doe", "1234567890"); - Book book2 = new Book("Spring Data 2", "John Doe", "1234567891"); - Book book3 = new Book("Spring Data 3", "John Doe", "1234567892"); + Book book1 = new Book("Spring Data", "John Miller", "1234567890"); + Book book2 = new Book("Spring Data 2", "John Miller", "1234567891"); + Book book3 = new Book("Spring Data 3", "John Miller", "1234567892"); bookPagingAndSortingRepository.saveAll(Arrays.asList(book1, book2, book3)); Pageable pageable = PageRequest.of(0, 2, Sort.by("title").descending()); - List books = bookPagingAndSortingRepository.findBooksByAuthor("John Doe", pageable); + List books = bookPagingAndSortingRepository.findBooksByAuthor("John Miller", pageable); Assertions.assertEquals(2, books.size()); Assertions.assertEquals(book3.getId(), books.get(0).getId()); Assertions.assertEquals(book2.getId(), books.get(1).getId()); diff --git a/persistence-modules/spring-data-mongodb/pom.xml b/persistence-modules/spring-data-mongodb/pom.xml index 87cf1acaf8..a59fcff3d9 100644 --- a/persistence-modules/spring-data-mongodb/pom.xml +++ b/persistence-modules/spring-data-mongodb/pom.xml @@ -8,31 +8,19 @@ com.baeldung - parent-spring-5 + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-spring-5 + ../../parent-boot-2 - org.springframework.data - spring-data-mongodb - ${org.springframework.data.version} + org.springframework.boot + spring-boot-starter-data-mongodb - org.mongodb - mongodb-driver-sync - ${mongodb-driver.version} - - - org.mongodb - mongodb-driver-reactivestreams - ${mongodb-reactivestreams.version} - - - io.projectreactor - reactor-core - ${projectreactor.version} + org.springframework.boot + spring-boot-starter-data-mongodb-reactive io.projectreactor @@ -40,23 +28,6 @@ ${projectreactor.version} test - - org.springframework - spring-core - ${spring.version} - - - commons-logging - commons-logging - - - - - org.springframework - spring-test - ${spring.version} - test - com.querydsl querydsl-mongodb @@ -103,12 +74,9 @@ - 3.4.7 5.0.0 1.1.3 - 4.1.0 3.5.4 - 4.6.1 4.6.3 diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java index 53b2c7a0e7..a53dfc6663 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java @@ -28,6 +28,7 @@ import com.baeldung.model.User; * * This test requires: * * mongodb instance running on the environment + * Run the src/live-test/resources/live-test-setup.sh * */ @RunWith(SpringJUnit4ClassRunner.class) diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java index d92296beab..adc31ffea2 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java @@ -26,6 +26,7 @@ import com.baeldung.repository.UserRepository; * * This test requires: * * mongodb instance running on the environment + * Run the src/live-test/resources/live-test-setup.sh * */ @RunWith(SpringJUnit4ClassRunner.class) diff --git a/persistence-modules/spring-data-neo4j/pom.xml b/persistence-modules/spring-data-neo4j/pom.xml index 33f2966db3..8a0a9ff464 100644 --- a/persistence-modules/spring-data-neo4j/pom.xml +++ b/persistence-modules/spring-data-neo4j/pom.xml @@ -15,53 +15,39 @@ - org.neo4j - neo4j-ogm-embedded-driver - ${neo4j-ogm.version} + org.neo4j.test + neo4j-harness + ${neo4j-harness.version} + test - org.springframework.data - spring-data-neo4j - ${spring-data-neo4j.version} - - - com.voodoodyne.jackson.jsog - jackson-jsog - ${jackson-jsog.version} - compile + org.springframework.boot + spring-boot-starter-data-neo4j + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + org.springframework.boot spring-boot-starter-test ${spring-boot.version} test - - - org.neo4j - neo4j-ogm-test - ${neo4j-ogm.version} - test - - - org.neo4j.test - neo4j-harness - ${neo4j.version} - test - - - org.springframework - spring-test - ${spring-test.version} + + + org.springframework.boot + spring-boot-starter-logging + + - 3.4.6 - 5.0.1.RELEASE - 1.1 - 2.0.1.RELEASE - 5.0.1.RELEASE - 3.1.2 + 2.7.14 + 5.10.0 \ No newline at end of file diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/Neo4JApplication.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/Neo4JApplication.java new file mode 100644 index 0000000000..8e1f104be5 --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/Neo4JApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.data.neo4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Neo4JApplication { + + public static void main(String[] args) { + SpringApplication.run(Neo4JApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java deleted file mode 100644 index 4e87c24614..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jConfiguration.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.spring.data.neo4j.config; - -import org.neo4j.ogm.config.Configuration.Builder; -import org.neo4j.ogm.session.SessionFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; - -@ComponentScan(basePackages = { "com.baeldung.spring.data.neo4j.services" }) -@Configuration -@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repository") -public class MovieDatabaseNeo4jConfiguration { - - public static final String URL = System.getenv("NEO4J_URL") != null ? System.getenv("NEO4J_URL") : "http://neo4j:movies@localhost:7474"; - - @Bean - public org.neo4j.ogm.config.Configuration getConfiguration() { - return new Builder().uri(URL).build(); - } - - @Bean - public SessionFactory getSessionFactory() { - return new SessionFactory(getConfiguration(), "com.baeldung.spring.data.neo4j.domain"); - } -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java deleted file mode 100644 index a4cbe4b809..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.spring.data.neo4j.config; - -import org.neo4j.ogm.config.Configuration.Builder; -import org.neo4j.ogm.session.SessionFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; -import org.springframework.transaction.annotation.EnableTransactionManagement; - -@Configuration -@EnableTransactionManagement -@ComponentScan(basePackages = { "com.baeldung.spring.data.neo4j.services" }) -@EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repository") -@Profile({ "embedded", "test" }) -public class MovieDatabaseNeo4jTestConfiguration { - - @Bean - public org.neo4j.ogm.config.Configuration getConfiguration() { - org.neo4j.ogm.config.Configuration config = new Builder().build(); - return config; - } - - @Bean - public SessionFactory getSessionFactory() { - return new SessionFactory(getConfiguration(), "com.baeldung.spring.data.neo4j.domain"); - } - - @Bean - public Neo4jTransactionManager transactionManager() { - return new Neo4jTransactionManager(getSessionFactory()); - } - -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/Neo4jConfig.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/Neo4jConfig.java new file mode 100644 index 0000000000..7571d01c68 --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/Neo4jConfig.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.data.neo4j.config; + +import org.neo4j.cypherdsl.core.renderer.Dialect; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Neo4jConfig { + @Bean + org.neo4j.cypherdsl.core.renderer.Configuration cypherDslConfiguration() { + return org.neo4j.cypherdsl.core.renderer.Configuration.newConfig() + .withDialect(Dialect.NEO4J_5).build(); + } +} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Author.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Author.java new file mode 100644 index 0000000000..69f035dcae --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Author.java @@ -0,0 +1,48 @@ +package com.baeldung.spring.data.neo4j.domain; + + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Relationship; + +import java.util.List; + +@Node("Author") +public class Author { + @Id + private Long id; + + private String name; + + @Relationship(type = "WRITTEN_BY", direction = Relationship.Direction.INCOMING) + private List books; + + public Author(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getBooks() { + return books; + } + + public void setBooks(List books) { + this.books = books; + } +} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Book.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Book.java new file mode 100644 index 0000000000..4e6aff6798 --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Book.java @@ -0,0 +1,58 @@ +package com.baeldung.spring.data.neo4j.domain; + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; +import org.springframework.data.neo4j.core.schema.Relationship; + +@Node("Book") +public class Book { + @Id + private String isbn; + + @Property("name") + private String title; + + private Integer year; + + @Relationship(type = "WRITTEN_BY", direction = Relationship.Direction.OUTGOING) + private Author author; + + public Book(String isbn, String title, Integer year) { + this.isbn = isbn; + this.title = title; + this.year = year; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Car.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Car.java deleted file mode 100644 index 455407a92b..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Car.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.spring.data.neo4j.domain; - -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Relationship; - -@NodeEntity -public class Car { - @Id @GeneratedValue - private Long id; - - private String make; - - @Relationship(direction = "INCOMING") - private Company company; - - public Car(String make, String model) { - this.make = make; - this.model = model; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getMake() { - return make; - } - - public void setMake(String make) { - this.make = make; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - private String model; -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Company.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Company.java deleted file mode 100644 index 4422ade44f..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Company.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.spring.data.neo4j.domain; - -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Relationship; - -@NodeEntity -public class Company { - private Long id; - - private String name; - - @Relationship(type="owns") - private Car car; - - public Company(String name) { - this.name = name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Car getCar() { - return car; - } - - public void setCar(Car car) { - this.car = car; - } -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java deleted file mode 100644 index 996a661b07..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Movie.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.spring.data.neo4j.domain; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.voodoodyne.jackson.jsog.JSOGGenerator; - -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Relationship; - -import java.util.Collection; -import java.util.List; - -@JsonIdentityInfo(generator = JSOGGenerator.class) - -@NodeEntity -public class Movie { - @Id @GeneratedValue - Long id; - - private String title; - - private int released; - private String tagline; - - @Relationship(type = "ACTED_IN", direction = Relationship.INCOMING) - private List roles; - - public Movie() { - } - - public String getTitle() { - return title; - } - - public int getReleased() { - return released; - } - - public String getTagline() { - return tagline; - } - - public Collection getRoles() { - return roles; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setReleased(int released) { - this.released = released; - } - - public void setTagline(String tagline) { - this.tagline = tagline; - } - - public void setRoles(List roles) { - this.roles = roles; - } - -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java deleted file mode 100644 index 453ca1c3f3..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Person.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.spring.data.neo4j.domain; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.voodoodyne.jackson.jsog.JSOGGenerator; - -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Relationship; - -import java.util.List; - -@JsonIdentityInfo(generator = JSOGGenerator.class) -@NodeEntity -public class Person { - @Id @GeneratedValue - Long id; - - private String name; - private int born; - - @Relationship(type = "ACTED_IN") - private List movies; - - public Person() { - } - - public String getName() { - return name; - } - - public int getBorn() { - return born; - } - - public List getMovies() { - return movies; - } - - public void setName(String name) { - this.name = name; - } - - public void setBorn(int born) { - this.born = born; - } - - public void setMovies(List movies) { - this.movies = movies; - } - -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java deleted file mode 100644 index 5a18837dae..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/domain/Role.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.baeldung.spring.data.neo4j.domain; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.voodoodyne.jackson.jsog.JSOGGenerator; -import org.neo4j.ogm.annotation.EndNode; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.RelationshipEntity; -import org.neo4j.ogm.annotation.StartNode; - -import java.util.Collection; - -@JsonIdentityInfo(generator = JSOGGenerator.class) -@RelationshipEntity(type = "ACTED_IN") -public class Role { - @Id @GeneratedValue - Long id; - private Collection roles; - @StartNode - private Person person; - @EndNode - private Movie movie; - - public Role() { - } - - public Collection getRoles() { - return roles; - } - - public Person getPerson() { - return person; - } - - public Movie getMovie() { - return movie; - } - - public void setRoles(Collection roles) { - this.roles = roles; - } - - public void setPerson(Person person) { - this.person = person; - } - - public void setMovie(Movie movie) { - this.movie = movie; - } -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/AuthorRepository.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/AuthorRepository.java new file mode 100644 index 0000000000..16949dfeef --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/AuthorRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.data.neo4j.repository; + +import com.baeldung.spring.data.neo4j.domain.Author; +import com.baeldung.spring.data.neo4j.domain.Book; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AuthorRepository extends Neo4jRepository { + @Query("MATCH (b:Book)-[:WRITTEN_BY]->(a:Author) WHERE a.name = $name AND b.year > $year RETURN b") + List findBooksAfterYear(@Param("name") String name, @Param("year") Integer year); +} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/BookRepository.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/BookRepository.java new file mode 100644 index 0000000000..0489ff3c30 --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/BookRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.data.neo4j.repository; + + +import com.baeldung.spring.data.neo4j.domain.Book; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BookRepository extends Neo4jRepository { + Book findOneByTitle(String title); + List findAllByYear(Integer year); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/MovieRepository.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/MovieRepository.java deleted file mode 100644 index dde946ea73..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/MovieRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.spring.data.neo4j.repository; - -import com.baeldung.spring.data.neo4j.domain.Movie; -import org.springframework.data.neo4j.annotation.Query; -import org.springframework.data.neo4j.repository.Neo4jRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -@Repository -public interface MovieRepository extends Neo4jRepository { - - Movie findByTitle(@Param("title") String title); - - @Query("MATCH (m:Movie) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m") - Collection findByTitleContaining(@Param("title") String title); - - @Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person) RETURN m.title as movie, collect(a.name) as cast LIMIT {limit}") - List> graph(@Param("limit") int limit); -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/PersonRepository.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/PersonRepository.java deleted file mode 100644 index 22094d26b6..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/repository/PersonRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.baeldung.spring.data.neo4j.repository; - -import com.baeldung.spring.data.neo4j.domain.Person; -import org.springframework.data.neo4j.repository.Neo4jRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface PersonRepository extends Neo4jRepository { -} diff --git a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java b/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java deleted file mode 100644 index 086bf48bfa..0000000000 --- a/persistence-modules/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/services/MovieService.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.spring.data.neo4j.services; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.baeldung.spring.data.neo4j.repository.MovieRepository; - -import java.util.*; - -@Service -@Transactional -public class MovieService { - - @Autowired - private MovieRepository movieRepository; - - private Map toD3Format(Iterator> result) { - List> nodes = new ArrayList<>(); - List> rels = new ArrayList<>(); - int i = 0; - while (result.hasNext()) { - Map row = result.next(); - nodes.add(map("title", row.get("movie"), "label", "movie")); - int target = i; - i++; - for (Object name : (Collection) row.get("cast")) { - Map actor = map("title", name, "label", "actor"); - int source = nodes.indexOf(actor); - if (source == -1) { - nodes.add(actor); - source = i++; - } - rels.add(map("source", source, "target", target)); - } - } - return map("nodes", nodes, "links", rels); - } - - private Map map(String key1, Object value1, String key2, Object value2) { - Map result = new HashMap<>(2); - result.put(key1, value1); - result.put(key2, value2); - return result; - } - - public Map graph(int limit) { - Iterator> result = movieRepository.graph(limit).iterator(); - return toD3Format(result); - } -} diff --git a/persistence-modules/spring-data-neo4j/src/main/resources/application.properties b/persistence-modules/spring-data-neo4j/src/main/resources/application.properties new file mode 100644 index 0000000000..6a0b6712fd --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.neo4j.uri=bolt://localhost:7687 +spring.neo4j.authentication.username=neo4j +spring.neo4j.authentication.password=password \ No newline at end of file diff --git a/persistence-modules/spring-data-neo4j/src/main/resources/test.png b/persistence-modules/spring-data-neo4j/src/main/resources/test.png deleted file mode 100644 index c3b5e80276..0000000000 Binary files a/persistence-modules/spring-data-neo4j/src/main/resources/test.png and /dev/null differ diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookAndAuthorRepositoryIntegrationTest.java b/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookAndAuthorRepositoryIntegrationTest.java new file mode 100644 index 0000000000..f08af19825 --- /dev/null +++ b/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/BookAndAuthorRepositoryIntegrationTest.java @@ -0,0 +1,69 @@ +package com.baeldung.spring.data.neo4j; + +import com.baeldung.spring.data.neo4j.domain.Book; +import com.baeldung.spring.data.neo4j.repository.AuthorRepository; +import com.baeldung.spring.data.neo4j.repository.BookRepository; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.harness.Neo4j; +import org.neo4j.harness.Neo4jBuilders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import java.util.List; + +@DataNeo4jTest +public class BookAndAuthorRepositoryIntegrationTest { + + private static Neo4j newServer; + + @BeforeAll + static void initializeNeo4j() { + newServer = Neo4jBuilders.newInProcessBuilder() + .withDisabledServer() + .withFixture("CREATE (b:Book {isbn: '978-0547928210', name: 'The Fellowship of the Ring', year: 1954})" + + "-[:WRITTEN_BY]->(a:Author {id: 1, name: 'J. R. R. Tolkien'})" + + "CREATE (b2:Book {isbn: '978-0547928203', name: 'The Two Towers', year: 1956})-[:WRITTEN_BY]->(a)") + .build(); + } + + @AfterAll + static void stopNeo4j() { + newServer.close(); + } + + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + registry.add("spring.neo4j.uri", newServer::boltURI); + registry.add("spring.neo4j.authentication.username", () -> "neo4j"); + registry.add("spring.neo4j.authentication.password", () -> "null"); + } + + @Autowired + private BookRepository bookRepository; + + @Autowired + private AuthorRepository authorRepository; + + @Test + void givenBookExists_whenFindOneByTitle_thenBookIsReturned() { + Book book = bookRepository.findOneByTitle("The Two Towers"); + Assertions.assertEquals("978-0547928203", book.getIsbn()); + } + + @Test + void givenOneBookExistsForYear_whenFindAllByYear_thenOneBookIsReturned() { + List books = bookRepository.findAllByYear(1954); + Assertions.assertEquals(1, books.size()); + } + + @Test + void givenOneBookExistsAfterYear_whenFindBooksAfterYear_thenOneBookIsReturned() { + List books = authorRepository.findBooksAfterYear("J. R. R. Tolkien", 1955); + Assertions.assertEquals(1, books.size()); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryIntegrationTest.java b/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryIntegrationTest.java deleted file mode 100644 index 3d9215f32f..0000000000 --- a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/spring/data/neo4j/MovieRepositoryIntegrationTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.baeldung.spring.data.neo4j; - -import com.baeldung.spring.data.neo4j.config.MovieDatabaseNeo4jTestConfiguration; -import com.baeldung.spring.data.neo4j.domain.Movie; -import com.baeldung.spring.data.neo4j.domain.Person; -import com.baeldung.spring.data.neo4j.domain.Role; -import com.baeldung.spring.data.neo4j.repository.MovieRepository; -import com.baeldung.spring.data.neo4j.repository.PersonRepository; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import java.util.*; - -import static junit.framework.TestCase.assertNull; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = MovieDatabaseNeo4jTestConfiguration.class) -@ActiveProfiles(profiles = "test") -public class MovieRepositoryIntegrationTest { - - @Autowired - private MovieRepository movieRepository; - - @Autowired - private PersonRepository personRepository; - - public MovieRepositoryIntegrationTest() { - } - - @Before - public void initializeDatabase() { - System.out.println("seeding embedded database"); - Movie italianJob = new Movie(); - italianJob.setTitle("The Italian Job"); - italianJob.setReleased(1999); - movieRepository.save(italianJob); - - Person mark = new Person(); - mark.setName("Mark Wahlberg"); - personRepository.save(mark); - - Role charlie = new Role(); - charlie.setMovie(italianJob); - charlie.setPerson(mark); - Collection roleNames = new HashSet<>(); - roleNames.add("Charlie Croker"); - charlie.setRoles(roleNames); - List roles = new ArrayList<>(); - roles.add(charlie); - italianJob.setRoles(roles); - movieRepository.save(italianJob); - } - - @Test - @DirtiesContext - public void testFindByTitle() { - System.out.println("findByTitle"); - String title = "The Italian Job"; - Movie result = movieRepository.findByTitle(title); - assertNotNull(result); - assertEquals(1999, result.getReleased()); - } - - @Test - @DirtiesContext - public void testCount() { - System.out.println("count"); - long movieCount = movieRepository.count(); - assertNotNull(movieCount); - assertEquals(1, movieCount); - } - - @Test - @DirtiesContext - public void testFindAll() { - System.out.println("findAll"); - Collection result = (Collection) movieRepository.findAll(); - assertNotNull(result); - assertEquals(1, result.size()); - } - - @Test - @DirtiesContext - public void testFindByTitleContaining() { - System.out.println("findByTitleContaining"); - String title = "Italian"; - Collection result = movieRepository.findByTitleContaining(title); - assertNotNull(result); - assertEquals(1, result.size()); - } - - @Test - @DirtiesContext - public void testGraph() { - System.out.println("graph"); - List> graph = movieRepository.graph(5); - assertEquals(1, graph.size()); - Map map = graph.get(0); - assertEquals(2, map.size()); - String[] cast = (String[]) map.get("cast"); - String movie = (String) map.get("movie"); - assertEquals("The Italian Job", movie); - assertEquals("Mark Wahlberg", cast[0]); - } - - @Test - @DirtiesContext - public void testDeleteMovie() { - System.out.println("deleteMovie"); - movieRepository.delete(movieRepository.findByTitle("The Italian Job")); - assertNull(movieRepository.findByTitle("The Italian Job")); - } - - @Test - @DirtiesContext - public void testDeleteAll() { - System.out.println("deleteAll"); - movieRepository.deleteAll(); - Collection result = (Collection) movieRepository.findAll(); - assertEquals(0, result.size()); - } -} diff --git a/persistence-modules/spring-data-shardingsphere/pom.xml b/persistence-modules/spring-data-shardingsphere/pom.xml index 1f37bed4cc..c1ca313038 100644 --- a/persistence-modules/spring-data-shardingsphere/pom.xml +++ b/persistence-modules/spring-data-shardingsphere/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-data-shardingsphere 1.0 diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java similarity index 98% rename from persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java rename to persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java index 938d250058..139081182f 100644 --- a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java @@ -21,7 +21,7 @@ import java.util.List; @Testcontainers @SpringBootTest -class OrderServiceIntegrationTest { +class OrderServiceLiveTest { @Container static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java new file mode 100644 index 0000000000..895dd52afb --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java @@ -0,0 +1,90 @@ +package com.baeldung.shardingsphere; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import java.util.List; + + +/** + * This Manual test requires: Docker service running. + */ +@Testcontainers +@SpringBootTest +class OrderServiceManualTest { + + @Container + static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds0") + .withUsername("test") + .withPassword("test"); + + @Container + static MySQLContainer mySQLContainer2 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds1") + .withUsername("test") + .withPassword("test"); + + static { + mySQLContainer2.setPortBindings(List.of("13307:3306")); + mySQLContainer1.setPortBindings(List.of("13306:3306")); + } + @Autowired + private OrderService orderService; + + @Autowired + private OrderRepository orderRepository; + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); + } + + @Test + void shouldFindOrderInCorrectShard() { + // given + Order order1 = new Order(1L, 1L, BigDecimal.TEN, Status.PROCESSING, LocalDate.now(), "123 Main St"); + Order order2 = new Order(2L, 2L, BigDecimal.valueOf(12.5), Status.SHIPPED, LocalDate.now(), "456 Main St"); + + // when + Order savedOrder1 = orderService.createOrder(order1); + Order savedOrder2 = orderService.createOrder(order2); + + // then + // Assuming the sharding strategy is based on the order id, data for order1 should be present only in ds0 + // and data for order2 should be present only in ds1 + Assertions.assertThat(orderService.getOrder(savedOrder1.getOrderId())).isEqualTo(savedOrder1); + Assertions.assertThat(orderService.getOrder(savedOrder2.getOrderId())).isEqualTo(savedOrder2); + + // Verify that the orders are not present in the wrong shards. + // You would need to implement these methods in your OrderService. + // They should use a JdbcTemplate or EntityManager to execute SQL directly against each shard. + Assertions.assertThat(assertOrderInShard(savedOrder1, mySQLContainer2)).isTrue(); + Assertions.assertThat(assertOrderInShard(savedOrder2, mySQLContainer1)).isTrue(); + } + + private boolean assertOrderInShard(Order order, MySQLContainer container) { + try (Connection conn = DriverManager.getConnection(container.getJdbcUrl(), container.getUsername(), container.getPassword())) { + PreparedStatement stmt = conn.prepareStatement("SELECT * FROM `order` WHERE order_id = ?"); + stmt.setLong(1, order.getOrderId()); + ResultSet rs = stmt.executeQuery(); + return rs.next(); + } catch (SQLException ex) { + throw new RuntimeException("Error querying order in shard", ex); + } + } +} diff --git a/persistence-modules/spring-data-yugabytedb/pom.xml b/persistence-modules/spring-data-yugabytedb/pom.xml index cf85988ac3..d7f7576cfe 100644 --- a/persistence-modules/spring-data-yugabytedb/pom.xml +++ b/persistence-modules/spring-data-yugabytedb/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-data-yugabytedb 1.0 diff --git a/persistence-modules/spring-hibernate-5/README.md b/persistence-modules/spring-hibernate-5/README.md index e2344fd585..ce78e5a0df 100644 --- a/persistence-modules/spring-hibernate-5/README.md +++ b/persistence-modules/spring-hibernate-5/README.md @@ -4,10 +4,7 @@ This module contains articles about Hibernate 5 with Spring. ### Relevant articles -- [Programmatic Transactions in the Spring TestContext Framework](https://www.baeldung.com/spring-test-programmatic-transactions) - [Introduction to Hibernate Search](https://www.baeldung.com/hibernate-search) -- [@DynamicUpdate with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-dynamicupdate) - [Hibernate Second-Level Cache](http://www.baeldung.com/hibernate-second-level-cache) - [Deleting Objects with Hibernate](http://www.baeldung.com/delete-with-hibernate) - [Spring, Hibernate and a JNDI Datasource](http://www.baeldung.com/spring-persistence-jpa-jndi-datasource) -- [Bootstrapping Hibernate 5 with Spring](https://www.baeldung.com/hibernate-5-spring) diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java deleted file mode 100644 index b3e979478f..0000000000 --- a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.hibernate.bootstrap; - -import com.google.common.base.Preconditions; -import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.Environment; -import org.springframework.orm.hibernate5.HibernateTransactionManager; -import org.springframework.orm.hibernate5.LocalSessionFactoryBean; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.EnableTransactionManagement; - -import javax.sql.DataSource; -import java.util.Properties; - -@Configuration -@EnableTransactionManagement -@ImportResource({ "classpath:hibernate5Configuration.xml" }) -public class HibernateXMLConf { - -} diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java deleted file mode 100644 index fc183d1f19..0000000000 --- a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.baeldung.hibernate.dynamicupdate; - -import javax.transaction.Transactional; - -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.annotation.Commit; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; - -import com.baeldung.hibernate.dynamicupdate.model.Account; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = DynamicUpdateConfig.class, loader = AnnotationConfigContextLoader.class) -@Transactional -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class DynamicUpdateIntegrationTest { - - private static final Integer ACCOUNT_ID = 1; - - @Autowired - private AccountRepository accountRepository; - - @Test - @Commit - public void testA_whenTestAccountIsSaved_thenSuccess() { - Account account = new Account(ACCOUNT_ID, "account1", "regional", true); - accountRepository.save(account); - } - - @Test - @Commit - // Enable Hibernate's debug logging in logback.xml to see the generated SQL statement. - public void testB_whenAccountNameUpdated_thenSuccess() { - Account account = accountRepository.findOne(ACCOUNT_ID); - account.setName("Test Account"); - accountRepository.save(account); - } - -} diff --git a/spring-reactive-modules/spring-5-reactive/.gitignore b/persistence-modules/spring-hibernate-6/.gitignore similarity index 92% rename from spring-reactive-modules/spring-5-reactive/.gitignore rename to persistence-modules/spring-hibernate-6/.gitignore index dec013dfa4..83c05e60c8 100644 --- a/spring-reactive-modules/spring-5-reactive/.gitignore +++ b/persistence-modules/spring-hibernate-6/.gitignore @@ -1,5 +1,6 @@ +*.class + #folders# -.idea /target /neoDb* /data diff --git a/persistence-modules/spring-hibernate-6/README.md b/persistence-modules/spring-hibernate-6/README.md new file mode 100644 index 0000000000..86a1c919f3 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/README.md @@ -0,0 +1,9 @@ +## Hibernate 6 with Spring + +This module contains articles about Hibernate 6 with Spring. + +### Relevant articles + +- [Programmatic Transactions in the Spring TestContext Framework](https://www.baeldung.com/spring-test-programmatic-transactions) +- [@DynamicUpdate with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-dynamicupdate) +- [Bootstrapping Hibernate with Spring](https://www.baeldung.com/hibernate-spring) diff --git a/persistence-modules/spring-hibernate-6/pom.xml b/persistence-modules/spring-hibernate-6/pom.xml new file mode 100644 index 0000000000..a13117e68c --- /dev/null +++ b/persistence-modules/spring-hibernate-6/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + spring-hibernate-6 + 0.1-SNAPSHOT + spring-hibernate-6 + + + com.baeldung + persistence-modules + 1.0.0-SNAPSHOT + + + + + + org.springframework + spring-context + ${org.springframework.version} + + + commons-logging + commons-logging + + + + + org.springframework + spring-aspects + ${org.springframework.version} + + + + org.springframework + spring-orm + ${org.springframework.version} + + + org.springframework.data + spring-data-jpa + ${org.springframework.data.version} + + + org.hibernate.orm + hibernate-core + ${hibernate.version} + + + org.apache.tomcat + tomcat-dbcp + ${tomcat-dbcp.version} + + + + + com.google.guava + guava + ${guava.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + test + + + org.springframework + spring-test + ${org.springframework.version} + test + + + org.springframework.security + spring-security-test + ${org.springframework.security.version} + test + + + org.hsqldb + hsqldb + ${hsqldb.version} + + + mysql + mysql-connector-java + ${mysql-connector-java.version} + + + com.h2database + h2 + ${h2.version} + + + + + + 6.0.11 + 3.1.3 + 6.1.3 + + 6.2.8.Final + 8.0.7-dmr + 9.0.80 + + + \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java similarity index 100% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java similarity index 100% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java new file mode 100644 index 0000000000..220c18bccf --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java @@ -0,0 +1,12 @@ +package com.baeldung.hibernate.bootstrap; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableTransactionManagement +@ImportResource({ "classpath:hibernate6Configuration.xml" }) +public class HibernateXMLConf { + +} diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java similarity index 86% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java index cae41db831..d260fed7a1 100644 --- a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java @@ -1,7 +1,7 @@ package com.baeldung.hibernate.bootstrap.model; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Entity public class TestEntity { diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/AccountRepository.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/AccountRepository.java similarity index 100% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/AccountRepository.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/AccountRepository.java diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java similarity index 98% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java index 23e28a9e3b..766295f67a 100644 --- a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateConfig.java @@ -2,7 +2,7 @@ package com.baeldung.hibernate.dynamicupdate; import java.util.Properties; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java similarity index 94% rename from persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java rename to persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java index b3753112fe..808ffe99ee 100644 --- a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/hibernate/dynamicupdate/model/Account.java @@ -2,9 +2,9 @@ package com.baeldung.hibernate.dynamicupdate.model; import java.text.MessageFormat; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; import org.hibernate.annotations.DynamicUpdate; diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/IFooDao.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/IFooDao.java new file mode 100644 index 0000000000..0935772dbd --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/IFooDao.java @@ -0,0 +1,8 @@ +package com.baeldung.persistence.dao; + +import com.baeldung.persistence.model.Foo; +import com.baeldung.persistence.dao.common.IOperations; + +public interface IFooDao extends IOperations { + // +} diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractDao.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractDao.java new file mode 100644 index 0000000000..5a6c76a93a --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractDao.java @@ -0,0 +1,14 @@ +package com.baeldung.persistence.dao.common; + +import java.io.Serializable; + +import com.google.common.base.Preconditions; + +public abstract class AbstractDao implements IOperations { + + protected Class clazz; + + protected final void setClazz(final Class clazzToSet) { + clazz = Preconditions.checkNotNull(clazzToSet); + } +} diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractHibernateDao.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractHibernateDao.java new file mode 100644 index 0000000000..f34866d883 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/AbstractHibernateDao.java @@ -0,0 +1,59 @@ +package com.baeldung.persistence.dao.common; + +import java.io.Serializable; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.base.Preconditions; + +@SuppressWarnings("unchecked") +public abstract class AbstractHibernateDao extends AbstractDao implements IOperations { + + @Autowired + protected SessionFactory sessionFactory; + + // API + + @Override + public T findOne(final long id) { + return (T) getCurrentSession().get(clazz, id); + } + + @Override + public List findAll() { + return getCurrentSession().createQuery("from " + clazz.getName()).getResultList(); + } + + @Override + public void create(final T entity) { + Preconditions.checkNotNull(entity); + getCurrentSession().saveOrUpdate(entity); + } + + @Override + public T update(final T entity) { + Preconditions.checkNotNull(entity); + return (T) getCurrentSession().merge(entity); + } + + @Override + public void delete(final T entity) { + Preconditions.checkNotNull(entity); + getCurrentSession().delete(entity); + } + + @Override + public void deleteById(final long entityId) { + final T entity = findOne(entityId); + Preconditions.checkState(entity != null); + delete(entity); + } + + protected Session getCurrentSession() { + return sessionFactory.getCurrentSession(); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/IOperations.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/IOperations.java new file mode 100644 index 0000000000..4ef99221ab --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/common/IOperations.java @@ -0,0 +1,20 @@ +package com.baeldung.persistence.dao.common; + +import java.io.Serializable; +import java.util.List; + +public interface IOperations { + + T findOne(final long id); + + List findAll(); + + void create(final T entity); + + T update(final T entity); + + void delete(final T entity); + + void deleteById(final long entityId); + +} diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/impl/FooHibernateDao.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/impl/FooHibernateDao.java new file mode 100644 index 0000000000..5411073360 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/dao/impl/FooHibernateDao.java @@ -0,0 +1,19 @@ +package com.baeldung.persistence.dao.impl; + +import com.baeldung.persistence.dao.common.AbstractHibernateDao; +import com.baeldung.persistence.dao.IFooDao; +import com.baeldung.persistence.model.Foo; +import org.springframework.stereotype.Repository; + +@Repository +public class FooHibernateDao extends AbstractHibernateDao implements IFooDao { + + public FooHibernateDao() { + super(); + + setClazz(Foo.class); + } + + // API + +} diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/model/Foo.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/model/Foo.java new file mode 100644 index 0000000000..c9a541290d --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/persistence/model/Foo.java @@ -0,0 +1,73 @@ +package com.baeldung.persistence.model; + +import jakarta.persistence.*; +import java.io.Serializable; + +@Entity +public class Foo implements Serializable{ + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private long id; + + @Column(name = "name") + private String name; + + public Foo() { + super(); + } + + public Foo(final String name) { + super(); + this.name = name; + } + + 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; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Foo other = (Foo) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("Foo [name=").append(name).append("]"); + return builder.toString(); + } +} diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceConfig.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceConfig.java new file mode 100644 index 0000000000..04961c3c49 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceConfig.java @@ -0,0 +1,82 @@ +package com.baeldung.spring; + +import com.baeldung.persistence.dao.IFooDao; +import com.baeldung.persistence.dao.impl.FooHibernateDao; +import com.google.common.base.Preconditions; +import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.Properties; + +@Configuration +@EnableTransactionManagement +@PropertySource({ "classpath:persistence-h2.properties" }) +@ComponentScan({ "com.baeldung.persistence" }) +public class PersistenceConfig { + + @Autowired + private Environment env; + + @Bean + public LocalSessionFactoryBean sessionFactory() { + final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); + sessionFactory.setDataSource(myDataSource()); + sessionFactory.setPackagesToScan(new String[] { "com.baeldung.persistence.model" }); + sessionFactory.setHibernateProperties(hibernateProperties()); + + return sessionFactory; + } + + @Bean + public DataSource myDataSource() { + final BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); + dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url"))); + dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); + dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); + + return dataSource; + } + + @Bean + public PlatformTransactionManager hibernateTransactionManager() { + final HibernateTransactionManager transactionManager = new HibernateTransactionManager(); + transactionManager.setSessionFactory(sessionFactory().getObject()); + return transactionManager; + } + + @Bean + public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { + return new PersistenceExceptionTranslationPostProcessor(); + } + + @Bean + public IFooDao fooHibernateDao() { + return new FooHibernateDao(); + } + + private final Properties hibernateProperties() { + final Properties hibernateProperties = new Properties(); + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + + hibernateProperties.setProperty("hibernate.show_sql", "false"); + + // Envers properties + hibernateProperties.setProperty("org.hibernate.envers.audit_table_suffix", env.getProperty("envers.audit_table_suffix")); + + return hibernateProperties; + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceXmlConfig.java b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceXmlConfig.java new file mode 100644 index 0000000000..14caf5c88c --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/java/com/baeldung/spring/PersistenceXmlConfig.java @@ -0,0 +1,14 @@ +package com.baeldung.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableTransactionManagement +@ComponentScan({ "com.baeldung.persistence.dao", "com.baeldung.persistence.service" }) +@ImportResource({ "classpath:hibernate6Config.xml" }) +public class PersistenceXmlConfig { + +} \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Config.xml b/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Config.xml new file mode 100644 index 0000000000..bbb61cb3e0 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Config.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + ${hibernate.hbm2ddl.auto} + ${hibernate.dialect} + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Configuration.xml b/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Configuration.xml new file mode 100644 index 0000000000..cb6cf0aa5c --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/hibernate6Configuration.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + ${hibernate.hbm2ddl.auto} + ${hibernate.dialect} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/logback.xml b/persistence-modules/spring-hibernate-6/src/main/resources/logback.xml new file mode 100644 index 0000000000..ec0dc2469a --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/persistence-h2.properties b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-h2.properties new file mode 100644 index 0000000000..2ed7022eab --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-h2.properties @@ -0,0 +1,22 @@ +# jdbc.X +jdbc.driverClassName=org.h2.Driver +jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +jdbc.eventGeneratedId=sa +jdbc.user=sa +jdbc.pass= + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create-drop +hibernate.cache.use_second_level_cache=true +hibernate.cache.use_query_cache=true +hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory + + +# hibernate.search.X +hibernate.search.default.directory_provider = filesystem +hibernate.search.default.indexBase = /data/index/default + +# envers.X +envers.audit_table_suffix=_audit_log diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/persistence-jndi.properties b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-jndi.properties new file mode 100644 index 0000000000..16d750d7f8 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-jndi.properties @@ -0,0 +1,8 @@ +# jdbc.X +jdbc.url=java:comp/env/jdbc/BaeldungDatabase + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=false +#hibernate.hbm2ddl.auto=create +hibernate.hbm2ddl.auto=update \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-6/src/main/resources/persistence-mysql.properties b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-mysql.properties new file mode 100644 index 0000000000..b3cfd31f46 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/main/resources/persistence-mysql.properties @@ -0,0 +1,13 @@ +# jdbc.X +jdbc.driverClassName=com.mysql.cj.jdbc.Driver +jdbc.url=jdbc:mysql://localhost:3306/spring_hibernate5_01?createDatabaseIfNotExist=true +jdbc.eventGeneratedId=tutorialuser +jdbc.pass=tutorialmy5ql + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create-drop + +# envers.X +envers.audit_table_suffix=_audit_log diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/SpringContextTest.java b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/SpringContextTest.java similarity index 60% rename from persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/SpringContextTest.java rename to persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/SpringContextTest.java index 7029905c49..4ec83cda3e 100644 --- a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/SpringContextTest.java +++ b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/SpringContextTest.java @@ -2,18 +2,18 @@ package com.baeldung; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; -import com.baeldung.spring.data.neo4j.config.MovieDatabaseNeo4jTestConfiguration; +import com.baeldung.spring.PersistenceConfig; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = MovieDatabaseNeo4jTestConfiguration.class) -@ActiveProfiles(profiles = "test") +@ContextConfiguration(classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class) public class SpringContextTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } } diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java similarity index 79% rename from persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java rename to persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java index c41423643a..31522288b6 100644 --- a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java +++ b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java @@ -1,33 +1,36 @@ package com.baeldung.hibernate.bootstrap; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.baeldung.hibernate.bootstrap.model.TestEntity; + + import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.Commit; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.transaction.TestTransaction; import org.springframework.transaction.annotation.Transactional; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { HibernateConf.class }) @Transactional -public class HibernateBootstrapIntegrationTest { +@ContextConfiguration(classes = { HibernateXMLConf.class }) +@ExtendWith(SpringExtension.class) +class HibernateBootstrapIntegrationTest { @Autowired private SessionFactory sessionFactory; @Test - public void whenBootstrapHibernateSession_thenNoException() { + void whenBootstrapHibernateSession_thenNoException() { Session session = sessionFactory.getCurrentSession(); @@ -37,11 +40,11 @@ public class HibernateBootstrapIntegrationTest { TestEntity searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); } @Test - public void whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { + void whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { assertTrue(TestTransaction.isActive()); //Save an entity and commit. @@ -53,7 +56,7 @@ public class HibernateBootstrapIntegrationTest { TestEntity searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertTrue(TestTransaction.isFlaggedForRollback()); TestTransaction.flagForCommit(); @@ -72,7 +75,7 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); session.delete(searchEntity); session.flush(); @@ -88,7 +91,7 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); session.delete(searchEntity); session.flush(); @@ -108,12 +111,12 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNull(searchEntity); + assertNull(searchEntity); } @Test @Commit - public void givenTransactionCommitDefault_whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { + void givenTransactionCommitDefault_whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { assertTrue(TestTransaction.isActive()); //Save an entity and commit. @@ -125,7 +128,7 @@ public class HibernateBootstrapIntegrationTest { TestEntity searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); assertFalse(TestTransaction.isFlaggedForRollback()); TestTransaction.end(); @@ -143,7 +146,7 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); session.delete(searchEntity); session.flush(); @@ -160,7 +163,7 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); session.delete(searchEntity); session.flush(); @@ -179,7 +182,7 @@ public class HibernateBootstrapIntegrationTest { session = sessionFactory.getCurrentSession(); searchEntity = session.find(TestEntity.class, 1); - Assert.assertNull(searchEntity); + assertNull(searchEntity); } } diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java similarity index 65% rename from persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java rename to persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java index 5b811ad576..153e6736f1 100644 --- a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java +++ b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java @@ -1,26 +1,27 @@ package com.baeldung.hibernate.bootstrap; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.baeldung.hibernate.bootstrap.model.TestEntity; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; -@RunWith(SpringJUnit4ClassRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { HibernateXMLConf.class }) @Transactional -public class HibernateXMLBootstrapIntegrationTest { +class HibernateXMLBootstrapIntegrationTest { @Autowired private SessionFactory sessionFactory; @Test - public void whenBootstrapHibernateSession_thenNoException() { + void whenBootstrapHibernateSession_thenNoException() { Session session = sessionFactory.getCurrentSession(); @@ -30,7 +31,7 @@ public class HibernateXMLBootstrapIntegrationTest { TestEntity searchEntity = session.find(TestEntity.class, 1); - Assert.assertNotNull(searchEntity); + assertNotNull(searchEntity); } } diff --git a/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java new file mode 100644 index 0000000000..9a52599842 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/hibernate/dynamicupdate/DynamicUpdateIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.hibernate.dynamicupdate; + +import java.util.Optional; + +import jakarta.transaction.Transactional; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.Commit; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import com.baeldung.hibernate.dynamicupdate.model.Account; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { DynamicUpdateConfig.class }, loader = AnnotationConfigContextLoader.class) +@Transactional +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class DynamicUpdateIntegrationTest { + + private static final Integer ACCOUNT_ID = 1; + + @Autowired + private AccountRepository accountRepository; + + @Test + @Commit + @Order(1) + void testA_whenTestAccountIsSaved_thenSuccess() { + Account account = new Account(ACCOUNT_ID, "account1", "regional", true); + accountRepository.save(account); + } + + @Test + @Commit + @Order(2) + // Enable Hibernate's debug logging in logback.xml to see the generated SQL statement. + void testB_whenAccountNameUpdated_thenSuccess() { + Optional account = accountRepository.findById(ACCOUNT_ID); + if(account.isPresent()){ + account.get().setName("Test Account"); + accountRepository.save(account.get()); + } + } + +} diff --git a/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/persistence/dao/common/HibernateDaoIntegrationTest.java b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/persistence/dao/common/HibernateDaoIntegrationTest.java new file mode 100644 index 0000000000..d7069c62c9 --- /dev/null +++ b/persistence-modules/spring-hibernate-6/src/test/java/com/baeldung/persistence/dao/common/HibernateDaoIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.persistence.dao.common; + +import com.baeldung.persistence.model.Foo; +import com.baeldung.spring.PersistenceConfig; +import org.apache.commons.lang3.RandomStringUtils; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class) +class HibernateDaoIntegrationTest { + + @Autowired + private SessionFactory sessionFactory; + + private Session session; + + @BeforeEach + public final void before() { + session = sessionFactory.openSession(); + } + + @AfterEach + public final void after() { + session.close(); + } + + @Test + final void whenContextIsBootstrapped_thenNoExceptions() { + // + } + + @Test + final void whenPersistEntity_thenSuccess() { + session.persist(new Foo(RandomStringUtils.randomAlphabetic(5).toUpperCase())); + } + +} diff --git a/persistence-modules/spring-jdbc-2/pom.xml b/persistence-modules/spring-jdbc-2/pom.xml new file mode 100644 index 0000000000..ce79c1c615 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + org.example + spring-jdbc-2 + 1.0-SNAPSHOT + spring-jdbc-2 + Demo project for Spring Jdbc + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-starter-test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + 3.2.0-SNAPSHOT + 5.10.0 + UTF-8 + + + \ No newline at end of file diff --git a/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/JdbcClientDemoApplication.java b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/JdbcClientDemoApplication.java new file mode 100644 index 0000000000..d10124fdef --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/JdbcClientDemoApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.jdbcclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = "com.baledung.jdbcclient") +public class JdbcClientDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(JdbcClientDemoApplication.class, args); + } +} diff --git a/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/dao/StudentDao.java b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/dao/StudentDao.java new file mode 100644 index 0000000000..ba5bfcee11 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/dao/StudentDao.java @@ -0,0 +1,95 @@ +package com.baeldung.jdbcclient.dao; + +import com.baeldung.jdbcclient.model.Student; +import com.baeldung.jdbcclient.model.StudentResultExtractor; +import com.baeldung.jdbcclient.model.StudentRowMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowCountCallbackHandler; +import org.springframework.jdbc.core.simple.JdbcClient; +import org.springframework.stereotype.Repository; + +import java.sql.Types; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Repository +public class StudentDao { + + private static final Logger logger = LoggerFactory.getLogger(StudentDao.class); + @Autowired + private JdbcClient jdbcClient; + + public Integer insertWithSetParamWithNamedParamAndSqlType(Student student) { + String sql = "INSERT INTO student (student_name, age, grade, gender, state)" + + "VALUES (:name, :age, :grade, :gender, :state)"; + Integer noOfrowsAffected = this.jdbcClient.sql(sql) + .param("name", student.getStudentName(), Types.VARCHAR) + .param("age", student.getAge(), Types.INTEGER) + .param("grade", student.getGrade(), Types.INTEGER) + .param("gender", student.getStudentGender(), Types.VARCHAR) + .param("state", student.getState(), Types.VARCHAR) + .update(); + logger.info("No. of rows affected: " + noOfrowsAffected); + return noOfrowsAffected; + } + + public List getStudentsOfGradeStateAndGenderWithPositionalParams(int grade, String state, String gender) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = ? and state = ? and gender = ?"; + return jdbcClient.sql(sql) + .param(grade) + .param(state) + .param(gender) + .query(new StudentRowMapper()).list(); + } + + public List getStudentsOfGradeStateAndGenderWithParamIndex(int grade, String state, String gender) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = ? and state = ? and gender = ?"; + return jdbcClient.sql(sql) + .param(1,grade) + .param(2, state) + .param(3, gender) + .query(new StudentResultExtractor()); + } + + public Student getStudentsOfGradeStateAndGenderWithParamsInVarargs(int grade, String state, String gender) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = ? and state = ? and gender = ? limit 1"; + return jdbcClient.sql(sql) + .params(grade, state, gender) + .query(new StudentRowMapper()).single(); + } + + public Optional getStudentsOfGradeStateAndGenderWithParamsInList(List params) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = ? and state = ? and gender = ? limit 1"; + return jdbcClient.sql(sql) + .params(params) + .query(new StudentRowMapper()).optional(); + } + + + public int getCountOfStudentsOfGradeStateAndGenderWithNamedParam(int grade, String state, String gender) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = :grade and state = :state and gender = :gender"; + RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler(); + jdbcClient.sql(sql) + .param("grade", grade) + .param("state", state) + .param("gender", gender) + .query(countCallbackHandler); + return countCallbackHandler.getRowCount(); + } + + public List getStudentsOfGradeStateAndGenderWithParamMap(Map paramMap) { + String sql = "select student_id, student_name, age, grade, gender, state from student" + + " where grade = :grade and state = :state and gender = :gender"; + return jdbcClient.sql(sql) + .params(paramMap) + .query(new StudentRowMapper()).list(); + } +} diff --git a/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/Student.java b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/Student.java new file mode 100644 index 0000000000..3de8a6e1f9 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/Student.java @@ -0,0 +1,60 @@ +package com.baeldung.jdbcclient.model; + +public class Student { + private Integer studentId; + private String studentName; + private String studentGender; + private Integer age; + private Integer grade; + + public Integer getStudentId() { + return studentId; + } + + public void setStudentId(Integer studentId) { + this.studentId = studentId; + } + + public String getStudentName() { + return studentName; + } + + public void setStudentName(String studentName) { + this.studentName = studentName; + } + + public String getStudentGender() { + return studentGender; + } + + public void setStudentGender(String studentGender) { + this.studentGender = studentGender; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Integer getGrade() { + return grade; + } + + public void setGrade(Integer grade) { + this.grade = grade; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + private String state; + +} diff --git a/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentResultExtractor.java b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentResultExtractor.java new file mode 100644 index 0000000000..29cb60cee9 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentResultExtractor.java @@ -0,0 +1,26 @@ +package com.baeldung.jdbcclient.model; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class StudentResultExtractor implements ResultSetExtractor> { + @Override + public List extractData(ResultSet rs) throws SQLException { + List students = new ArrayList(); + while(rs.next()) { + Student student = new Student(); + student.setStudentId(rs.getInt("student_id")); + student.setStudentName(rs.getString("student_name")); + student.setAge(rs.getInt("age")); + student.setStudentGender(rs.getString("gender")); + student.setGrade(rs.getInt("grade")); + student.setState(rs.getString("state")); + students.add(student); + } + return students; + } +} diff --git a/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentRowMapper.java b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentRowMapper.java new file mode 100644 index 0000000000..c387a6c485 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/java/com/baeldung/jdbcclient/model/StudentRowMapper.java @@ -0,0 +1,20 @@ +package com.baeldung.jdbcclient.model; + +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class StudentRowMapper implements RowMapper { + @Override + public Student mapRow(ResultSet rs, int rowNum) throws SQLException { + Student student = new Student(); + student.setStudentId(rs.getInt("student_id")); + student.setStudentName(rs.getString("student_name")); + student.setAge(rs.getInt("age")); + student.setStudentGender(rs.getString("gender")); + student.setGrade(rs.getInt("grade")); + student.setState(rs.getString("state")); + return student; + } +} diff --git a/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/application.properties b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/application.properties new file mode 100644 index 0000000000..04c963ebf4 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/application.properties @@ -0,0 +1,5 @@ +# DataSource Configuration +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=user +spring.datasource.password= # Leave this empty \ No newline at end of file diff --git a/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/drop_student.sql b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/drop_student.sql new file mode 100644 index 0000000000..954545a862 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/drop_student.sql @@ -0,0 +1 @@ +DROP TABLE student; \ No newline at end of file diff --git a/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/student.sql b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/student.sql new file mode 100644 index 0000000000..0e137f5445 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/main/resources/jdbcclient/student.sql @@ -0,0 +1,98 @@ + +CREATE TABLE student ( + student_id INT AUTO_INCREMENT PRIMARY KEY, + student_name VARCHAR(255) NOT NULL, + age INT, + grade INT NOT NULL, + gender VARCHAR(10) NOT NULL, + state VARCHAR(100) NOT NULL +); +-- Student 1 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California'); + +-- Student 2 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York'); + +-- Student 3 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Michael Davis', 4, 1, 'Male', 'Texas'); + +-- Student 4 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Martinez', 2, 1, 'Female', 'Florida'); + +-- Student 5 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'California'); + +-- Student 6 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 4, 2, 'Female', 'Texas'); + +-- Student 7 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ethan Rodriguez', 3, 1, 'Male', 'New York'); + +-- Student 8 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Hernandez', 2, 1, 'Female', 'Florida'); + +-- Student 9 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('James Wilson', 5, 4, 'Male', 'Texas'); + +-- Student 10 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Miller', 3, 1, 'Female', 'California'); + +-- Student 11 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Benjamin Brown', 4, 1, 'Male', 'New York'); + +-- Student 12 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mia Smith', 2, 1, 'Female', 'Florida'); + +-- Student 13 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Daniel Johnson', 5, 4, 'Male', 'California'); + +-- Student 14 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Davis', 4, 2, 'Female', 'Texas'); + +-- Student 15 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Matthew Martinez', 3, 1, 'Male', 'New York'); + +-- Student 16 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Taylor', 2, 1, 'Female', 'Florida'); + +-- Student 17 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Alexander White', 5, 4, 'Male', 'California'); + +-- Student 18 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Johnson', 4, 2, 'Female', 'Texas'); + +-- Student 19 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Christopher Lee', 3, 1, 'Male', 'New York'); + +-- Student 20 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Wilson', 2, 1, 'Female', 'Florida'); + +-- Student 21 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Elijah Smith', 5, 3, 'Male', 'Texas'); + +-- Student 22 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Isabella Davis', 4, 2, 'Female', 'California'); + +-- Student 23 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Liam Johnson', 3, 1, 'Male', 'New York'); + +-- Student 24 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 2, 1, 'Female', 'Florida'); + +-- Student 25 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Noah Rodriguez', 5, 3, 'Male', 'Texas'); + +-- Student 26 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Hernandez', 4, 2, 'Female', 'California'); + +-- Student 27 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mason Smith', 3, 1, 'Male', 'New York'); + +-- Student 28 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Taylor', 2, 1, 'Female', 'Florida'); + +-- Student 29 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'Texas'); + +-- Student 30 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Martinez', 4, 4, 'Female', 'California'); diff --git a/persistence-modules/spring-jdbc-2/src/test/java/com/baeldung/jdbcclient/JdbcClientUnitTest.java b/persistence-modules/spring-jdbc-2/src/test/java/com/baeldung/jdbcclient/JdbcClientUnitTest.java new file mode 100644 index 0000000000..be30efcb9c --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/test/java/com/baeldung/jdbcclient/JdbcClientUnitTest.java @@ -0,0 +1,104 @@ +package com.baeldung.jdbcclient; + +import com.baeldung.jdbcclient.dao.StudentDao; +import com.baeldung.jdbcclient.model.Student; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; + +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@Sql(value = "/jdbcclient/student.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(value = "/jdbcclient/drop_student.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +@SpringBootTest(classes = JdbcClientDemoApplication.class) +@TestPropertySource(locations = {"classpath:jdbcclient/application.properties"}) + +public class JdbcClientUnitTest { + private static final Logger logger = LoggerFactory.getLogger(JdbcClientUnitTest.class); + + @Autowired + private StudentDao studentDao; + + @Test + void givenJdbcClient_whenInsertWithNamedParamAndSqlType_thenSuccess() { + logger.info("testing invoked successfully"); + Student student = getSampleStudent("Johny Dep", 8, 4, "Male", "New York"); + assertEquals(1, studentDao.insertWithSetParamWithNamedParamAndSqlType(student)); + } + + @Test + void givenJdbcClient_whenQueryWithPositionalParams_thenSuccess() { + logger.info("testing invoked successfully"); + List students = studentDao.getStudentsOfGradeStateAndGenderWithPositionalParams( + 1, "New York", "Male"); + logger.info("number of students fetched " + students.size()); + assertEquals(6, students.size()); + } + + @Test + void givenJdbcClient_whenQueryWithParamsInVarargs_thenSuccess() { + logger.info("testing invoked successfully"); + Student student = studentDao.getStudentsOfGradeStateAndGenderWithParamsInVarargs( + 1, "New York", "Male"); + assertNotNull(student); + } + + @Test + void givenJdbcClient_whenQueryWithParamsInList_thenSuccess() { + logger.info("testing invoked successfully"); + List params = List.of(1, "New York", "Male"); + Optional optional = studentDao.getStudentsOfGradeStateAndGenderWithParamsInList(params); + if(optional.isPresent()) { + assertNotNull(optional.get()); + } else { + assertThrows(NoSuchElementException.class, () -> optional.get()); + } + } + + @Test + void givenJdbcClient_whenQueryWithParamsIndex_thenSuccess() { + logger.info("testing invoked successfully"); + List students = studentDao.getStudentsOfGradeStateAndGenderWithParamIndex( + 1, "New York", "Male"); + assertEquals(6, students.size()); + } + @Test + void givenJdbcClient_whenQueryWithNamedParam_thenSuccess() { + logger.info("testing invoked successfully"); + Integer count = studentDao.getCountOfStudentsOfGradeStateAndGenderWithNamedParam( + 1, "New York", "Male"); + logger.info("number of students fetched " + count); + assertEquals(6, count); + } + @Test + void givenJdbcClient_whenQueryWithParamMap_thenSuccess() { + logger.info("testing invoked successfully"); + Map paramMap = Map.of( + "grade", 1, + "gender", "Male", + "state", "New York" + ); + List students = studentDao.getStudentsOfGradeStateAndGenderWithParamMap(paramMap); + logger.info("number of students fetched " + students.size()); + assertEquals(6, students.size()); + } + + private Student getSampleStudent(String name, int age, int grade, String gender, String state) { + Student student = new Student(); + student.setStudentName(name); + student.setStudentGender(gender); + student.setAge(age); + student.setGrade(grade); + student.setState(state); + return student; + } +} diff --git a/persistence-modules/spring-jdbc-2/src/test/resources/logback-test.xml b/persistence-modules/spring-jdbc-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..8d4771e308 --- /dev/null +++ b/persistence-modules/spring-jdbc-2/src/test/resources/logback-test.xml @@ -0,0 +1,12 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-jdbc/README.md b/persistence-modules/spring-jdbc/README.md index 21d25915de..19f8537a4e 100644 --- a/persistence-modules/spring-jdbc/README.md +++ b/persistence-modules/spring-jdbc/README.md @@ -7,3 +7,4 @@ - [Obtaining Auto-generated Keys in Spring JDBC](https://www.baeldung.com/spring-jdbc-autogenerated-keys) - [Spring JDBC Batch Inserts](https://www.baeldung.com/spring-jdbc-batch-inserts) - [Fix EmptyResultDataAccessException When Using JdbcTemplate](https://www.baeldung.com/jdbctemplate-fix-emptyresultdataaccessexception) +- [How to replace deprecated jdbcTemplate.queryForObject and jdbcTemplate.query in spring boot 2.4.X and above](https://www.baeldung.com/spring-boot-replace-deprecated-jdbctemplate-queryforobject-query) diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/ReplaceDeprecatedApplication.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/ReplaceDeprecatedApplication.java new file mode 100644 index 0000000000..f1f50dfbf9 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/ReplaceDeprecatedApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.jdbc.replacedeprecated; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = "com.baeldung.spring.jdbc.replacedeprecated") +public class ReplaceDeprecatedApplication { + + public static void main(String[] args) { + SpringApplication.run(ReplaceDeprecatedApplication.class, args); + } +} diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithDeprecatedJdbcTemplateMethods.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithDeprecatedJdbcTemplateMethods.java new file mode 100644 index 0000000000..74e1ea6a0a --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithDeprecatedJdbcTemplateMethods.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.jdbc.replacedeprecated; + +import com.baeldung.spring.jdbc.replacedeprecated.model.Student; +import com.baeldung.spring.jdbc.replacedeprecated.model.StudentResultExtractor; +import com.baeldung.spring.jdbc.replacedeprecated.model.StudentRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowCountCallbackHandler; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class StudentDaoWithDeprecatedJdbcTemplateMethods { + JdbcTemplate jdbcTemplate; + + @Autowired + public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List getStudentsOfAgeAndGender(Integer age, String gender) { + String sql = "select student_id, student_name, age, gender, grade, state from student where age= ? and gender = ?"; + Object[] args = {age, gender}; + return jdbcTemplate.query(sql, args, new StudentRowMapper()); + } + + public List getStudentsOfAgeGenderAndGrade(Integer age, String gender, Integer grade) { + String sql = "select student_id, student_name, age, gender, grade, state from student where age= ? and gender = ? and grade = ?"; + Object[] args = {age, gender, grade}; + return jdbcTemplate.query(sql, args, new StudentRowMapper()); + } + + public List getStudentsOfGradeAndState(Integer grade, String state) { + String sql = "select student_id, student_name, age, gender, grade, state from student where grade = ? and state = ?"; + Object[] args = {grade, state}; + return jdbcTemplate.query(sql, args, new StudentResultExtractor()); + } + + public Student getStudentOfStudentIDAndGrade(Integer studentID, Integer grade) { + String sql = "select student_id, student_name, age, gender, grade, state from student where student_id = ? and grade = ?"; + Object[] args = {studentID, grade}; + + return jdbcTemplate.queryForObject(sql, args, new StudentRowMapper()); + } + + public Integer getCountOfStudentsInAGradeFromAState(Integer grade, String state) { + String sql = "select student_id, student_name, age, gender, grade, state from student where grade = ? and state = ?"; + Object[] args = {grade, state}; + RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler(); + jdbcTemplate.query(sql, args, countCallbackHandler); + return countCallbackHandler.getRowCount(); + } +} diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithPreferredJdbcTemplateMethods.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithPreferredJdbcTemplateMethods.java new file mode 100644 index 0000000000..afe8a8f2bd --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithPreferredJdbcTemplateMethods.java @@ -0,0 +1,56 @@ +package com.baeldung.spring.jdbc.replacedeprecated; + +import com.baeldung.spring.jdbc.replacedeprecated.model.Student; +import com.baeldung.spring.jdbc.replacedeprecated.model.StudentResultExtractor; +import com.baeldung.spring.jdbc.replacedeprecated.model.StudentRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowCountCallbackHandler; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class StudentDaoWithPreferredJdbcTemplateMethods { + JdbcTemplate jdbcTemplate; + + @Autowired + public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List getStudentsOfAgeAndGender(Integer age, String gender) { + String sql = "select student_id, student_name, age, gender, grade, state from student where age= ? and gender = ?"; + return jdbcTemplate.query(sql, new StudentRowMapper(), age, gender); + } + + public List getStudentsOfAgeGenderAndGrade(Integer age, String gender, Integer grade) { + String sql = "select student_id, student_name, age, gender, grade, state from student where age= ? and gender = ? and grade = ?"; + return jdbcTemplate.query(sql, new StudentRowMapper(), age, gender, grade); + } + + public List getStudentsOfGradeAndState(Integer grade, String state) { + String sql = "select student_id, student_name, age, gender, grade, state from student where grade = ? and state = ?"; + return jdbcTemplate.query(sql, new StudentResultExtractor(), grade, state); + } + + public Student getStudentOfStudentIDAndGrade(Integer studentID, Integer grade) { + String sql = "select student_id, student_name, age, gender, grade, state from student where student_id = ? and grade = ?"; + + return jdbcTemplate.queryForObject(sql, new StudentRowMapper(), studentID, grade); + } + + public Integer getCountOfGenderInAGrade(String gender, Integer grade) { + String sql = "select count(1) as total from student where gender = ? and grade = ?"; + + return jdbcTemplate.queryForObject(sql, Integer.class, gender, grade); + } + + public Integer getCountOfStudentsInAGradeFromAState(Integer grade, String state) { + String sql = "select student_id, student_name, age, gender, grade, state from student where grade = ? and state = ?"; + + RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler(); + jdbcTemplate.query(sql, countCallbackHandler, grade, state); + return countCallbackHandler.getRowCount(); + } +} diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/Student.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/Student.java new file mode 100644 index 0000000000..001089d830 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/Student.java @@ -0,0 +1,60 @@ +package com.baeldung.spring.jdbc.replacedeprecated.model; + +public class Student { + private Integer studentId; + private String studentName; + private String studentGender; + private Integer age; + private Integer grade; + + public Integer getStudentId() { + return studentId; + } + + public void setStudentId(Integer studentId) { + this.studentId = studentId; + } + + public String getStudentName() { + return studentName; + } + + public void setStudentName(String studentName) { + this.studentName = studentName; + } + + public String getStudentGender() { + return studentGender; + } + + public void setStudentGender(String studentGender) { + this.studentGender = studentGender; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Integer getGrade() { + return grade; + } + + public void setGrade(Integer grade) { + this.grade = grade; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + private String state; + +} diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentResultExtractor.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentResultExtractor.java new file mode 100644 index 0000000000..d2da59e5f9 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentResultExtractor.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.jdbc.replacedeprecated.model; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class StudentResultExtractor implements ResultSetExtractor> { + @Override + public List extractData(ResultSet rs) throws SQLException { + List students = new ArrayList(); + while(rs.next()) { + Student student = new Student(); + student.setStudentId(rs.getInt("student_id")); + student.setStudentName(rs.getString("student_name")); + student.setAge(rs.getInt("age")); + student.setStudentGender(rs.getString("gender")); + student.setGrade(rs.getInt("grade")); + student.setState(rs.getString("state")); + students.add(student); + } + return students; + } +} diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentRowMapper.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentRowMapper.java new file mode 100644 index 0000000000..bf2419e663 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/replacedeprecated/model/StudentRowMapper.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.jdbc.replacedeprecated.model; + +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class StudentRowMapper implements RowMapper { + @Override + public Student mapRow(ResultSet rs, int rowNum) throws SQLException { + Student student = new Student(); + student.setStudentId(rs.getInt("student_id")); + student.setStudentName(rs.getString("student_name")); + student.setAge(rs.getInt("age")); + student.setStudentGender(rs.getString("gender")); + student.setGrade(rs.getInt("grade")); + student.setState(rs.getString("state")); + return student; + } +} diff --git a/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/application.properties b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/application.properties new file mode 100644 index 0000000000..04c963ebf4 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/application.properties @@ -0,0 +1,5 @@ +# DataSource Configuration +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=user +spring.datasource.password= # Leave this empty \ No newline at end of file diff --git a/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/drop_student.sql b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/drop_student.sql new file mode 100644 index 0000000000..954545a862 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/drop_student.sql @@ -0,0 +1 @@ +DROP TABLE student; \ No newline at end of file diff --git a/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/student.sql b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/student.sql new file mode 100644 index 0000000000..0e137f5445 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/main/resources/com/baeldung/spring/jdbc/replacedeprecated/student.sql @@ -0,0 +1,98 @@ + +CREATE TABLE student ( + student_id INT AUTO_INCREMENT PRIMARY KEY, + student_name VARCHAR(255) NOT NULL, + age INT, + grade INT NOT NULL, + gender VARCHAR(10) NOT NULL, + state VARCHAR(100) NOT NULL +); +-- Student 1 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California'); + +-- Student 2 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York'); + +-- Student 3 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Michael Davis', 4, 1, 'Male', 'Texas'); + +-- Student 4 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Martinez', 2, 1, 'Female', 'Florida'); + +-- Student 5 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'California'); + +-- Student 6 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 4, 2, 'Female', 'Texas'); + +-- Student 7 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ethan Rodriguez', 3, 1, 'Male', 'New York'); + +-- Student 8 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Hernandez', 2, 1, 'Female', 'Florida'); + +-- Student 9 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('James Wilson', 5, 4, 'Male', 'Texas'); + +-- Student 10 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Miller', 3, 1, 'Female', 'California'); + +-- Student 11 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Benjamin Brown', 4, 1, 'Male', 'New York'); + +-- Student 12 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mia Smith', 2, 1, 'Female', 'Florida'); + +-- Student 13 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Daniel Johnson', 5, 4, 'Male', 'California'); + +-- Student 14 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Davis', 4, 2, 'Female', 'Texas'); + +-- Student 15 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Matthew Martinez', 3, 1, 'Male', 'New York'); + +-- Student 16 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Taylor', 2, 1, 'Female', 'Florida'); + +-- Student 17 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Alexander White', 5, 4, 'Male', 'California'); + +-- Student 18 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Johnson', 4, 2, 'Female', 'Texas'); + +-- Student 19 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Christopher Lee', 3, 1, 'Male', 'New York'); + +-- Student 20 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emma Wilson', 2, 1, 'Female', 'Florida'); + +-- Student 21 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Elijah Smith', 5, 3, 'Male', 'Texas'); + +-- Student 22 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Isabella Davis', 4, 2, 'Female', 'California'); + +-- Student 23 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Liam Johnson', 3, 1, 'Male', 'New York'); + +-- Student 24 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Garcia', 2, 1, 'Female', 'Florida'); + +-- Student 25 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Noah Rodriguez', 5, 3, 'Male', 'Texas'); + +-- Student 26 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Sophia Hernandez', 4, 2, 'Female', 'California'); + +-- Student 27 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Mason Smith', 3, 1, 'Male', 'New York'); + +-- Student 28 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Ava Taylor', 2, 1, 'Female', 'Florida'); + +-- Student 29 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('William Brown', 5, 5, 'Male', 'Texas'); + +-- Student 30 +INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Olivia Martinez', 4, 4, 'Female', 'California'); diff --git a/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithJdbcTemplateMethodsUnitTest.java b/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithJdbcTemplateMethodsUnitTest.java new file mode 100644 index 0000000000..ea1a4a8659 --- /dev/null +++ b/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/replacedeprecated/StudentDaoWithJdbcTemplateMethodsUnitTest.java @@ -0,0 +1,131 @@ +package com.baeldung.spring.jdbc.replacedeprecated; + +import com.baeldung.spring.jdbc.replacedeprecated.model.Student; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.test.context.jdbc.Sql; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@JdbcTest +@Sql(value = "student.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(value = "drop_student.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +public class StudentDaoWithJdbcTemplateMethodsUnitTest { + private static final Logger logger = LoggerFactory.getLogger(StudentDaoWithJdbcTemplateMethodsUnitTest.class); + @Autowired + StudentDaoWithDeprecatedJdbcTemplateMethods studentDaoWithDeprecatedJdbcTemplateMethods; + @Autowired + StudentDaoWithPreferredJdbcTemplateMethods studentDaoWithPreferredJdbcTemplateMethods; + + @Test + public void givenPreferredMethodQuery_whenArgsAgeAndGender_thenReturnStudents() { + List students = studentDaoWithPreferredJdbcTemplateMethods.getStudentsOfAgeAndGender(4, "Female"); + + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + " Student gender: " + student.getStudentGender()); + } + assertEquals(6, students.size()); + } + + @Test + public void givenPreferredMethodQuery_whenArgsAgeGenderAndGrade_thenReturnStudents() { + List students = studentDaoWithPreferredJdbcTemplateMethods.getStudentsOfAgeGenderAndGrade(4, "Female", 2); + + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + " Student gender: " + student.getStudentGender() + + " Student grade: " + student.getGrade()); + } + assertEquals(5, students.size()); + } + + @Test + public void givenDeprecatedMethodQuery_whenArgsAgeGenderAndGrade_thenReturnStudents() { + List students = studentDaoWithDeprecatedJdbcTemplateMethods.getStudentsOfAgeGenderAndGrade(4, "Female", 2); + + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + " Student gender: " + student.getStudentGender() + + " Student grade: " + student.getGrade()); + } + assertEquals(5, students.size()); + } + + @Test + public void givenDeprecatedMethodQuery_whenArgsAgeAndGender_thenReturnStudents() { + List students = studentDaoWithDeprecatedJdbcTemplateMethods.getStudentsOfAgeAndGender(4, "Female"); + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + " Student gender: " + student.getStudentGender()); + } + assertEquals(6, students.size()); + } + + @Test + public void givenDeprecatedMethodQuery_whenArgsGradeAndState_thenReturnStudents() { + List students = studentDaoWithDeprecatedJdbcTemplateMethods.getStudentsOfGradeAndState(1, "New York"); + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + + " Student grade: " + student.getStudentGender() + + " Student State: " + student.getState()); + } + assertEquals(6, students.size()); + } + + @Test + public void givenPreferredMethodQuery_whenArgsGradeAndState_thenReturnStudents() { + List students = studentDaoWithPreferredJdbcTemplateMethods.getStudentsOfGradeAndState(1, "New York"); + for (Student student: students) { + logger.info("Student Name: " + student.getStudentName() + + " Student grade: " + student.getStudentGender() + + " Student State: " + student.getState()); + } + assertEquals(6, students.size()); + } + + @Test + public void givenDeprecatedMethodQuery_whenArgsGradeAndState_thenReturnCount() { + Integer count = studentDaoWithDeprecatedJdbcTemplateMethods.getCountOfStudentsInAGradeFromAState(1, "New York"); + logger.info("Total students of grade 1 from New York: " + count); + assertEquals(6, count); + } + @Test + public void givenPreferredMethodQuery_whenArgsGradeAndState_thenReturnCount() { + Integer count = studentDaoWithPreferredJdbcTemplateMethods.getCountOfStudentsInAGradeFromAState(1, "New York"); + logger.info("Total students of grade 1 from New York: " + count); + assertEquals(6, count); + } + @Test + public void givenDeprecatedMethodQueryForObject_whenArgsStudentIDAndGrade_thenReturnStudent() { + Student student = studentDaoWithDeprecatedJdbcTemplateMethods.getStudentOfStudentIDAndGrade(4, 1); + assertEquals(1, student.getGrade()); + assertEquals(4, student.getStudentId()); + logger.info("Student ID: " + student.getStudentId() + + " Student Name: " + student.getStudentName() + " Student grade: " + student.getGrade()); + } + + @Test + public void givenPreferredMethodQueryForObject_whenArgsStudentIDAndGrade_thenReturnStudent() { + Student student = studentDaoWithPreferredJdbcTemplateMethods.getStudentOfStudentIDAndGrade(4, 1); + assertEquals(1, student.getGrade()); + assertEquals(4, student.getStudentId()); + logger.info("Student ID: " + student.getStudentId() + + " Student Name: " + student.getStudentName() + " Student grade: " + student.getGrade()); + } + + @Test + public void givenPreferredMethodQueryForObject_whenArgsGenderAndGrade_thenReturnCount() { + Integer count = studentDaoWithPreferredJdbcTemplateMethods.getCountOfGenderInAGrade("Female", 2); + assertEquals(6, count); + logger.info("Total number of Female Students: " + count); + } + + @Test + public void givenDeprecatedMethodQueryForObject_whenArgsGenderAndGrade_thenReturnCount() { + Integer count = studentDaoWithPreferredJdbcTemplateMethods.getCountOfGenderInAGrade("Female", 2); + assertEquals(6, count); + logger.info("Total number of Female Students: " + count); + } +} diff --git a/pom.xml b/pom.xml index 97e3cf6639..ab1fffa8b9 100644 --- a/pom.xml +++ b/pom.xml @@ -342,16 +342,13 @@ core-java-modules/core-java-8-datetime-2 core-java-modules/core-java-sun core-java-modules/core-java-security - core-java-modules/core-java-nio-2 - core-java-modules/core-java-serialization core-java-modules/core-java-lang core-java-modules/core-java-lang-math-3 - core-java-modules/core-java-collections-conversions-2 + core-java-modules/core-java-streams-2 - @@ -363,14 +360,12 @@ muleesb web-modules/java-lite - web-modules/restx persistence-modules/deltaspike - persistence-modules/hibernate-ogm - persistence-modules/java-cassandra + persistence-modules/hibernate-ogm persistence-modules/spring-data-cassandra-reactive - persistence-modules/spring-data-neo4j java-nashorn jeromq + spring-ejb-modules/ejb-beans @@ -428,7 +423,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials @@ -521,16 +515,13 @@ core-java-modules/core-java-8-datetime-2 core-java-modules/core-java-sun core-java-modules/core-java-security - core-java-modules/core-java-nio-2 - core-java-modules/core-java-serialization core-java-modules/core-java-lang core-java-modules/core-java-lang-math-3 - core-java-modules/core-java-collections-conversions-2 + core-java-modules/core-java-streams-2 - @@ -540,13 +531,12 @@ lombok-modules/lombok-custom muleesb web-modules/java-lite - web-modules/restx persistence-modules/deltaspike - persistence-modules/hibernate-ogm - persistence-modules/java-cassandra + persistence-modules/hibernate-ogm persistence-modules/spring-data-cassandra-reactive - persistence-modules/spring-data-neo4j java-nashorn + jeromq + spring-ejb-modules/ejb-beans @@ -596,7 +586,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials @@ -701,11 +690,11 @@ + parent-boot-3 lombok-modules osgi spring-katharsis logging-modules - spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -731,9 +720,15 @@ spring-boot-rest spring-drools spring-cloud-modules/spring-cloud-azure + spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow - spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-eureka + spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-security + spring-cloud-modules/spring-cloud-stream-starters + spring-cloud-modules/spring-cloud-zuul-eureka-integration + spring-exceptions spring-jenkins-pipeline spring-core @@ -760,6 +755,7 @@ algorithms-modules apache-libraries + apache-libraries-2 apache-poi apache-velocity di-modules @@ -767,21 +763,11 @@ aws-modules checker-framework - couchbase core-groovy-modules core-java-modules - - - - - - - - custom-pmd data-structures - ddd-contexts jackson-modules jmh deeplearning4j @@ -791,7 +777,7 @@ kubernetes-modules libraries-concurrency jhipster-6 - + libraries-testing maven-modules optaplanner persistence-modules @@ -816,7 +802,6 @@ akka-modules - annotations httpclient-simple antlr apache-kafka @@ -824,6 +809,7 @@ apache-olingo apache-poi-2 + apache-poi-3 apache-thrift apache-tika @@ -831,11 +817,8 @@ atomikos atomix - axon - bazel google-auto-project - ddd disruptor dozer dubbo @@ -872,7 +855,7 @@ libraries-apache-commons-2 libraries-apache-commons-collections libraries-apache-commons-io - + libraries-data-2 libraries-data-io libraries-files libraries-http @@ -899,6 +882,7 @@ spring-5 spring-5-webflux spring-5-webflux-2 + spring-6-rsocket spring-activiti spring-actuator spring-core-2 @@ -909,7 +893,8 @@ spring-kafka - + spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -940,6 +925,12 @@ image-processing language-interop gradle-modules/gradle/maven-to-gradle + persistence-modules/spring-data-neo4j + gcp-firebase + spring-di-4 + spring-kafka-2 + + libraries-llms @@ -973,11 +964,11 @@ + parent-boot-3 lombok-modules osgi spring-katharsis logging-modules - spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -1004,6 +995,14 @@ spring-drools spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-eureka + spring-cloud-modules/spring-cloud-contract + spring-cloud-modules/spring-cloud-data-flow + spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-stream-starters + spring-cloud-modules/spring-cloud-security + spring-cloud-modules/spring-cloud-zuul-eureka-integration + spring-exceptions spring-jenkins-pipeline spring-core @@ -1026,6 +1025,7 @@ algorithms-modules apache-libraries + apache-libraries-2 apache-poi apache-velocity di-modules @@ -1033,11 +1033,11 @@ aws-modules checker-framework - couchbase - + core-groovy-modules core-java-modules + gcp-firebase @@ -1050,7 +1050,6 @@ spring-aop-2 custom-pmd data-structures - ddd-contexts jackson-modules jmh deeplearning4j @@ -1061,7 +1060,7 @@ kubernetes-modules libraries-concurrency jhipster-6 - + libraries-testing maven-modules optaplanner persistence-modules @@ -1086,13 +1085,13 @@ akka-modules - annotations antlr apache-kafka apache-kafka-2 apache-olingo apache-poi-2 + apache-poi-3 apache-thrift apache-tika @@ -1100,11 +1099,8 @@ atomikos atomix - axon - bazel google-auto-project - ddd disruptor dozer @@ -1142,7 +1138,7 @@ libraries-apache-commons-2 libraries-apache-commons-collections libraries-apache-commons-io - + libraries-data-2 libraries-data-io libraries-files libraries-http @@ -1180,7 +1176,8 @@ spring-kafka - + spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -1211,6 +1208,12 @@ image-processing language-interop gradle-modules/gradle/maven-to-gradle + persistence-modules/spring-data-neo4j + spring-actuator + spring-di-4 + spring-kafka-2 + + libraries-llms @@ -1261,7 +1264,7 @@ 2.2 1.3 4.4.0 - 1.12.13 + 1.14.6 @@ -1270,38 +1273,38 @@ 2.22.2 - 3.8.1 - 3.0.0 + 3.11.0 + 3.1.0 1.8 1.2.17 1.36 1.36 - 2.21.0 + 3.1.2 4.4 - 2.11.0 + 2.13.0 2.6 - 3.12.0 + 3.13.0 1.5.0 - 3.3.2 + 3.4.0 4.0.1 1.2 2.3.3 1.2 - 2.13.3 - 1.4 + 2.15.2 + 1.5 1.9.2 5.9.2 1.3.2 - 0.3.1 - 2.5.2 + 1.0 + 3.1.1 0.0.1 3.12.2 - 3.0.0 - 3.19.0 + 3.3.0 + 3.21.0 1.18.28 2.1.214 - 31.1-jre - 3.2.2 + 32.1.2-jre + 3.3.0 diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml index df3eca8a4f..74deab3558 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml @@ -255,7 +255,6 @@ 1.17.2 11 0.12.1 - 3.10.1 11 11 3.1.0 diff --git a/quarkus-modules/quarkus/pom.xml b/quarkus-modules/quarkus/pom.xml index 99d18579c3..fc3d294beb 100644 --- a/quarkus-modules/quarkus/pom.xml +++ b/quarkus-modules/quarkus/pom.xml @@ -152,11 +152,8 @@ - native-image + image-build - - true - diff --git a/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeHelloResourceIT.java b/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeHelloResourceIT.java index e6c8a3b8fb..b8567a8609 100644 --- a/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeHelloResourceIT.java +++ b/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeHelloResourceIT.java @@ -2,9 +2,9 @@ package com.baeldung.quarkus; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; -import io.quarkus.test.junit.NativeImageTest; +import io.quarkus.test.junit.QuarkusIntegrationTest; -@NativeImageTest +@QuarkusIntegrationTest @QuarkusTestResource(H2DatabaseTestResource.class) public class NativeHelloResourceIT extends HelloResourceUnitTest { diff --git a/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeLibraryResourceIT.java b/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeLibraryResourceIT.java index 0c11fa6fb4..10539d78d7 100644 --- a/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeLibraryResourceIT.java +++ b/quarkus-modules/quarkus/src/test/java/com/baeldung/quarkus/NativeLibraryResourceIT.java @@ -2,9 +2,9 @@ package com.baeldung.quarkus; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; -import io.quarkus.test.junit.NativeImageTest; +import io.quarkus.test.junit.QuarkusIntegrationTest; -@NativeImageTest +@QuarkusIntegrationTest @QuarkusTestResource(H2DatabaseTestResource.class) class NativeLibraryResourceIT extends LibraryHttpEndpointIntegrationTest { } diff --git a/reactive-systems/docker-compose.yml b/reactive-systems/docker-compose.yml new file mode 100644 index 0000000000..51e15f6a19 --- /dev/null +++ b/reactive-systems/docker-compose.yml @@ -0,0 +1,57 @@ +version: '3' +services: + frontend: + build: ./frontend + ports: + - "80:80" + zookeeper: + image: confluentinc/cp-zookeeper:latest + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 + ports: + - 22181:2181 + kafka: + image: confluentinc/cp-kafka:latest + container_name: kafka-broker + depends_on: + - zookeeper + ports: + - 29092:29092 + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-broker:9092,PLAINTEXT_HOST://localhost:29092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + mongodb: + container_name: mongo-db + image: mongo:6.0 + volumes: + - ~/mongo:/data/db + ports: + - "27017:27017" + healthcheck: + test: exit 0 + order-service: + build: ./order-service + ports: + - "8080:8080" + depends_on: + mongodb: + condition: service_healthy + inventory-service: + build: ./inventory-service + ports: + - "8081:8081" + depends_on: + mongodb: + condition: service_healthy + shipping-service: + build: ./shipping-service + ports: + - "8082:8082" + depends_on: + mongodb: + condition: service_healthy \ No newline at end of file diff --git a/reactive-systems/inventory-service/Dockerfile b/reactive-systems/inventory-service/Dockerfile index d37887cf34..d0900decfa 100644 --- a/reactive-systems/inventory-service/Dockerfile +++ b/reactive-systems/inventory-service/Dockerfile @@ -1,3 +1,3 @@ FROM openjdk:8-jdk-alpine -COPY target/inventory-service-async-0.0.1-SNAPSHOT.jar app.jar +COPY target/inventory-service-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] \ No newline at end of file diff --git a/reactive-systems/order-service/Dockerfile b/reactive-systems/order-service/Dockerfile index 516e088a05..e48c19c2b1 100644 --- a/reactive-systems/order-service/Dockerfile +++ b/reactive-systems/order-service/Dockerfile @@ -1,3 +1,3 @@ FROM openjdk:8-jdk-alpine -COPY target/order-service-async-0.0.1-SNAPSHOT.jar app.jar +COPY target/order-service-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] \ No newline at end of file diff --git a/reactive-systems/shipping-service/Dockerfile b/reactive-systems/shipping-service/Dockerfile index 4906d1d9a8..ff57bb953d 100644 --- a/reactive-systems/shipping-service/Dockerfile +++ b/reactive-systems/shipping-service/Dockerfile @@ -1,3 +1,3 @@ FROM openjdk:8-jdk-alpine -COPY target/shipping-service-async-0.0.1-SNAPSHOT.jar app.jar +COPY target/shipping-service-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-jar","-Dspring.profiles.active=docker","/app.jar"] \ No newline at end of file diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index e27a1a2845..dd7533fe73 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -26,6 +26,11 @@ ${reactor.version} test + + io.projectreactor.addons + reactor-extra + ${reactor.version} + org.projectlombok lombok @@ -35,7 +40,7 @@ - 3.4.17 + 3.5.1 \ No newline at end of file diff --git a/reactor-core/src/test/java/com/baeldung/reactor/math/MathFluxOperationsUnitTest.java b/reactor-core/src/test/java/com/baeldung/reactor/math/MathFluxOperationsUnitTest.java new file mode 100644 index 0000000000..2ff8005acd --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/math/MathFluxOperationsUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.math; + +import org.junit.Test; + +import reactor.math.MathFlux; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +public class MathFluxOperationsUnitTest { + + @Test + public void givenFluxOfNumbers_whenCalculatingSum_thenExpectCorrectResult() { + Flux numbers = Flux.just(1, 2, 3, 4, 5); + Mono sumMono = MathFlux.sumInt(numbers); + StepVerifier.create(sumMono) + .expectNext(15) + .verifyComplete(); + } + + @Test + public void givenFluxOfNumbers_whenCalculatingAverage_thenExpectCorrectResult() { + Flux numbers = Flux.just(1, 2, 3, 4, 5); + Mono averageMono = MathFlux.averageDouble(numbers); + StepVerifier.create(averageMono) + .expectNext(3.0) + .verifyComplete(); + } + + @Test + public void givenFluxOfNumbers_whenFindingMinElement_thenExpectCorrectResult() { + Flux numbers = Flux.just(3, 1, 5, 2, 4); + Mono minMono = MathFlux.min(numbers); + StepVerifier.create(minMono) + .expectNext(1) + .verifyComplete(); + } + + @Test + public void givenFluxOfNumbers_whenFindingMaxElement_thenExpectCorrectResult() { + Flux numbers = Flux.just(3, 1, 5, 2, 4); + Mono maxMono = MathFlux.max(numbers); + StepVerifier.create(maxMono) + .expectNext(5) + .verifyComplete(); + } + +} diff --git a/saas-modules/sentry-servlet/pom.xml b/saas-modules/sentry-servlet/pom.xml index 4f9e37ebd5..70f6876dee 100644 --- a/saas-modules/sentry-servlet/pom.xml +++ b/saas-modules/sentry-servlet/pom.xml @@ -46,6 +46,5 @@ 6.11.0 1.10.4 - 3.3.2 \ No newline at end of file diff --git a/saas-modules/slack/pom.xml b/saas-modules/slack/pom.xml index 326167c055..d9e7abb4a2 100644 --- a/saas-modules/slack/pom.xml +++ b/saas-modules/slack/pom.xml @@ -55,7 +55,6 @@ 1.4 - 2.4 \ No newline at end of file diff --git a/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java index a9c3b4185d..29fb832bd9 100644 --- a/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java +++ b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Date; +import org.junit.Ignore; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -97,13 +98,14 @@ public class Auth0JsonWebTokenUnitTest { assertEquals(DATA, claim.asString()); } - @Test + //Need to fix with JAVA-24552 + @Ignore public void givenJWT_whenCreatedWithNotBefore_thenThrowException() { jwtToken = JWT.create() .withIssuer(ISSUER) .withClaim(DATA_CLAIM, DATA) - .withNotBefore(new Date(System.currentTimeMillis() + 1000L)) + .withNotBefore(new Date(System.currentTimeMillis() + 10000L)) .sign(algorithm); assertThrows(IncorrectClaimException.class, () -> { diff --git a/security-modules/pom.xml b/security-modules/pom.xml index b779c0d46d..864b1a7fcc 100644 --- a/security-modules/pom.xml +++ b/security-modules/pom.xml @@ -25,8 +25,4 @@ sql-injection-samples - - 3.3.2 - - diff --git a/server-modules/undertow/pom.xml b/server-modules/undertow/pom.xml index 42a46d9508..a73771485c 100644 --- a/server-modules/undertow/pom.xml +++ b/server-modules/undertow/pom.xml @@ -46,7 +46,6 @@ 1.4.18.Final - 3.0.2 \ No newline at end of file diff --git a/spring-4/src/test/resources/logback-test.xml b/spring-4/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..a273ab5d26 --- /dev/null +++ b/spring-4/src/test/resources/logback-test.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-5-webflux-2/README.md b/spring-5-webflux-2/README.md index e64c88c61d..1b01f519a4 100644 --- a/spring-5-webflux-2/README.md +++ b/spring-5-webflux-2/README.md @@ -6,3 +6,4 @@ This module contains articles about Spring 5 WebFlux - [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable) - [Comparison Between Mono’s doOnNext() and doOnSuccess()](https://www.baeldung.com/mono-doonnext-doonsuccess) - [How to Access the First Element of a Flux](https://www.baeldung.com/java-flux-first-element) +- [Using zipWhen() with Mono](https://www.baeldung.com/java-mono-zipwhen) diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/model/User.java new file mode 100644 index 0000000000..37008bb061 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/model/User.java @@ -0,0 +1,22 @@ +package com.baeldung.webflux.zipwhen.model; + +public class User { + + private final String id; + private final String email; + + public User(String id, String email) { + this.id = id; + this.email = email; + + } + + public String getId() { + return id; + } + + public String getEmail() { + return email; + } + +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/DatabaseService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/DatabaseService.java new file mode 100644 index 0000000000..d420646871 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/DatabaseService.java @@ -0,0 +1,24 @@ +package com.baeldung.webflux.zipwhen.service; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +public class DatabaseService { + private Map dataStore = new ConcurrentHashMap<>(); + + public Mono saveUserData(User user) { + return Mono.create(sink -> { + try { + dataStore.put(user.getId(), user); + sink.success(true); + } catch (Exception e) { + sink.success(false); + } + }); + } +} + diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java new file mode 100644 index 0000000000..9c0340b7ee --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java @@ -0,0 +1,20 @@ +package com.baeldung.webflux.zipwhen.service; + +import reactor.core.publisher.Mono; + +public class EmailService { + private final UserService userService; + + public EmailService(UserService userService) { + this.userService = userService; + } + + public Mono sendEmail(String userId) { + return userService.getUser(userId) + .flatMap(user -> { + System.out.println("Sending email to: " + user.getEmail()); + return Mono.just(true); + }) + .defaultIfEmpty(false); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/UserService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/UserService.java new file mode 100644 index 0000000000..fe602fbc33 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/UserService.java @@ -0,0 +1,12 @@ +package com.baeldung.webflux.zipwhen.service; + +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +public class UserService { + public Mono getUser(String userId) { + return Mono.just(new User(userId, "john Major")); + } +} + diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java new file mode 100644 index 0000000000..dbd89c45d3 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java @@ -0,0 +1,43 @@ +package com.baeldung.webflux.zipwhen.web; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import com.baeldung.webflux.zipwhen.model.User; +import com.baeldung.webflux.zipwhen.service.DatabaseService; +import com.baeldung.webflux.zipwhen.service.EmailService; +import com.baeldung.webflux.zipwhen.service.UserService; + +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import reactor.util.function.Tuples; + +public class UserController { + private final UserService userService; + private final EmailService emailService; + private final DatabaseService databaseService; + + public UserController(UserService userService, EmailService emailService, DatabaseService databaseService) { + this.userService = userService; + this.emailService = emailService; + this.databaseService = databaseService; + } + + @GetMapping("/example/{userId}") + public Mono> combineAllDataFor(@PathVariable String userId) { + Mono userMono = userService.getUser(userId); + Mono emailSentMono = emailService.sendEmail(userId) + .subscribeOn(Schedulers.parallel()); + Mono databaseResultMono = userMono.flatMap(user -> databaseService.saveUserData(user) + .map(Object::toString)); + + return userMono.zipWhen(user -> emailSentMono, Tuples::of) + .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { + User user = tuple.getT1(); + Boolean emailSent = tuple.getT2(); + return ResponseEntity.ok() + .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); + }); + } +} diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java new file mode 100644 index 0000000000..8ed4cfb6c6 --- /dev/null +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java @@ -0,0 +1,43 @@ +package com.baeldung.webflux.zipwhen; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import com.baeldung.webflux.zipwhen.model.User; +import com.baeldung.webflux.zipwhen.service.DatabaseService; +import com.baeldung.webflux.zipwhen.service.EmailService; +import com.baeldung.webflux.zipwhen.service.UserService; +import com.baeldung.webflux.zipwhen.web.UserController; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +public class UserControllerUnitTest { + @Test + public void givenUserId_whenCombineAllData_thenReturnsMonoWithCombinedData() { + UserService userService = Mockito.mock(UserService.class); + EmailService emailService = Mockito.mock(EmailService.class); + DatabaseService databaseService = Mockito.mock(DatabaseService.class); + + String userId = "123"; + User user = new User(userId, "John Doe"); + + Mockito.when(userService.getUser(userId)) + .thenReturn(Mono.just(user)); + Mockito.when(emailService.sendEmail(userId)) + .thenReturn(Mono.just(true)); + Mockito.when(databaseService.saveUserData(user)) + .thenReturn(Mono.just(true)); + + UserController userController = new UserController(userService, emailService, databaseService); + + Mono> responseMono = userController.combineAllDataFor(userId); + + StepVerifier.create(responseMono) + .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() + .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) + .verifyComplete(); + } +} diff --git a/spring-6-rsocket/README.md b/spring-6-rsocket/README.md new file mode 100644 index 0000000000..95c805b0bf --- /dev/null +++ b/spring-6-rsocket/README.md @@ -0,0 +1,7 @@ +## RSocket + +This module contains articles about RSocket in Spring Framework 6. + +### Relevant articles +- [RSocket Interface in Spring 6](https://www.baeldung.com/spring-rsocket) + diff --git a/spring-6-rsocket/pom.xml b/spring-6-rsocket/pom.xml new file mode 100644 index 0000000000..5d15a605ae --- /dev/null +++ b/spring-6-rsocket/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + com.bealdung + rsocket + 0.0.1-SNAPSHOT + rsocket + + + com.baeldung + parent-spring-6 + 0.0.1-SNAPSHOT + ../parent-spring-6 + + + + + + org.springframework.boot + spring-boot-starter-rsocket + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + 3.1.3 + 1.4.11 + 2.0.9 + + diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java new file mode 100644 index 0000000000..8fed6bee9b --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java @@ -0,0 +1,21 @@ +package com.bealdung.rsocket.requester; + +import org.springframework.messaging.rsocket.service.RSocketExchange; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public interface MessageClient { + + @RSocketExchange("MyDestination") + Mono sendMessage(Mono input); + + @RSocketExchange("Counter") + Flux Counter(); + + @RSocketExchange("Warning") + Mono Warning(Mono warning); + + @RSocketExchange("channel") + Flux channel(Flux input); +} diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java new file mode 100644 index 0000000000..a2cfcc69ca --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java @@ -0,0 +1,45 @@ +package com.bealdung.rsocket.responder; + +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.stereotype.Controller; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Controller +public class MessageController { + + @MessageMapping("MyDestination") + public Mono message(Mono input) { + return input.doOnNext(msg -> System.out.println("Request is:" + msg + ",Request!")) + .map(msg -> msg + ",Response!"); + } + + @MessageMapping("Counter") + public Flux Counter() { + return Flux.range(1, 10) + .map(i -> "Count is: " + i); + } + + @MessageMapping("Warning") + public Mono Warning(Mono error) { + error.doOnNext(e -> System.out.println("warning is :" + e)) + .subscribe(); + return Mono.empty(); + } + + @MessageMapping("channel") + public Flux channel(Flux input) { + return input.doOnNext(i -> { + System.out.println("Received message is : " + i); + }) + .map(m -> m.toUpperCase()) + .doOnNext(r -> { + System.out.println("RESPONSE IS :" + r); + }); + } + +} + + + diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java new file mode 100644 index 0000000000..9e763007fe --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java @@ -0,0 +1,73 @@ +package com.bealdung.rsocket.responder; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.messaging.rsocket.RSocketRequester; +import org.springframework.messaging.rsocket.service.RSocketServiceProxyFactory; + +import com.bealdung.rsocket.requester.MessageClient; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@SpringBootApplication +public class RSocketApplication { + public static void main(String[] args) { + SpringApplication.run(RSocketApplication.class, args); + } + + @Bean + public RSocketServiceProxyFactory getRSocketServiceProxyFactory(RSocketRequester.Builder requestBuilder) { + RSocketRequester requester = requestBuilder.tcp("localhost", 7000); + return RSocketServiceProxyFactory.builder(requester) + .build(); + } + + @Bean + public MessageClient getClient(RSocketServiceProxyFactory factory) { + return factory.createClient(MessageClient.class); + } + + @Bean + public ApplicationRunner runRequestResponseModel(MessageClient client) { + return args -> { + client.sendMessage(Mono.just("Request-Response test ")) + .doOnNext(message -> { + System.out.println("Response is :" + message); + }) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runStreamModel(MessageClient client) { + return args -> { + client.Counter() + .doOnNext(t -> { + System.out.println("message is :" + t); + }) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runFireAndForget(MessageClient client) { + return args -> { + client.Warning(Mono.just("Important Warning")) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runChannel(MessageClient client) { + return args -> { + client.channel(Flux.just("a", "b", "c", "d", "e")) + .doOnNext(i -> { + System.out.println(i); + }) + .subscribe(); + }; + } +} \ No newline at end of file diff --git a/spring-6-rsocket/src/main/resources/application.properties b/spring-6-rsocket/src/main/resources/application.properties new file mode 100644 index 0000000000..cab786cd30 --- /dev/null +++ b/spring-6-rsocket/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.rsocket.server.port=7000 \ No newline at end of file diff --git a/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java b/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java new file mode 100644 index 0000000000..4b85c4c6fc --- /dev/null +++ b/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java @@ -0,0 +1,35 @@ +package com.bealdung.rsocket; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.messaging.rsocket.RSocketRequester; +import org.springframework.messaging.rsocket.service.RSocketServiceProxyFactory; + +import com.bealdung.rsocket.requester.MessageClient; +import com.bealdung.rsocket.responder.RSocketApplication; + +import reactor.core.publisher.Mono; + +@SpringBootTest(classes = RSocketApplication.class) +public class RSocketRequestResponseIntegrationTest { + + MessageClient client; + + public RSocketRequestResponseIntegrationTest() { + RSocketRequester.Builder requesterBuilder = RSocketRequester.builder(); + RSocketRequester requester = requesterBuilder.tcp("localhost", 7000); + RSocketServiceProxyFactory factory = RSocketServiceProxyFactory.builder(requester) + .build(); + client = factory.createClient(MessageClient.class); + } + + @Test + public void whenSendingStream_thenReceiveTheSameStream() { + String message = "test message"; + assertEquals(message, client.sendMessage(Mono.just(message)) + .block()); + } + +} diff --git a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java deleted file mode 100644 index d289693a73..0000000000 --- a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplicationIntegrationTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung.activitiwithspring; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = ActivitiWithSpringApplication.class) -@AutoConfigureTestDatabase -public class ActivitiWithSpringApplicationIntegrationTest { - - @Test - public void contextLoads() { - } - -} diff --git a/spring-aop-2/README.md b/spring-aop-2/README.md index a9694ac236..0aa20d32f0 100644 --- a/spring-aop-2/README.md +++ b/spring-aop-2/README.md @@ -7,4 +7,5 @@ This module contains articles about Spring aspect oriented programming (AOP) - [Spring Performance Logging](https://www.baeldung.com/spring-performance-logging) - [When Does Java Throw UndeclaredThrowableException?](https://www.baeldung.com/java-undeclaredthrowableexception) - [Get Advised Method Info in Spring AOP](https://www.baeldung.com/spring-aop-get-advised-method-info) -- More articles: [[<-- prev]](/spring-aop) \ No newline at end of file +- [Invoke Spring @Cacheable from Another Method of Same Bean](https://www.baeldung.com/spring-invoke-cacheable-other-method-same-bean) +- More articles: [[<-- prev]](/spring-aop) diff --git a/spring-aop-2/pom.xml b/spring-aop-2/pom.xml index 056e248a3c..206e1d7d7c 100644 --- a/spring-aop-2/pom.xml +++ b/spring-aop-2/pom.xml @@ -51,4 +51,119 @@ + + + no-weaving + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + com.baeldung.selfinvocation.CompileTimeWeavingIntegrationTest + com.baeldung.selfinvocation.LoadTimeWeavingIntegrationTest + + + + + + + + + compile-time-weaving + + + + org.springframework + spring-aspects + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + com.baeldung.selfinvocation.CompileTimeWeavingIntegrationTest + + + + + org.codehaus.mojo + aspectj-maven-plugin + ${aspectj-plugin.version} + + ${java.version} + ${java.version} + ${java.version} + ignore + UTF-8 + + + org.springframework + spring-aspects + + + + + + + compile + + + + + + + + + + load-time-weaving + + + + org.springframework + spring-aspects + + + org.springframework + spring-tx + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + -javaagent:"${settings.localRepository}"/org/aspectj/aspectjweaver/${aspectjweaver.version}/aspectjweaver-${aspectjweaver.version}.jar + -javaagent:"${settings.localRepository}"/org/springframework/spring-instrument/${spring.version}/spring-instrument-${spring.version}.jar + + true + always + + com.baeldung.selfinvocation.LoadTimeWeavingIntegrationTest + + + + + + + + + + 1.14.0 + 5.3.27 + + \ No newline at end of file diff --git a/spring-aop-2/src/main/java/com/baeldung/Application.java b/spring-aop-2/src/main/java/com/baeldung/Application.java index c0490d50c6..cc64447264 100644 --- a/spring-aop-2/src/main/java/com/baeldung/Application.java +++ b/spring-aop-2/src/main/java/com/baeldung/Application.java @@ -2,8 +2,16 @@ package com.baeldung; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; @SpringBootApplication +@ComponentScan(basePackages = { "com.baeldung" }, excludeFilters = { + @ComponentScan.Filter(type = FilterType.ANNOTATION, + value = { SpringBootApplication.class}) +}) +@EnableCaching public class Application { public static void main(String[] args) { diff --git a/spring-aop-2/src/main/java/com/baeldung/selfinvocation/CompileTimeWeavingApplication.java b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/CompileTimeWeavingApplication.java new file mode 100644 index 0000000000..03995dd53b --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/CompileTimeWeavingApplication.java @@ -0,0 +1,20 @@ +package com.baeldung.selfinvocation; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.AdviceMode; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; + +@SpringBootApplication +@EnableCaching(mode = AdviceMode.ASPECTJ) +@ComponentScan(basePackages = { "com.baeldung" }, excludeFilters = { + @ComponentScan.Filter(type = FilterType.ANNOTATION, + value = { SpringBootApplication.class}) +}) +public class CompileTimeWeavingApplication { + public static void main(String[] args) { + SpringApplication.run(CompileTimeWeavingApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-aop-2/src/main/java/com/baeldung/selfinvocation/LoadTimeWeavingApplication.java b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/LoadTimeWeavingApplication.java new file mode 100644 index 0000000000..a3dcc161b3 --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/LoadTimeWeavingApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.selfinvocation; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.AdviceMode; +import org.springframework.context.annotation.EnableLoadTimeWeaving; + +@SpringBootApplication +@EnableCaching(mode = AdviceMode.ASPECTJ) +@EnableLoadTimeWeaving +public class LoadTimeWeavingApplication { + public static void main(String[] args) { + SpringApplication.run(LoadTimeWeavingApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-aop-2/src/main/java/com/baeldung/selfinvocation/MathService.java b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/MathService.java new file mode 100644 index 0000000000..993b73295f --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/selfinvocation/MathService.java @@ -0,0 +1,43 @@ +package com.baeldung.selfinvocation; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Service; + +import java.util.concurrent.atomic.AtomicInteger; + +@Service +@CacheConfig(cacheNames = "square") +@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) +public class MathService { + + @Autowired + private MathService self; + private final AtomicInteger counter = new AtomicInteger(); + + @CacheEvict(allEntries = true) + public AtomicInteger resetCounter() { + counter.set(0); + return counter; + } + + @Cacheable(key = "#n") + public double square(double n) { + counter.incrementAndGet(); + return n * n; + } + + public double sumOfSquareOf2() { + return this.square(2) + this.square(2); + } + + public double sumOfSquareOf3() { + return self.square(3) + self.square(3); + } + +} + diff --git a/spring-aop-2/src/main/resources/logback.xml b/spring-aop-2/src/main/resources/logback.xml index 4eaa556705..d63707a9da 100644 --- a/spring-aop-2/src/main/resources/logback.xml +++ b/spring-aop-2/src/main/resources/logback.xml @@ -17,6 +17,8 @@ + + diff --git a/spring-aop-2/src/test/java/com/baeldung/selfinvocation/CompileTimeWeavingIntegrationTest.java b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/CompileTimeWeavingIntegrationTest.java new file mode 100644 index 0000000000..d0522f67e5 --- /dev/null +++ b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/CompileTimeWeavingIntegrationTest.java @@ -0,0 +1,24 @@ +package com.baeldung.selfinvocation; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = CompileTimeWeavingApplication.class) +class CompileTimeWeavingIntegrationTest { + + @Resource + private MathService mathService; + + @Test + void givenCacheableMethod_whenInvokingByInternalCall_thenCacheIsTriggered() { + AtomicInteger counter = mathService.resetCounter(); + + assertThat(mathService.sumOfSquareOf2()).isEqualTo(8); + assertThat(counter.get()).isEqualTo(1); + } +} \ No newline at end of file diff --git a/spring-aop-2/src/test/java/com/baeldung/selfinvocation/LoadTimeWeavingIntegrationTest.java b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/LoadTimeWeavingIntegrationTest.java new file mode 100644 index 0000000000..93c57699d6 --- /dev/null +++ b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/LoadTimeWeavingIntegrationTest.java @@ -0,0 +1,25 @@ +package com.baeldung.selfinvocation; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = LoadTimeWeavingApplication.class) +class LoadTimeWeavingIntegrationTest { + + @Resource + private MathService mathService; + + @Test + void givenCacheableMethod_whenInvokingByInternalCall_thenCacheIsTriggered() { + AtomicInteger counter = mathService.resetCounter(); + + assertThat(mathService.sumOfSquareOf2()).isEqualTo(8); + assertThat(counter.get()).isEqualTo(1); + } + +} \ No newline at end of file diff --git a/spring-aop-2/src/test/java/com/baeldung/selfinvocation/MathServiceIntegrationTest.java b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/MathServiceIntegrationTest.java new file mode 100644 index 0000000000..24b829fa07 --- /dev/null +++ b/spring-aop-2/src/test/java/com/baeldung/selfinvocation/MathServiceIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.selfinvocation; + +import com.baeldung.Application; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = Application.class) +class MathServiceIntegrationTest { + + @Resource + private MathService mathService; + + @Test + void givenCacheableMethod_whenInvokedForSecondTime_thenCounterShouldNotIncrease() { + AtomicInteger counter = mathService.resetCounter(); + assertThat(mathService.square(2)).isEqualTo(4); + assertThat(counter.get()).isEqualTo(1); + + mathService.square(2); + assertThat(counter.get()).isEqualTo(1); + + mathService.square(3); + assertThat(counter.get()).isEqualTo(2); + } + + @Test + void givenCacheableMethod_whenInvokingByInternalCall_thenCacheIsNotTriggered() { + AtomicInteger counter = mathService.resetCounter(); + + assertThat(mathService.sumOfSquareOf2()).isEqualTo(8); + assertThat(counter.get()).isEqualTo(2); + } + + @Test + void givenCacheableMethod_whenInvokingByExternalCall_thenCacheIsTriggered() { + AtomicInteger counter = mathService.resetCounter(); + + assertThat(mathService.sumOfSquareOf3()).isEqualTo(18); + assertThat(counter.get()).isEqualTo(1); + } + +} \ No newline at end of file diff --git a/spring-boot-documentation/springwolf/pom.xml b/spring-boot-documentation/springwolf/pom.xml deleted file mode 100644 index 4bd9f24065..0000000000 --- a/spring-boot-documentation/springwolf/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - 4.0.0 - springwolf - 0.0.1-SNAPSHOT - springwolf - Documentation Spring Event Driven API Using AsyncAPI and Springwolf - - - com.baeldung.spring-boot-documentation - spring-boot-documentation - 1.0.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.kafka - spring-kafka - - - io.swagger.core.v3 - swagger-core-jakarta - ${swagger-core.version} - - - io.github.springwolf - springwolf-kafka - ${springwolf-kafka.version} - - - io.github.springwolf - springwolf-ui - ${springwolf-ui.version} - - - org.projectlombok - lombok - ${lombok.version} - - - org.springframework.kafka - spring-kafka-test - test - - - org.testcontainers - junit-jupiter - ${testcontainers-kafka.version} - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.boot.documentation.springwolf.SpringwolfApplication - - - - - - - 2.2.11 - 0.12.1 - 0.8.0 - 1.18.3 - - - diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index de14e26027..259a40dc38 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -44,7 +44,7 @@ spring-boot-graphql spring-boot-groovy - + spring-boot-jasypt spring-boot-jsp spring-boot-keycloak spring-boot-keycloak-2 @@ -91,12 +91,22 @@ spring-boot-3-native spring-boot-3-observation spring-boot-3-test-pitfalls + spring-boot-3-testcontainers + spring-boot-3-2 spring-boot-resilience4j spring-boot-properties spring-boot-properties-2 spring-boot-properties-3 spring-boot-properties-4 spring-boot-properties-migrator-demo + spring-boot-aws + spring-boot-keycloak-adapters + spring-boot-mvc-legacy + spring-boot-springdoc-2 + spring-boot-documentation + spring-boot-3-url-matching + spring-boot-graalvm-docker + spring-boot-validations @@ -118,8 +128,4 @@ - - 3.3.2 - - diff --git a/spring-boot-modules/spring-boot-3-2/README.md b/spring-boot-modules/spring-boot-3-2/README.md new file mode 100644 index 0000000000..c176de2310 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Spring Boot 3.1’s ConnectionDetails Abstraction](https://www.baeldung.com/spring-boot-3-1-connectiondetails-abstraction) diff --git a/spring-boot-modules/spring-boot-3-2/pom.xml b/spring-boot-modules/spring-boot-3-2/pom.xml new file mode 100644 index 0000000000..276659c609 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/pom.xml @@ -0,0 +1,290 @@ + + + 4.0.0 + spring-boot-3-2 + 0.0.1-SNAPSHOT + spring-boot-3-2 + Demo project for Spring Boot + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + repository.spring.release + Spring GA Repository + https://repo.spring.io/milestone + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-hateoas + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-webflux + + + org.mock-server + mockserver-netty + ${mockserver.version} + + + + org.mock-server + mockserver-client-java + ${mockserver.version} + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + org.projectlombok + lombok + true + + + org.mapstruct + mapstruct + ${mapstruct.version} + true + + + org.springframework.boot + spring-boot-docker-compose + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + 3.2.0-M2 + + + org.junit.jupiter + junit-jupiter + 5.10.0 + + + org.junit.jupiter + junit-jupiter-api + 5.10.0 + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-amqp + + + org.springframework.amqp + spring-rabbit-test + test + + + org.springframework.data + spring-data-redis + + + redis.clients + jedis + jar + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.postgresql + r2dbc-postgresql + runtime + + + org.springframework.boot + spring-boot-starter-data-r2dbc + + + io.projectreactor + reactor-test + test + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + org.springframework.boot + spring-boot-starter-data-cassandra + + + org.springframework.boot + spring-boot-starter-data-neo4j + + + org.springframework.kafka + spring-kafka + + + org.springframework.kafka + spring-kafka-test + test + + + org.springframework.boot + spring-boot-starter-data-couchbase + + + io.micrometer + micrometer-tracing-bridge-brave + + + io.zipkin.reporter2 + zipkin-reporter-brave + + + io.zipkin.reporter2 + zipkin-sender-urlconnection + + + + + + + org.springframework.boot + spring-boot-dependencies + 3.2.0-M2 + import + pom + + + + + + + + docker-compose + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.dockercompose.DockerComposeApplication + + + + + + + connection-details + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.connectiondetails.ConnectionDetailsApplication + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + org.projectlombok + lombok-mapstruct-binding + ${lombok-mapstruct-binding.version} + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + 1.5.2.Final + 2.0.0 + 3.0.0-M7 + 5.14.0 + 0.2.0 + + + diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/ConnectionDetailsApplication.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/ConnectionDetailsApplication.java new file mode 100644 index 0000000000..d32ae8c4fb --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/ConnectionDetailsApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.connectiondetails; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +//@ComponentScan(basePackages = "com.baeldung.connectiondetails") +public class ConnectionDetailsApplication { + + public static void main(String[] args) { + SpringApplication.run(ConnectionDetailsApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/adapter/VaultAdapter.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/adapter/VaultAdapter.java new file mode 100644 index 0000000000..e8319c7735 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/adapter/VaultAdapter.java @@ -0,0 +1,124 @@ +package com.baeldung.connectiondetails.adapter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VaultAdapter { + private static final Logger logger = LoggerFactory.getLogger(VaultAdapter.class); + public static String getSecret(String secretKey) { + logger.info("call vault to get the secret of key: " + secretKey); + + //Postgres keys + if (secretKey.equalsIgnoreCase("postgres_secret_key")) { + return "postgres"; + } + if (secretKey.equalsIgnoreCase("postgres_user_key")) { + return "postgres"; + } + if (secretKey.equalsIgnoreCase("postgres_jdbc_url")) { + return "jdbc:postgresql://localhost:15432/postgresdb"; + } + //RabbitMQ Server Keys + if (secretKey.equalsIgnoreCase("rabbitmq_username")) { + return "rabbitmquser"; + } + if (secretKey.equalsIgnoreCase("rabbitmq_password")) { + return "rabbitmq"; + } + if (secretKey.equalsIgnoreCase("rabbitmq_port")) { + return "5672"; + } + if (secretKey.equalsIgnoreCase("rabbitmq_host")) { + return "localhost"; + } + //Redis Server Keys + if (secretKey.equalsIgnoreCase("redis_username")) { + return null; + } + if (secretKey.equalsIgnoreCase("redis_password")) { + return "redis"; + } + if (secretKey.equalsIgnoreCase("redis_port")) { + return "6379"; + } + if (secretKey.equalsIgnoreCase("redis_host")) { + return "localhost"; + } + //Mongo DB Keys + if (secretKey.equalsIgnoreCase("mongo_connection_string")) { + return "mongodb://localhost:27017/demodb"; + } + + //r2dbc Keys + if (secretKey.equalsIgnoreCase("r2dbc_postgres_user")) { + return "postgres"; + } + if (secretKey.equalsIgnoreCase("r2dbc_postgres_secret")) { + return "postgres"; + } + if (secretKey.equalsIgnoreCase("r2dbc_postgres_host")) { + return "localhost"; + } + if (secretKey.equalsIgnoreCase("r2dbc_postgres_port")) { + return "15432"; + } + if (secretKey.equalsIgnoreCase("r2dbc_postgres_database")) { + return "postgresdb"; + } + //Elastic Search Keys + if (secretKey.equalsIgnoreCase("elastic_user")) { + return "elastic"; + } + if (secretKey.equalsIgnoreCase("elastic_secret")) { + return "secret"; + } + if (secretKey.equalsIgnoreCase("elastic_host")) { + return "localhost"; + } + if (secretKey.equalsIgnoreCase("elastic_port1")) { + return "19200"; + } + if (secretKey.equalsIgnoreCase("elastic_port2")) { + return "19300"; + } + //Cassandra keys + if (secretKey.equalsIgnoreCase("cassandra_user")) { + return "cassandra"; + } + if (secretKey.equalsIgnoreCase("cassandra_secret")) { + return "secret"; + } + if (secretKey.equalsIgnoreCase("cassandra_host")) { + return "localhost"; + } + if (secretKey.equalsIgnoreCase("cassandra_port")) { + return "19042"; + } + //Neo4j Keys + if (secretKey.equalsIgnoreCase("neo4j_secret")) { + return "neo4j123"; + } + if (secretKey.equalsIgnoreCase("neo4j_uri")) { + return "bolt://localhost:17687"; + } + //Kafka Keys + if (secretKey.equalsIgnoreCase("kafka_servers")) { + return "localhost:19092"; + } + //Couchbase Keys + if(secretKey.equalsIgnoreCase("couch_user")) { + return "Administrator"; + } + if(secretKey.equalsIgnoreCase("couch_secret")) { + return "password"; + } + if(secretKey.equalsIgnoreCase("couch_connection_string")) { + return "couchbase://127.0.0.1:8092"; + } + //Zipkin Keys + if(secretKey.equalsIgnoreCase("zipkin_span_endpoint")) { + return "http://localhost:9411/api/v2/spans"; + } + return "secretVal"; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetails.java new file mode 100644 index 0000000000..6a246cd9fc --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetails.java @@ -0,0 +1,32 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails; + +import java.util.List; + +public class CustomCassandraConnectionDetails implements CassandraConnectionDetails { + @Override + public List getContactPoints() { + Node node = new Node( + VaultAdapter.getSecret("cassandra_host"), + Integer.parseInt(VaultAdapter.getSecret("cassandra_port")) + ); + return List.of(node); + } + + @Override + public String getUsername() { + return VaultAdapter.getSecret("cassandra_user"); + } + + @Override + public String getPassword() { + return VaultAdapter.getSecret("cassandra_secret"); + } + + @Override + public String getLocalDatacenter() { + return "datacenter-1"; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..02ed8c0051 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCassandraConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("cassandra") +public class CustomCassandraConnectionDetailsConfiguration { + @Bean + @Primary + public CassandraConnectionDetails getCustomCassandraConnectionDetails() { + return new CustomCassandraConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetails.java new file mode 100644 index 0000000000..4fa0605cac --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetails.java @@ -0,0 +1,21 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseConnectionDetails; + +public class CustomCouchBaseConnectionDetails implements CouchbaseConnectionDetails { + @Override + public String getConnectionString() { + return VaultAdapter.getSecret("couch_connection_string"); + } + + @Override + public String getUsername() { + return VaultAdapter.getSecret("couch_user"); + } + + @Override + public String getPassword() { + return VaultAdapter.getSecret("couch_secret"); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..96cc34f92e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomCouchBaseConnectionDetailsConfiguration.java @@ -0,0 +1,16 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.couchbase.CouchbaseConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("couch") + +public class CustomCouchBaseConnectionDetailsConfiguration { + @Bean + public CouchbaseConnectionDetails getCouchBaseConnectionDetails() { + return new CustomCouchBaseConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetails.java new file mode 100644 index 0000000000..0b45878bc9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetails.java @@ -0,0 +1,29 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails; + +import java.util.List; + +public class CustomElasticsearchConnectionDetails implements ElasticsearchConnectionDetails { + @Override + public List getNodes() { + Node node1 = new Node( + VaultAdapter.getSecret("elastic_host"), + Integer.parseInt(VaultAdapter.getSecret("elastic_port1")), + Node.Protocol.HTTP + ); + return List.of(node1); + } + + @Override + public String getUsername() { + return VaultAdapter.getSecret("elastic_user"); + } + + @Override + public String getPassword() { + return VaultAdapter.getSecret("elastic_secret"); + } + +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..a9b3da44fa --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomElasticsearchConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("elastic") +public class CustomElasticsearchConnectionDetailsConfiguration { + @Bean + @Primary + public ElasticsearchConnectionDetails getCustomElasticConnectionDetails() { + return new CustomElasticsearchConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetails.java new file mode 100644 index 0000000000..6791ee6408 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetails.java @@ -0,0 +1,13 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails; + +import java.util.List; + +public class CustomKafkaConnectionDetails implements KafkaConnectionDetails { + @Override + public List getBootstrapServers() { + return List.of(VaultAdapter.getSecret("kafka_servers")); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..068281741a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomKafkaConnectionDetailsConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("kafka") +public class CustomKafkaConnectionDetailsConfiguration { + @Bean + public KafkaConnectionDetails getKafkaConnectionDetails() { + return new CustomKafkaConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetails.java new file mode 100644 index 0000000000..c0412fbb21 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetails.java @@ -0,0 +1,24 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.neo4j.driver.AuthToken; +import org.neo4j.driver.AuthTokens; +import org.springframework.boot.autoconfigure.neo4j.Neo4jConnectionDetails; + +import java.net.URI; +import java.net.URISyntaxException; + +public class CustomNeo4jConnectionDetails implements Neo4jConnectionDetails { + @Override + public URI getUri() { + try { + return new URI(VaultAdapter.getSecret("neo4j_uri")); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + @Override + public AuthToken getAuthToken() { + return AuthTokens.basic("neo4j", VaultAdapter.getSecret("neo4j_secret")); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..aec8908c7d --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomNeo4jConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.neo4j.Neo4jConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("neo4j") +public class CustomNeo4jConnectionDetailsConfiguration { + @Bean + @Primary + public Neo4jConnectionDetails getNeo4jConnectionDetails() { + return new CustomNeo4jConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetails.java new file mode 100644 index 0000000000..c29408992a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetails.java @@ -0,0 +1,11 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConnectionDetails; + +public class CustomZipkinConnectionDetails implements ZipkinConnectionDetails { + @Override + public String getSpanEndpoint() { + return VaultAdapter.getSecret("zipkin_span_endpoint"); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..2f451a3850 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/CustomZipkinConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("zipkin") +public class CustomZipkinConnectionDetailsConfiguration { + @Bean + @Primary + public ZipkinConnectionDetails getZipkinConnectionDetails() { + return new CustomZipkinConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/JdbcConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/JdbcConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..3387356366 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/JdbcConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("jdbc") +public class JdbcConnectionDetailsConfiguration { + @Bean + @Primary + public JdbcConnectionDetails getPostgresConnection() { + return new PostgresConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetails.java new file mode 100644 index 0000000000..df689d81b6 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetails.java @@ -0,0 +1,14 @@ +package com.baeldung.connectiondetails.configuration; + + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import com.mongodb.ConnectionString; +import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails; + +public class MongoDBConnectionDetails implements MongoConnectionDetails { + @Override + public ConnectionString getConnectionString() { + return new ConnectionString(VaultAdapter.getSecret("mongo_connection_string")); + } +} + diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..d455991d08 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/MongoDBConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("mongo") +public class MongoDBConnectionDetailsConfiguration { + @Bean + @Primary + public MongoConnectionDetails getMongoConnectionDetails() { + return new MongoDBConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/PostgresConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/PostgresConnectionDetails.java new file mode 100644 index 0000000000..c9b213a8d3 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/PostgresConnectionDetails.java @@ -0,0 +1,21 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; + +public class PostgresConnectionDetails implements JdbcConnectionDetails { + @Override + public String getUsername() { + return VaultAdapter.getSecret("postgres_user_key"); + } + + @Override + public String getPassword() { + return VaultAdapter.getSecret("postgres_secret_key"); + } + + @Override + public String getJdbcUrl() { + return VaultAdapter.getSecret("postgres_jdbc_url"); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetails.java new file mode 100644 index 0000000000..613ec83124 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetails.java @@ -0,0 +1,22 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails; + +public class R2dbcPostgresConnectionDetails implements R2dbcConnectionDetails { + @Override + public ConnectionFactoryOptions getConnectionFactoryOptions() { + + ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() + .option(ConnectionFactoryOptions.DRIVER, "postgresql") + .option(ConnectionFactoryOptions.HOST, VaultAdapter.getSecret("r2dbc_postgres_host")) + .option(ConnectionFactoryOptions.PORT, Integer.valueOf(VaultAdapter.getSecret("r2dbc_postgres_port"))) + .option(ConnectionFactoryOptions.USER, VaultAdapter.getSecret("r2dbc_postgres_user")) + .option(ConnectionFactoryOptions.PASSWORD, VaultAdapter.getSecret("r2dbc_postgres_secret")) + .option(ConnectionFactoryOptions.DATABASE, VaultAdapter.getSecret("r2dbc_postgres_database")) + .build(); + + return options; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..144355dce4 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/R2dbcPostgresConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("r2dbc") +public class R2dbcPostgresConnectionDetailsConfiguration { + @Bean + @Primary + public R2dbcConnectionDetails getR2dbcPostgresConnectionDetails() { + return new R2dbcPostgresConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetails.java new file mode 100644 index 0000000000..9dc4bdf33b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetails.java @@ -0,0 +1,34 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails; + +import java.util.List; + +public class RabbitMQConnectionDetails implements RabbitConnectionDetails { + @Override + public String getUsername() { + return VaultAdapter.getSecret("rabbitmq_username"); + } + + @Override + public String getPassword() { + return VaultAdapter.getSecret("rabbitmq_password"); + } + + @Override + public String getVirtualHost() { + return "/"; + } + + @Override + public List
getAddresses() { + return List.of(this.getFirstAddress()); + } + + @Override + public Address getFirstAddress() { + return new Address(VaultAdapter.getSecret("rabbitmq_host"), + Integer.parseInt(VaultAdapter.getSecret("rabbitmq_port"))); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..237bec3fc4 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RabbitMQConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("rabbitmq") +public class RabbitMQConnectionDetailsConfiguration { + @Primary + @Bean + public RabbitConnectionDetails getRabbitmqConnection() { + return new RabbitMQConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisCacheConnectionDetails.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisCacheConnectionDetails.java new file mode 100644 index 0000000000..9485f22240 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisCacheConnectionDetails.java @@ -0,0 +1,26 @@ +package com.baeldung.connectiondetails.configuration; + +import com.baeldung.connectiondetails.adapter.VaultAdapter; +import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails; + +public class RedisCacheConnectionDetails implements RedisConnectionDetails { + @Override + public String getPassword() { + return VaultAdapter.getSecret("redis_password"); + } + + @Override + public Standalone getStandalone() { + return new Standalone() { + @Override + public String getHost() { + return VaultAdapter.getSecret("redis_host"); + } + + @Override + public int getPort() { + return Integer.parseInt(VaultAdapter.getSecret("redis_port")); + } + }; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisConnectionDetailsConfiguration.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisConnectionDetailsConfiguration.java new file mode 100644 index 0000000000..31816ff0b4 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/configuration/RedisConnectionDetailsConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.connectiondetails.configuration; + +import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Configuration(proxyBeanMethods = false) +@Profile("redis") +public class RedisConnectionDetailsConfiguration { + @Bean + @Primary + public RedisConnectionDetails getRedisCacheConnection() { + return new RedisCacheConnectionDetails(); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/controller/ZipkinDemoController.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/controller/ZipkinDemoController.java new file mode 100644 index 0000000000..bba5607ccd --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/controller/ZipkinDemoController.java @@ -0,0 +1,19 @@ +package com.baeldung.connectiondetails.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ZipkinDemoController { + + Logger logger = LoggerFactory.getLogger(ZipkinDemoController.class); + + @GetMapping("/zipkin/test") + public @ResponseBody String testMethod() { + logger.info("This is a test"); + return "This is a test"; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/elastic/Person.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/elastic/Person.java new file mode 100644 index 0000000000..851dbb7c90 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/elastic/Person.java @@ -0,0 +1,27 @@ +package com.baeldung.connectiondetails.entity.elastic; + +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; + +@Document(indexName = "person") +public class Person { + String name; + @Id + String ssn; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSsn() { + return ssn; + } + + public void setSsn(String ssn) { + this.ssn = ssn; + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/neo4j/Person.java b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/neo4j/Person.java new file mode 100644 index 0000000000..63e88d0a41 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/java/com/baeldung/connectiondetails/entity/neo4j/Person.java @@ -0,0 +1,27 @@ +package com.baeldung.connectiondetails.entity.neo4j; + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +@Node +public class Person { + @Id + String name; + String zipcode; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getZipcode() { + return zipcode; + } + + public void setZipcode(String zipcode) { + this.zipcode = zipcode; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-cassandra.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-cassandra.properties new file mode 100644 index 0000000000..4098206d21 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-cassandra.properties @@ -0,0 +1,11 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-cassandra.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=cassandra +spring.cassandra.local-datacenter=dc1 +#spring.cassandra.keyspace-name=spring_cassandra +#spring.cassandra.schema-action=CREATE_IF_NOT_EXISTS +spring.data.cassandra.request.timeout=20000 # Set your desired timeout in milliseconds +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-couch.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-couch.properties new file mode 100644 index 0000000000..ccce04c0b5 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-couch.properties @@ -0,0 +1,8 @@ +spring.profiles.active=couch +spring.docker.compose.enabled=false +spring.docker.compose.file=./connectiondetails/docker/docker-compose-couch.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.couchbase.bucket.name=travel-sample +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-elastic.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-elastic.properties new file mode 100644 index 0000000000..2149730517 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-elastic.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-elastic.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=elastic +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-jdbc.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-jdbc.properties new file mode 100644 index 0000000000..b5a8a73bcf --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-jdbc.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-jdbc.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=jdbc +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-kafka.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-kafka.properties new file mode 100644 index 0000000000..9f756cfaf1 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-kafka.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-kafka.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=kafka +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-mongo.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-mongo.properties new file mode 100644 index 0000000000..31d828c5c9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-mongo.properties @@ -0,0 +1,8 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-mongo.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=mongo +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration +spring.data.mongodb.database=demodb \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-neo4j.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-neo4j.properties new file mode 100644 index 0000000000..e2dc9e20bf --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-neo4j.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-neo4j.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=neo4j +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-r2dbc.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-r2dbc.properties new file mode 100644 index 0000000000..3fcaa4f746 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-r2dbc.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-jdbc.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=r2dbc +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-rabbitmq.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-rabbitmq.properties new file mode 100644 index 0000000000..fa6b3f6608 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-rabbitmq.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-rabbitmq.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=rabbitmq +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-redis.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-redis.properties new file mode 100644 index 0000000000..c12f20c773 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-redis.properties @@ -0,0 +1,7 @@ +spring.docker.compose.enabled=true +spring.docker.compose.file=./connectiondetails/docker/docker-compose-redis.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.profiles.active=redis +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration, org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-zipkin.properties b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-zipkin.properties new file mode 100644 index 0000000000..544a3c07b6 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/application-zipkin.properties @@ -0,0 +1,9 @@ +spring.profiles.active=zipkin +spring.docker.compose.enabled=false +spring.docker.compose.file=./connectiondetails/docker/docker-compose-zipkin.yml +spring.docker.compose.skip.in-tests=false +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.mustache.check-template-location=false +spring.application.name=baeldung +management.tracing.sampling.probability=1.0 +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration, org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration, org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration, org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-cassandra.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-cassandra.yml new file mode 100644 index 0000000000..c593cbc73b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-cassandra.yml @@ -0,0 +1,9 @@ +version: '3.8' +services: + cassandra: + image: 'cassandra:latest' + environment: + - 'CASSANDRA_DC=datacenter-1' + - 'CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch' + ports: + - '19042:9042' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-couch.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-couch.yml new file mode 100644 index 0000000000..edcf8e2e08 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-couch.yml @@ -0,0 +1,12 @@ +version: '3.8' +services: + couchbase: + image: couchbase/server-sandbox:7.0.0 + ports: + - "8091-8095:8091-8095" + - "9102:9102" + - "11210:11210" + expose: + - "8091" + - "8094" + container_name: couchbase-sandbox-7.0.0-mm \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-elastic.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-elastic.yml new file mode 100644 index 0000000000..a6e51ee1a0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-elastic.yml @@ -0,0 +1,12 @@ +version: '3.8' +services: + elasticsearch: + image: 'docker.elastic.co/elasticsearch/elasticsearch:7.17.10' + environment: + - 'ELASTIC_USERNAME=elastic' + - 'ELASTIC_PASSWORD=secret' + - 'discovery.type=single-node' + - 'xpack.security.enabled=false' + ports: + - '19200:9200' +# - '19300:9300' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-jdbc.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-jdbc.yml new file mode 100644 index 0000000000..65a8f135e8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-jdbc.yml @@ -0,0 +1,10 @@ +version: '3.8' +services: + database: + image: 'postgres:13.1-alpine' + ports: + - '15432:5432' + environment: + - 'POSTGRES_USER=postgres' + - 'POSTGRES_DB=postgresdb' + - 'POSTGRES_PASSWORD=postgres' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-kafka.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-kafka.yml new file mode 100644 index 0000000000..5d13e6d6cc --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-kafka.yml @@ -0,0 +1,38 @@ +version: '3' +services: + zookeeper: + image: confluentinc/cp-zookeeper:latest + container_name: zookeeper + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 + ports: + - "2181:2181" + + schema-registry: + image: confluentinc/cp-schema-registry:latest + hostname: schema-registry + depends_on: + - kafka-broker-1 + ports: + - "8081:8081" + environment: + SCHEMA_REGISTRY_HOST_NAME: schema-registry + SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: 'zookeeper:2181' + SCHEMA_REGISTRY_LISTENERS: http://schema-registry:8081 + SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: PLAINTEXT://kafka-broker-1:9092,PLAINTEXT_INTERNAL://localhost:19092 + SCHEMA_REGISTRY_DEBUG: 'true' + + kafka-broker-1: + image: confluentinc/cp-kafka:latest + hostname: kafka-broker-1 + ports: + - "19092:19092" + depends_on: + - zookeeper + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXT + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-broker-1:9092,PLAINTEXT_INTERNAL://localhost:19092 + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-mongo.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-mongo.yml new file mode 100644 index 0000000000..f12f5c3aa7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-mongo.yml @@ -0,0 +1,10 @@ +version: '3.8' +services: + mongodb: + image: 'mongo:latest' + environment: + - 'MONGO_INITDB_DATABASE=demodb' +# - 'MONGO_INITDB_ROOT_PASSWORD=Mongo123' +# - 'MONGO_INITDB_ROOT_USERNAME=mongouser' + ports: + - '27017:27017' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-neo4j.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-neo4j.yml new file mode 100644 index 0000000000..611951e755 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-neo4j.yml @@ -0,0 +1,8 @@ +version: '3.8' +services: + neo4j: + image: 'neo4j:latest' + ports: + - '17687:7687' + environment: + NEO4J_AUTH: neo4j/neo4j123 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-rabbitmq.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-rabbitmq.yml new file mode 100644 index 0000000000..8abf19bd19 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-rabbitmq.yml @@ -0,0 +1,9 @@ +version: '3.8' +services: + rabbitmq: + image: 'rabbitmq:latest' + environment: + - 'RABBITMQ_DEFAULT_PASS=rabbitmq' + - 'RABBITMQ_DEFAULT_USER=rabbitmquser' + ports: + - '5672:5672' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-redis.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-redis.yml new file mode 100644 index 0000000000..c218cef998 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-redis.yml @@ -0,0 +1,8 @@ +version: '3.8' +services: + redis: + image: 'redis:latest' + ports: + - '6379:6379' + environment: + - 'REDIS_REQUIREPASS=redis' \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-zipkin.yml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-zipkin.yml new file mode 100644 index 0000000000..363dd24a2b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/docker/docker-compose-zipkin.yml @@ -0,0 +1,10 @@ +version: '3' +services: + zipkin: + image: 'openzipkin/zipkin:latest' + ports: + - "9411:9411" +# environment: +# - ZIPKIN_AUTH_USERNAME=your-username +# - ZIPKIN_AUTH_PASSWORD=your-password + # Add other necessary configurations here diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/cassandra-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/cassandra-connection-details-class-diag.puml new file mode 100644 index 0000000000..b16ef4d56e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/cassandra-connection-details-class-diag.puml @@ -0,0 +1,27 @@ +@startuml +'https://plantuml.com/class-diagram + +interface CassandraConnectionDetails { + +getUsername():String + +getPassword():String + +getContactPoints():List + +getLocalDatacenter():String +} +class CustomCouchBaseConnectionDetails { + +getUsername():String + +getPassword():String + +getContactPoints():List + +getLocalDatacenter():String +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomCassandraConnectionDetailsConfiguration { + +getCustomCassandraConnectionDetails():CassandraConnectionDetails +} +CustomCouchBaseConnectionDetails -left-> VaultAdapter:uses +CustomCouchBaseConnectionDetails -right-|> CassandraConnectionDetails : implements +CustomCassandraConnectionDetailsConfiguration -up-> CustomCassandraConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/connection-details-sequence-design.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/connection-details-sequence-design.puml new file mode 100644 index 0000000000..a2a917eea0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/connection-details-sequence-design.puml @@ -0,0 +1,16 @@ +@startuml +'https://plantuml.com/sequence-diagram +skinparam sequenceMessageAlign direction +skinparam handwritten true +skinparam sequence { +ParticipantBackgroundColor beige +ParticipantPadding 50 +} +autonumber + +"Spring Boot" -[#63b175]> "Hashicorp Vault": Secret Request +"Hashicorp Vault" -[#63b175]-> "Spring Boot": Secret Response +"Spring Boot" -[#63b175]> "Remote Service": Connection Request + +"Remote Service" -[#63b175]-> "Spring Boot": Connection Response +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/couch_connection_details_class_diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/couch_connection_details_class_diag.puml new file mode 100644 index 0000000000..fd8dbd094b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/couch_connection_details_class_diag.puml @@ -0,0 +1,25 @@ +@startuml +'https://plantuml.com/class-diagram + +interface CouchbaseConnectionDetails { + +getUsername():String + +getPassword():String + +getConnectionString():String +} +class CustomCouchBaseConnectionDetails { + +getUsername():String + +getPassword():String + +getConnectionString():String +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomCouchBaseConnectionDetailsConfiguration { + +getCouchBaseConnectionDetails():CouchbaseConnectionDetails +} +CustomCouchBaseConnectionDetails -left-> VaultAdapter:uses +CustomCouchBaseConnectionDetails -right-|> CouchbaseConnectionDetails : implements +CustomCouchBaseConnectionDetailsConfiguration -up-> CustomCouchBaseConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/elasticsearch-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/elasticsearch-connection-details-class-diag.puml new file mode 100644 index 0000000000..48db0bcc4f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/elasticsearch-connection-details-class-diag.puml @@ -0,0 +1,25 @@ +@startuml +'https://plantuml.com/class-diagram + +interface ElasticsearchConnectionDetails { + +getUsername():String + +getPassword():String + +getNodes():List +} +class CustomElasticsearchConnectionDetails { + +getUsername():String + +getPassword():String + +getNodes():List +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomElasticsearchConnectionDetailsConfiguration { + +getCustomElasticConnectionDetails():ElasticsearchConnectionDetails +} +CustomElasticsearchConnectionDetails -left-> VaultAdapter:uses +CustomElasticsearchConnectionDetails -right-|> ElasticsearchConnectionDetails : implements +CustomElasticsearchConnectionDetailsConfiguration -up-> CustomElasticsearchConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/jdbcconnection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/jdbcconnection-details-class-diag.puml new file mode 100644 index 0000000000..88de5d607f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/jdbcconnection-details-class-diag.puml @@ -0,0 +1,25 @@ +@startuml +'https://plantuml.com/class-diagram + +interface JdbcConnectionDetails { + +getUsername():String + +getPassword():String + +getJdbcUrl():String +} +class PostgresConnectionDetails { + +getUsername():String + +getPassword():String + +getJdbcUrl():String +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class JdbcConnectonDetailsConfiguration { + +getPostgresConnection():JdbcConnectionDetails +} +PostgresConnectionDetails -left-> VaultAdapter:uses +PostgresConnectionDetails -right-|> JdbcConnectionDetails : implements +JdbcConnectonDetailsConfiguration -up-> PostgresConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/kafka-connectiondetails-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/kafka-connectiondetails-class-diag.puml new file mode 100644 index 0000000000..57df331bb2 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/kafka-connectiondetails-class-diag.puml @@ -0,0 +1,21 @@ +@startuml +'https://plantuml.com/class-diagram + +interface KafkaConnectionDetails { + +getBootstrapServers():List +} +class CustomKafkaConnectionDetails { ++getBootstrapServers():List +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomKafkaConnectionDetailsConfiguration { + +getKafkaConnectionDetails():KafkaConnectionDetails +} +CustomKafkaConnectionDetails -left-> VaultAdapter:uses +CustomKafkaConnectionDetails -right-|> KafkaConnectionDetails:implements +CustomKafkaConnectionDetailsConfiguration -up-> CustomKafkaConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/mongodb-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/mongodb-connection-details-class-diag.puml new file mode 100644 index 0000000000..974c6de601 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/mongodb-connection-details-class-diag.puml @@ -0,0 +1,19 @@ +@startuml +'https://plantuml.com/class-diagram + +interface MongoConnectionDetails { + getConnectionString():ConnectionString +} +class MongoDBConnectionDetails { + getConnectionString():ConnectionString +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class MongoDBConnectionDetailsConfiguration { + +getMongoConnectionDetails() : MongoConnectionDetails +} +MongoDBConnectionDetails -left-> VaultAdapter:uses +MongoDBConnectionDetails -right-|> MongoConnectionDetails : implements +MongoDBConnectionDetailsConfiguration -up-> MongoDBConnectionDetails:uses +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/neo4j-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/neo4j-connection-details-class-diag.puml new file mode 100644 index 0000000000..5a3e8812f6 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/neo4j-connection-details-class-diag.puml @@ -0,0 +1,23 @@ +@startuml +'https://plantuml.com/class-diagram + +interface Neo4jConnectionDetails { + +getUri():URI + +getAuthToken():AuthToken +} +class CustomNeo4jConnectionDetails { + +getUri():URI + +getAuthToken():AuthToken +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomNeo4jConnectionDetailsConfiguration { + +getNeo4jConnectionDetails():Neo4jConnectionDetails +} +CustomNeo4jConnectionDetails -left-> VaultAdapter:uses +CustomNeo4jConnectionDetails -right-|> Neo4jConnectionDetails:implements +CustomNeo4jConnectionDetailsConfiguration -up-> CustomNeo4jConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/r2dbcconnection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/r2dbcconnection-details-class-diag.puml new file mode 100644 index 0000000000..ec69587ab9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/r2dbcconnection-details-class-diag.puml @@ -0,0 +1,21 @@ +@startuml +'https://plantuml.com/class-diagram + +interface R2dbcConnectionDetails { + +getConnectionFactoryOptions():ConnectionFactoryOptions +} +class R2dbcPostgresConnectionDetails { + +getConnectionFactoryOptions():ConnectionFactoryOptions +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class R2dbcPostgresConnectionDetailsConfiguration { + +getR2dbcPostgresConnectionDetails():R2dbcConnectionDetails +} +R2dbcPostgresConnectionDetails -right-> VaultAdapter:uses +R2dbcPostgresConnectionDetails -up-|> R2dbcConnectionDetails:implements +R2dbcPostgresConnectionDetailsConfiguration -up-> R2dbcPostgresConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/rabbitmq-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/rabbitmq-connection-details-class-diag.puml new file mode 100644 index 0000000000..0541e12915 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/rabbitmq-connection-details-class-diag.puml @@ -0,0 +1,27 @@ +@startuml +'https://plantuml.com/class-diagram + +interface RabbitConnectionDetails { + +getUsername():String + +getPassword():String + +getFirstAddress():Address + +getAddresses():List
+} +class RabbitMQConnectionDetails { + +getUsername():String + +getPassword():String + +getFirstAddress():Address + +getAddresses():List
+} +class VaultAdapter { + +getSecret(String secretKey):String +} +class RabbitMQConnectionDetailsConfiguration { + +getRabbitmqConnection() : RabbitConnectionDetails +} +RabbitMQConnectionDetails -left-> VaultAdapter:uses +RabbitMQConnectionDetails -right-|> RabbitConnectionDetails : implements +RabbitMQConnectionDetailsConfiguration -up-> RabbitMQConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/redis-connection-details-class-diagram.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/redis-connection-details-class-diagram.puml new file mode 100644 index 0000000000..a18c83a8be --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/redis-connection-details-class-diagram.puml @@ -0,0 +1,23 @@ +@startuml +'https://plantuml.com/class-diagram + +interface RedisConnectionDetails { + +getPassword():String + +getStandalone():Standalone +} +class RedisCacheConnectionDetails { + +getPassword():String + +getStandalone():Standalone +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class RedisConnectonDetailsConfiguration { + +getRedisCacheConnection():RedisConnectionDetails +} +RedisCacheConnectionDetails -left-> VaultAdapter:uses +RedisCacheConnectionDetails -right-|> RedisConnectionDetails : implements +RedisConnectonDetailsConfiguration -up-> RedisCacheConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/zipkin-connection-details-class-diag.puml b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/zipkin-connection-details-class-diag.puml new file mode 100644 index 0000000000..0f185f9c12 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/main/resources/connectiondetails/plantuml/zipkin-connection-details-class-diag.puml @@ -0,0 +1,21 @@ +@startuml +'https://plantuml.com/class-diagram + +interface ZipkinConnectionDetails { + +getSpanEndpoint():String +} +class CustomZipkinConnectionDetails { + +getSpanEndpoint():String +} +class VaultAdapter { + +getSecret(String secretKey):String +} +class CustomZipkinConnectionDetailsConfiguration { + +getZipkinConnectionDetails():ZipkinConnectionDetails +} +CustomZipkinConnectionDetails -left-> VaultAdapter:uses +CustomZipkinConnectionDetails -right-|> ZipkinConnectionDetails:implements +CustomZipkinConnectionDetailsConfiguration -up-> CustomZipkinConnectionDetails:uses + + +@enduml \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/conditionalonthreading/ConditionalOnThreadingUnitTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/conditionalonthreading/ConditionalOnThreadingUnitTest.java new file mode 100644 index 0000000000..ed65769954 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/conditionalonthreading/ConditionalOnThreadingUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.conditionalonthreading; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading; +import org.springframework.boot.autoconfigure.thread.Threading; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +public class ConditionalOnThreadingUnitTest { + + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withUserConfiguration(CurrentConfig.class); + + @Configuration + static class CurrentConfig { + + @Bean + @ConditionalOnThreading(Threading.PLATFORM) + ThreadingType platformBean() { + return ThreadingType.PLATFORM; + } + + @Bean + @ConditionalOnThreading(Threading.VIRTUAL) + ThreadingType virtualBean() { + return ThreadingType.VIRTUAL; + } + } + + enum ThreadingType { + PLATFORM, VIRTUAL + } + + @Test + @EnabledForJreRange(max = JRE.JAVA_20) + public void whenJava20AndVirtualThreadsEnabled_thenThreadingIsPlatform() { + applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run(context -> { + Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM); + }); + } + + @Test + @EnabledForJreRange(max = JRE.JAVA_20) + public void whenJava20AndVirtualThreadsDisabled_thenThreadingIsPlatform() { + applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> { + Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM); + }); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_21) + public void whenJava21AndVirtualThreadsEnabled_thenThreadingIsVirtual() { + applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run(context -> { + Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.VIRTUAL); + }); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_21) + public void whenJava21AndVirtualThreadsDisabled_thenThreadingIsPlatform() { + applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> { + Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM); + }); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CassandraConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CassandraConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..4130b6cb6b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CassandraConnectionDetailsIntegrationTest.java @@ -0,0 +1,37 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.CustomCassandraConnectionDetailsConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(CustomCassandraConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-cassandra.properties"}) +@ActiveProfiles("cassandra") +public class CassandraConnectionDetailsIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(CassandraConnectionDetailsIntegrationTest.class); + @Autowired + private CassandraTemplate cassandraTemplate; + @Test + public void givenHashicorpVault_whenRunQuery_thenSuccess() { + boolean result = cassandraTemplate.getCqlOperations() + .execute("CREATE KEYSPACE IF NOT EXISTS spring_cassandra" + + " WITH replication = {'class':'SimpleStrategy', 'replication_factor':3}"); + logger.info("the result -" + result); + assertTrue(result); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CouchbaseConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CouchbaseConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..454aad4c6c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/CouchbaseConnectionDetailsIntegrationTest.java @@ -0,0 +1,30 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.CustomCouchBaseConnectionDetailsConfiguration; +import com.couchbase.client.java.Cluster; +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.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(CustomCouchBaseConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-couch.properties"}) +@ActiveProfiles("couch") +public class CouchbaseConnectionDetailsIntegrationTest { + @Autowired + private Cluster cluster; + @Test + public void givenSecretVault_whenConnectWithCouch_thenSuccess() { + assertDoesNotThrow(cluster.ping()::version); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/ElasticsearchConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/ElasticsearchConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..ee698cd6ea --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/ElasticsearchConnectionDetailsIntegrationTest.java @@ -0,0 +1,45 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.CustomElasticsearchConnectionDetailsConfiguration; +import com.baeldung.connectiondetails.entity.elastic.Person; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(CustomElasticsearchConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-elastic.properties"}) +@ActiveProfiles("elastic") +public class ElasticsearchConnectionDetailsIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(ElasticsearchConnectionDetailsIntegrationTest.class); + @Autowired + private ElasticsearchTemplate elasticsearchTemplate; + + @Before + public void prepare() { + if (elasticsearchTemplate.indexOps(Person.class).exists()) { + elasticsearchTemplate.indexOps(Person.class).delete(); + } + } + @Test + public void givenHashicorpVault_whenCreateIndexInElastic_thenSuccess() { + + boolean result = elasticsearchTemplate.indexOps(Person.class).create(); + logger.info("index created:" + result); + assertTrue(result); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/JdbcConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/JdbcConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..748bc27b0b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/JdbcConnectionDetailsIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.JdbcConnectionDetailsConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import java.sql.Date; +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(JdbcConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-jdbc.properties"}) +@ActiveProfiles("jdbc") +public class JdbcConnectionDetailsIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(JdbcConnectionDetailsIntegrationTest.class); + @Autowired + private JdbcTemplate jdbcTemplate; + @Test + public void givenSecretVault_whenIntegrateWithPostgres_thenConnectionSuccessful() { + String sql = "select current_date;"; + Date date = jdbcTemplate.queryForObject(sql, Date.class); + assertEquals(LocalDate.now().toString(), date.toString()); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/KafkaConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/KafkaConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..bc0e174b3f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/KafkaConnectionDetailsIntegrationTest.java @@ -0,0 +1,32 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.CustomKafkaConnectionDetailsConfiguration; +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.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(CustomKafkaConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-kafka.properties"}) +@ActiveProfiles("kafka") +public class KafkaConnectionDetailsIntegrationTest { + @Autowired + private KafkaTemplate kafkaTemplate; + + @Test + public void givenSecretVault_whenPublishMsgToKafkaQueue_thenSuccess() { + assertDoesNotThrow(kafkaTemplate::getDefaultTopic); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/MongoDBConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/MongoDBConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..868ebfea98 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/MongoDBConnectionDetailsIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.MongoDBConnectionDetailsConfiguration; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration; +import org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration; +import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(MongoDBConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-mongo.properties"}) +@ActiveProfiles("mongo") +public class MongoDBConnectionDetailsIntegrationTest { + + @Autowired + private MongoTemplate mongoTemplate; + @Test + public void givenSecretVault_whenExecuteQueryOnMongoDB_ReturnResult() throws JSONException { + mongoTemplate.insert("{\"msg\":\"My First Entry in MongoDB\"}", "myDemoCollection"); + String result = mongoTemplate.find(new Query(), String.class, "myDemoCollection").get(0); + + JSONObject jsonObject = new JSONObject(result); + result = jsonObject.get("msg").toString(); + R2dbcAutoConfiguration r2dbcAutoConfiguration; + R2dbcDataAutoConfiguration r2dbcDataAutoConfiguration; + R2dbcRepositoriesAutoConfiguration r2dbcRepositoriesAutoConfiguration; + + assertEquals("My First Entry in MongoDB", result); + } +} + diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/Neo4jConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/Neo4jConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..943ed7bdea --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/Neo4jConnectionDetailsIntegrationTest.java @@ -0,0 +1,43 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.CustomNeo4jConnectionDetailsConfiguration; +import com.baeldung.connectiondetails.entity.neo4j.Person; +import org.junit.After; +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.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(CustomNeo4jConnectionDetailsConfiguration.class) +@ComponentScan(basePackages = "com.baeldung.connectiondetails") +@TestPropertySource(locations = {"classpath:connectiondetails/application-neo4j.properties"}) +@ActiveProfiles("neo4j") +public class Neo4jConnectionDetailsIntegrationTest { + @Autowired + private Neo4jTemplate neo4jTemplate; + + @After + public void cleanup() { + neo4jTemplate.deleteAll(Person.class); + } + @Test + public void giveSecretVault_whenRunQuery_thenSuccess() { + Person person = new Person(); + person.setName("James"); + person.setZipcode("751003"); + + Person data = neo4jTemplate.save(person); + assertEquals("James", data.getName()); + } + +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/R2dbcConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/R2dbcConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..5f8c8349fb --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/R2dbcConnectionDetailsIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.R2dbcPostgresConnectionDetailsConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(R2dbcPostgresConnectionDetailsConfiguration.class) +@TestPropertySource(locations = {"classpath:connectiondetails/application-r2dbc.properties"}) +@ActiveProfiles("r2dbc") +public class R2dbcConnectionDetailsIntegrationTest { + Logger logger = LoggerFactory.getLogger(R2dbcConnectionDetailsIntegrationTest.class); + @Autowired + private R2dbcEntityTemplate r2dbcEntityTemplate; + + @Test + public void givenSecretVault_whenQueryPostgresReactive_thenSuccess() { + + String sql = "select * from information_schema.tables"; + + List result = r2dbcEntityTemplate.getDatabaseClient().sql(sql).fetch().all() + .map(r -> { + return "hello " + r.get("table_name").toString(); + }).collectList().block(); + logger.info("count ------" + result.size()); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RabbitmqConnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RabbitmqConnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..9e10973ed7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RabbitmqConnectionDetailsIntegrationTest.java @@ -0,0 +1,62 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.RabbitMQConnectionDetailsConfiguration; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(RabbitMQConnectionDetailsConfiguration.class) +@TestPropertySource(locations = {"classpath:connectiondetails/application-rabbitmq.properties"}) +@ActiveProfiles("rabbitmq") +public class RabbitmqConnectionDetailsIntegrationTest { + + private static final Logger logger = LoggerFactory.getLogger(RabbitmqConnectionDetailsIntegrationTest.class); + + @Autowired + private RabbitTemplate rabbitTemplate; + + @Autowired + private CachingConnectionFactory connectionFactory; + + private final static String queueName = "Test_Queue"; + + RabbitAdmin rabbitAdmin; + + @Before + public void setup() { + logger.info("create new queue"); + rabbitAdmin = new RabbitAdmin(connectionFactory); + logger.info("creating queue: " + rabbitAdmin.declareQueue(new Queue(queueName))); + connectionFactory.destroy(); + } + + @After + public void cleanup() { + logger.info("delete queue"); + this.rabbitAdmin.deleteQueue(queueName, false, true); + } + @Test + public void givenSecretVault_whenPublishMessageToRabbitmq_thenSuccess() { + logger.info("sending message to queue " + queueName); + final String MSG = "this is a test message"; + this.rabbitTemplate.convertAndSend(queueName, MSG); + assertEquals(MSG, this.rabbitTemplate.receiveAndConvert(queueName)); + } +} diff --git a/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RedisCacheConnnectionDetailsIntegrationTest.java b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RedisCacheConnnectionDetailsIntegrationTest.java new file mode 100644 index 0000000000..5dbd2d6c03 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-2/src/test/java/com/baeldung/connectiondetails/RedisCacheConnnectionDetailsIntegrationTest.java @@ -0,0 +1,34 @@ +package com.baeldung.connectiondetails; + +import com.baeldung.connectiondetails.configuration.RedisConnectionDetailsConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ConnectionDetailsApplication.class) +@Import(RedisConnectionDetailsConfiguration.class) +@TestPropertySource(locations = {"classpath:connectiondetails/application-redis.properties"}) +@ActiveProfiles("redis") +public class RedisCacheConnnectionDetailsIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(RedisCacheConnnectionDetailsIntegrationTest.class); + + @Autowired + RedisTemplate redisTemplate; + + @Test + public void giveSecretVault_whenStoreInRedisCache_thenSuccess() { + redisTemplate.opsForValue().set("City", "New York"); + assertEquals("New York", redisTemplate.opsForValue().get("City")); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/README.md b/spring-boot-modules/spring-boot-3-testcontainers/README.md new file mode 100644 index 0000000000..e6aa952295 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [Built-in Testcontainers Support in Spring Boot](https://www.baeldung.com/spring-boot-built-in-testcontainers) +- [How to Reuse Testcontainers in Java](https://www.baeldung.com/java-reuse-testcontainers) diff --git a/spring-boot-modules/spring-boot-3-testcontainers/pom.xml b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml new file mode 100644 index 0000000000..173fb8795c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + spring-boot-3-testcontainers + 0.0.1-SNAPSHOT + spring-boot-3-testcontainers + Testcontainer Improvements in Spring Boot 3 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + org.springframework.boot + spring-boot-testcontainers + + + + org.testcontainers + mongodb + ${testcontainers.version} + test + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + + + + io.rest-assured + rest-assured + ${rest-assured.version} + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 3.0.0-M7 + 1.18.3 + 5.3.1 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java new file mode 100644 index 0000000000..afe987a313 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java new file mode 100644 index 0000000000..4780a2f66a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java @@ -0,0 +1,13 @@ +package com.baeldung.testcontainers.support; + +import java.util.UUID; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document("characters") +public record MiddleEarthCharacter(@Id String id, String name, String race) { + public MiddleEarthCharacter(String name, String race) { + this(UUID.randomUUID().toString(), name, race); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java new file mode 100644 index 0000000000..3b7bfddbef --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java @@ -0,0 +1,30 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("characters") +public class MiddleEarthCharactersController { + private final MiddleEarthCharactersRepository repository; + + public MiddleEarthCharactersController(MiddleEarthCharactersRepository repository) { + this.repository = repository; + } + + @GetMapping + public List findByRace(@RequestParam String race) { + return repository.findAllByRace(race); + } + + @PostMapping + public MiddleEarthCharacter save(@RequestBody MiddleEarthCharacter character) { + return repository.save(character); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java new file mode 100644 index 0000000000..a668650670 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MiddleEarthCharactersRepository extends MongoRepository { + List findAllByRace(String race); +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/reuse/ReusableContainersLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/reuse/ReusableContainersLiveTest.java new file mode 100644 index 0000000000..4a96160e32 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/reuse/ReusableContainersLiveTest.java @@ -0,0 +1,52 @@ +package com.baeldung.testcontainers.reuse; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@SpringBootTest +class ReusableContainersLiveTest { + + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) + .withReuse(true); + + @BeforeAll + static void beforeAll() { + mongoDBContainer.start(); + } + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } + + @Autowired + private MiddleEarthCharactersRepository repository; + + @Test + void whenRunningMultipleTimes_thenContainerShouldBeReused_andTestShouldFail() { + assertThat(repository.findAll()) + .isEmpty(); + + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit")) + ); + + assertThat(repository.findAll()) + .hasSize(2); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/DynamicPropertiesLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/DynamicPropertiesLiveTest.java new file mode 100644 index 0000000000..d2511286e3 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/DynamicPropertiesLiveTest.java @@ -0,0 +1,61 @@ +package com.baeldung.testcontainers.support; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment +class DynamicPropertiesLiveTest { + @Container + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/LocalDevApplication.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/LocalDevApplication.java new file mode 100644 index 0000000000..0b49fba26b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/LocalDevApplication.java @@ -0,0 +1,33 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.devtools.restart.RestartScope; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; +import com.baeldung.testcontainers.Application; + + +// Testcontainers require a valid docker installation. +// When running the app locally, ensure you have a valid Docker environment +class LocalDevApplication { + + public static void main(String[] args) { + SpringApplication.from(Application::main) + .with(LocalDevTestcontainersConfig.class) + .run(args); + } + + @TestConfiguration(proxyBeanMethods = false) + static class LocalDevTestcontainersConfig { + @Bean + @RestartScope + @ServiceConnection + public MongoDBContainer mongoDBContainer() { + return new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + } + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/ServiceConnectionLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/ServiceConnectionLiveTest.java new file mode 100644 index 0000000000..a93c136e1c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/support/ServiceConnectionLiveTest.java @@ -0,0 +1,57 @@ +package com.baeldung.testcontainers.support; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.test.annotation.DirtiesContext; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment +class ServiceConnectionLiveTest { + + @Container + @ServiceConnection + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-url-matching/pom.xml b/spring-boot-modules/spring-boot-3-url-matching/pom.xml index aa83a676d7..43f89eab47 100644 --- a/spring-boot-modules/spring-boot-3-url-matching/pom.xml +++ b/spring-boot-modules/spring-boot-3-url-matching/pom.xml @@ -67,7 +67,7 @@ io.projectreactor reactor-test - ${reactor-test.version} + ${reactor-core.version} test diff --git a/spring-boot-modules/spring-boot-3/README.md b/spring-boot-modules/spring-boot-3/README.md index 8791aaae1f..ded5db30e4 100644 --- a/spring-boot-modules/spring-boot-3/README.md +++ b/spring-boot-modules/spring-boot-3/README.md @@ -8,3 +8,4 @@ - [HTTP Interface in Spring 6](https://www.baeldung.com/spring-6-http-interface) - [Working with Virtual Threads in Spring 6](https://www.baeldung.com/spring-6-virtual-threads) - [Docker Compose Support in Spring Boot 3](https://www.baeldung.com/ops/docker-compose-support-spring-boot) +- [A Guide to RestClient in Spring Boot](https://www.baeldung.com/spring-boot-restclient) diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index 32c69801ca..bb8c5dd53c 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-3 0.0.1-SNAPSHOT @@ -41,6 +41,31 @@ mockserver-netty ${mockserver.version} + + org.junit.jupiter + junit-jupiter + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-api + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-engine + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-params + ${jupiter.version} + + + org.junit.platform + junit-platform-commons + 1.10.0 + org.mock-server mockserver-client-java @@ -49,7 +74,6 @@ com.h2database h2 - runtime @@ -184,12 +208,50 @@ 19 1.5.2.Final - 2.0.0 + 2.2.0 3.0.0-M7 com.baeldung.sample.TodoApplication 5.14.0 - 3.1.0 + 3.2.0-SNAPSHOT 0.2.0 + 5.10.0 + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java new file mode 100644 index 0000000000..892cf3b5ae --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java @@ -0,0 +1,44 @@ +package com.baeldung.restclient; + +import java.util.Objects; + +public class Article { + Integer id; + String title; + + public Article() {} + + public Article(Integer id, String title) { + this.id = id; + this.title = title; + } + + public Integer getId() { + return id; + } + + public String getTitle() { + return title; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Article article = (Article) o; + return Objects.equals(id, article.id) && Objects.equals(title, article.title); + } + + @Override + public int hashCode() { + return Objects.hash(id, title); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java new file mode 100644 index 0000000000..5e1dff6fd7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java @@ -0,0 +1,54 @@ +package com.baeldung.restclient; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@RestController +@RequestMapping("/articles") +public class ArticleController { + Map database = new HashMap<>(); + + @GetMapping + public ResponseEntity> getArticles() { + Collection
values = database.values(); + if (values.isEmpty()) { + return ResponseEntity.noContent().build(); + } + return ResponseEntity.ok(values); + } + + @GetMapping("/{id}") + public ResponseEntity
getArticle(@PathVariable("id") Integer id) { + Article article = database.get(id); + if (article == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(article); + } + + @PostMapping + public void createArticle(@RequestBody Article article) { + database.put(article.getId(), article); + } + + @PutMapping("/{id}") + public void updateArticle(@PathVariable("id") Integer id, @RequestBody Article article) { + assert Objects.equals(id, article.getId()); + database.remove(id); + database.put(id, article); + } + + @DeleteMapping("/{id}") + public void deleteArticle(@PathVariable Integer id) { + database.remove(id); + } + @DeleteMapping() + public void deleteArticles() { + database.clear(); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java new file mode 100644 index 0000000000..cdd13b8330 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class ArticleNotFoundException extends RuntimeException { + public ArticleNotFoundException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java new file mode 100644 index 0000000000..26ca75036e --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class InvalidArticleResponseException extends RuntimeException { + public InvalidArticleResponseException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java new file mode 100644 index 0000000000..c411a8f74a --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.restclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RestClientApplication { + + public static void main(String[] args) { + SpringApplication.run(RestClientApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml b/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml deleted file mode 100644 index bce67fa400..0000000000 --- a/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml +++ /dev/null @@ -1,7 +0,0 @@ -spring: - docker: - compose: - enabled: true - file: docker-compose.yml - autoconfigure: - exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java new file mode 100644 index 0000000000..1a615faf4e --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java @@ -0,0 +1,166 @@ +package com.baeldung.restclient; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestClient; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class RestClientIntegrationTest { + + @LocalServerPort + private int port; + private String uriBase; + RestClient restClient = RestClient.create(); + + @Autowired + ObjectMapper objectMapper; + + @BeforeEach + public void setup() { + uriBase = "http://localhost:" + port; + } + + @AfterEach + public void teardown() { + restClient.delete() + .uri(uriBase + "/articles") + .retrieve() + .toBodilessEntity(); + } + + @Test + void shouldGetArticlesAndReturnString() { + String articlesAsString = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(String.class); + + assertThat(articlesAsString).isEqualTo(""); + } + + @Test + void shouldPostAndGetArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + List
articles = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(new ParameterizedTypeReference<>() {}); + + assertThat(articles).isEqualTo(List.of(article)); + } + + @Test + void shouldPostAndGetArticlesWithExchange() { + assertThatThrownBy(this::getArticlesWithExchange).isInstanceOf(ArticleNotFoundException.class); + + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + List
articles = getArticlesWithExchange(); + + assertThat(articles).isEqualTo(List.of(article)); + } + + private List
getArticlesWithExchange() { + return restClient.get() + .uri(uriBase + "/articles") + .exchange((request, response) -> { + if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(204))) { + throw new ArticleNotFoundException(); + } else if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) { + return objectMapper.readValue(response.getBody(), new TypeReference<>() {}); + } else { + throw new InvalidArticleResponseException(); + } + }); + } + + @Test + void shouldPostAndGetArticlesWithErrorHandling() { + assertThatThrownBy(() -> { + restClient.get() + .uri(uriBase + "/articles/1234") + .retrieve() + .onStatus(status -> status.value() == 404, (request, response) -> { throw new ArticleNotFoundException(); }) + .body(new ParameterizedTypeReference<>() {}); + }).isInstanceOf(ArticleNotFoundException.class); + } + + @Test + void shouldPostAndPutAndGetArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + Article articleChanged = new Article(1, "How to use RestClient even better"); + restClient.put() + .uri(uriBase + "/articles/1") + .contentType(MediaType.APPLICATION_JSON) + .body(articleChanged) + .retrieve() + .toBodilessEntity(); + + List
articles = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(new ParameterizedTypeReference<>() {}); + + assertThat(articles).isEqualTo(List.of(articleChanged)); + } + + @Test + void shouldPostAndDeleteArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + restClient.delete() + .uri(uriBase + "/articles") + .retrieve() + .toBodilessEntity(); + + ResponseEntity entity = restClient.get() + .uri(uriBase + "/articles") + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .toBodilessEntity(); + + assertThat(entity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204)); + } +} diff --git a/spring-boot-modules/spring-boot-actuator/pom.xml b/spring-boot-modules/spring-boot-actuator/pom.xml index 1ccf436bbf..7f630fa96e 100644 --- a/spring-boot-modules/spring-boot-actuator/pom.xml +++ b/spring-boot-modules/spring-boot-actuator/pom.xml @@ -9,9 +9,10 @@ This is simple boot application for Spring boot actuator test - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -39,16 +40,6 @@ com.h2database h2 - - javax.servlet - javax.servlet-api - provided - - - javax.servlet - jstl - runtime - org.springframework.boot spring-boot-starter-test diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java index 894c24693e..20ee834d52 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java @@ -1,36 +1,56 @@ package com.baeldung.endpoints.enabling; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; -import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -@Configuration @EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { +@Configuration +public class SecurityConfiguration { - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); - auth.inMemoryAuthentication() - .withUser("user") - .password(encoder.encode("password")) - .roles("USER") - .and() - .withUser("admin") - .password(encoder.encode("admin")) - .roles("USER", "ADMIN"); + @Bean + MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) { + return new MvcRequestMatcher.Builder(introspector); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()) - .authorizeRequests((requests) -> requests.anyRequest() - .hasRole("ADMIN")); - http.httpBasic(); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception { + http.httpBasic(Customizer.withDefaults()); + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests(authz -> { + authz.requestMatchers(mvc.pattern("/actuator/**")) + .hasRole("ADMIN") + .anyRequest() + .authenticated(); + }); + + return http.build(); + } + + + + @Bean + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + UserDetails admin = User.withDefaultPasswordEncoder() + .username("admin") + .password("password") + .roles("USER", "ADMIN") + .build(); + return new InMemoryUserDetailsManager(user, admin); } } diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java index db4e69127a..88f39d8ccc 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java @@ -1,9 +1,9 @@ package com.baeldung.endpoints.info; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "users") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java index 729b3c0b96..ee87412986 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java @@ -15,7 +15,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.context.request.RequestContextListener; -import javax.servlet.ServletContext; +import jakarta.servlet.ServletContext; @EnableScheduling @ComponentScan("com.baeldung.metrics") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java index 0f7579f060..a7aaddf0fb 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java @@ -7,14 +7,14 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @Component public class MetricFilter implements Filter { diff --git a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java index 8274619517..079195714b 100644 --- a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java +++ b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java @@ -13,20 +13,20 @@ import org.springframework.test.web.servlet.MockMvc; @SpringBootTest @AutoConfigureMockMvc -public class EndpointEnablingIntegrationTest { +class EndpointEnablingIntegrationTest { @Autowired private MockMvc mockMvc; @Test @WithMockUser(username = "user", password = "password", roles = "USER") - public void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception { + void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception { mockMvc.perform(get("/actuator")) .andExpect(status().isForbidden()); } @Test @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") - public void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception { + void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception { mockMvc.perform(get("/actuator")) .andExpect(jsonPath("$._links").exists()) .andExpect(jsonPath("$._links.beans").exists()) diff --git a/spring-boot-modules/spring-boot-artifacts/pom.xml b/spring-boot-modules/spring-boot-artifacts/pom.xml index dedeb0ab2a..e39ddb5af1 100644 --- a/spring-boot-modules/spring-boot-artifacts/pom.xml +++ b/spring-boot-modules/spring-boot-artifacts/pom.xml @@ -193,7 +193,6 @@ 2.2.4 3.1.7 4.5.8 - 2.18 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-autoconfiguration/pom.xml b/spring-boot-modules/spring-boot-autoconfiguration/pom.xml index 7a3f9f01e8..7880a033f8 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/pom.xml +++ b/spring-boot-modules/spring-boot-autoconfiguration/pom.xml @@ -10,9 +10,10 @@ This is simple boot application demonstrating a custom auto-configuration - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -66,6 +67,13 @@ org.apache.maven.plugins maven-war-plugin + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.autoconfiguration.example.AutoconfigurationApplication + + diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/MySQLAutoconfiguration.java b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/MySQLAutoconfiguration.java index 295e0d74c9..c470656597 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/MySQLAutoconfiguration.java +++ b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/MySQLAutoconfiguration.java @@ -3,10 +3,10 @@ package com.baeldung.autoconfiguration; import java.util.Arrays; import java.util.Properties; -import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style; @@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; @@ -31,7 +30,9 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.util.ClassUtils; -@Configuration +import jakarta.persistence.EntityManagerFactory; + +@AutoConfiguration @ConditionalOnClass(DataSource.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @PropertySource("classpath:mysql.properties") diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/annotationprocessor/DatabaseProperties.java b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/annotationprocessor/DatabaseProperties.java index 4fb5b408a2..47f07c808f 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/annotationprocessor/DatabaseProperties.java +++ b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/annotationprocessor/DatabaseProperties.java @@ -1,11 +1,13 @@ package com.baeldung.autoconfiguration.annotationprocessor; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; + @Configuration @ConfigurationProperties(prefix = "database") public class DatabaseProperties { diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/example/MyUser.java b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/example/MyUser.java index 31ce0fd969..26a2e04e2f 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/example/MyUser.java +++ b/spring-boot-modules/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/example/MyUser.java @@ -1,7 +1,7 @@ package com.baeldung.autoconfiguration.example; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Entity public class MyUser { diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring.factories b/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 11c775fc6c..0000000000 --- a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baeldung.autoconfiguration.MySQLAutoconfiguration diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000..ab28361814 --- /dev/null +++ b/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.baeldung.autoconfiguration.MySQLAutoconfiguration diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/mysql.properties b/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/mysql.properties index 74f1ee1373..27092f852f 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/mysql.properties +++ b/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/mysql.properties @@ -1,5 +1,5 @@ usemysql=local -mysql-hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect mysql-hibernate.show_sql=true mysql-hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-aws/pom.xml b/spring-boot-modules/spring-boot-aws/pom.xml index 12a65908af..44cd38be3f 100644 --- a/spring-boot-modules/spring-boot-aws/pom.xml +++ b/spring-boot-modules/spring-boot-aws/pom.xml @@ -9,10 +9,12 @@ spring-boot-aws spring-boot-aws + - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + org.springframework.boot + spring-boot-starter-parent + 2.7.11 + @@ -23,7 +25,7 @@ com.amazonaws.serverless aws-serverless-java-container-springboot2 - ${springboot2.aws.version} + ${aws-serverless-java-container-springboot2.version} org.springframework.boot @@ -64,16 +66,18 @@ org.apache.maven.plugins maven-compiler-plugin - 11 - 11 + ${maven.compiler.source.version} + ${maven.compiler.target.version} - 1.9.1 + 1.9.1 3.2.4 + 11 + 11 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-basic-customization/pom.xml b/spring-boot-modules/spring-boot-basic-customization/pom.xml index 4b1009d38a..581a7fec06 100644 --- a/spring-boot-modules/spring-boot-basic-customization/pom.xml +++ b/spring-boot-modules/spring-boot-basic-customization/pom.xml @@ -86,5 +86,4 @@ com.baeldung.changeport.CustomApplication - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-bootstrap/pom.xml b/spring-boot-modules/spring-boot-bootstrap/pom.xml index 4ceae26f60..da16f79a2a 100644 --- a/spring-boot-modules/spring-boot-bootstrap/pom.xml +++ b/spring-boot-modules/spring-boot-bootstrap/pom.xml @@ -9,9 +9,10 @@ Demo project for Spring Boot - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -47,13 +48,12 @@ io.rest-assured rest-assured - ${rest-assured.version} test - javax.servlet - javax.servlet-api - ${servlet.version} + org.springframework.boot + spring-boot-starter-cloud-connectors + ${spring-boot-cloud-connectors.version} @@ -332,6 +332,7 @@ 4.0.0 Greenwich.RELEASE 1.0.0.RELEASE + 2.2.13.RELEASE \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java index ecb21cdf4b..c876e1c3d4 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java @@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; @Configuration @@ -12,12 +13,11 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.authorizeRequests() - .anyRequest() - .permitAll() - .and() - .csrf() - .disable(); + http.authorizeHttpRequests(expressionInterceptUrlRegistry -> + expressionInterceptUrlRegistry + .anyRequest() + .permitAll()) + .csrf(AbstractHttpConfigurer::disable); return http.build(); } } diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java index 6be27d4cf0..d599c64567 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java @@ -1,10 +1,10 @@ package com.baeldung.persistence.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Book { diff --git a/spring-boot-modules/spring-boot-ci-cd/pom.xml b/spring-boot-modules/spring-boot-ci-cd/pom.xml index 8c12c98236..6e58f1162d 100644 --- a/spring-boot-modules/spring-boot-ci-cd/pom.xml +++ b/spring-boot-modules/spring-boot-ci-cd/pom.xml @@ -34,7 +34,7 @@ org.jacoco jacoco-maven-plugin - 0.8.5 + ${jacoco-maven-plugin.version} default-prepare-agent @@ -65,7 +65,7 @@ com.heroku.sdk heroku-maven-plugin - 3.0.2 + ${heroku-maven-plugin.version} spring-boot-ci-cd @@ -88,7 +88,7 @@ com.google.cloud.tools jib-maven-plugin - 2.2.0 + ${jib-maven-plugin.version} registry.hub.docker.com/baeldungjib/baeldung-ci-cd-process @@ -104,4 +104,10 @@ + + 0.8.5 + 3.0.2 + 2.2.0 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-cli/pom.xml b/spring-boot-modules/spring-boot-cli/pom.xml index 76b14b2103..19607ac21c 100644 --- a/spring-boot-modules/spring-boot-cli/pom.xml +++ b/spring-boot-modules/spring-boot-cli/pom.xml @@ -6,7 +6,6 @@ spring-boot-cli spring-boot-cli jar - com.baeldung.spring-boot-modules diff --git a/spring-boot-modules/spring-boot-crud/pom.xml b/spring-boot-modules/spring-boot-crud/pom.xml index 7acaa49e87..35f3ec114d 100644 --- a/spring-boot-modules/spring-boot-crud/pom.xml +++ b/spring-boot-modules/spring-boot-crud/pom.xml @@ -59,7 +59,7 @@ org.apache.maven.plugins maven-assembly-plugin - 3.3.0 + ${maven-assembly-plugin.version} jar-with-dependencies @@ -78,4 +78,8 @@ + + 3.3.0 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-data-2/README.md b/spring-boot-modules/spring-boot-data-2/README.md index 9ff2b2caf8..8e6619dce4 100644 --- a/spring-boot-modules/spring-boot-data-2/README.md +++ b/spring-boot-modules/spring-boot-data-2/README.md @@ -1,7 +1,6 @@ ### Relevant Articles: - [HttpMessageNotWritableException: No Converter for [class …] With Preset Content-Type](https://www.baeldung.com/spring-no-converter-with-preset) -- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper) - [“HttpMessageNotWritableException: No converter found for return value of type”](https://www.baeldung.com/spring-no-converter-found) - [Creating a Read-Only Repository with Spring Data](https://www.baeldung.com/spring-data-read-only-repository) - [Using JaVers for Data Model Auditing in Spring Data](https://www.baeldung.com/spring-data-javers-audit) diff --git a/spring-boot-modules/spring-boot-data-3/pom.xml b/spring-boot-modules/spring-boot-data-3/pom.xml index 4903d2ea26..6c2edbb864 100644 --- a/spring-boot-modules/spring-boot-data-3/pom.xml +++ b/spring-boot-modules/spring-boot-data-3/pom.xml @@ -27,7 +27,7 @@ com.amazonaws.secretsmanager aws-secretsmanager-jdbc - ${aws.secrets.manager.jdbc} + ${aws-secretsmanager-jdbc.version} mysql @@ -46,7 +46,7 @@ io.awspring.cloud spring-cloud-starter-aws-secrets-manager-config - ${aws.secrets.manager.config} + ${spring-cloud-starter-aws-secrets-manager-config.version} @@ -60,8 +60,8 @@ - 2.4.4 - 1.0.11 + 2.4.4 + 1.0.11 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-data/README.md b/spring-boot-modules/spring-boot-data/README.md index c56c87014d..aa745b77a2 100644 --- a/spring-boot-modules/spring-boot-data/README.md +++ b/spring-boot-modules/spring-boot-data/README.md @@ -11,4 +11,5 @@ This module contains articles about Spring Boot with Spring Data - [Spring Custom Property Editor](https://www.baeldung.com/spring-mvc-custom-property-editor) - [Using @JsonComponent in Spring Boot](https://www.baeldung.com/spring-boot-jsoncomponent) - [Guide To Running Logic on Startup in Spring](https://www.baeldung.com/running-setup-logic-on-startup-in-spring) +- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper) diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/app/Application.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/app/Application.java similarity index 100% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/app/Application.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/app/Application.java diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java similarity index 100% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java index d1875d03d9..ecb07e44b1 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeConstants.java @@ -1,10 +1,10 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; - import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; + public class CoffeeConstants { public static final String DATETIME_FORMAT = "dd-MM-yyyy HH:mm"; diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java index edb2b478fc..0aa2d3eb96 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeCustomizerConfig.java @@ -1,11 +1,12 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.annotation.JsonInclude; +import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; + import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; +import com.fasterxml.jackson.annotation.JsonInclude; @Configuration public class CoffeeCustomizerConfig { diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java index eff2b5c252..be8e3bb34d 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeHttpConverterConfiguration.java @@ -1,12 +1,13 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.annotation.JsonInclude; +import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; +import com.fasterxml.jackson.annotation.JsonInclude; @Configuration public class CoffeeHttpConverterConfiguration { diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java index 8057fff3db..19501f872c 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeJacksonBuilderConfig.java @@ -1,12 +1,13 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.annotation.JsonInclude; +import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; +import com.fasterxml.jackson.annotation.JsonInclude; @Configuration public class CoffeeJacksonBuilderConfig { diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java index f1ce6458ae..cadf17b6b8 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeObjectMapperConfig.java @@ -1,13 +1,14 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; -import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @Configuration public class CoffeeObjectMapperConfig { diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java similarity index 88% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java index fc157f8156..55a928dabc 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/config/CoffeeRegisterModuleConfig.java @@ -1,19 +1,19 @@ package com.baeldung.boot.jackson.config; -import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; -import static com.baeldung.boot.jackson.config.CoffeeConstants.LOCAL_DATETIME_SERIALIZER; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @Configuration @PropertySource("classpath:coffee.properties") public class CoffeeRegisterModuleConfig { @Bean - public Module javaTimeModule() { + public JavaTimeModule javaTimeModule() { JavaTimeModule module = new JavaTimeModule(); module.addSerializer(LOCAL_DATETIME_SERIALIZER); return module; diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java index 23749b18a2..36489a645a 100644 --- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java +++ b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/controller/CoffeeController.java @@ -1,11 +1,12 @@ package com.baeldung.boot.jackson.controller; -import com.baeldung.boot.jackson.model.Coffee; +import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE; + import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE; +import com.baeldung.boot.jackson.model.Coffee; @RestController public class CoffeeController { diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/model/Coffee.java b/spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/model/Coffee.java similarity index 100% rename from spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/jackson/model/Coffee.java rename to spring-boot-modules/spring-boot-data/src/main/java/com/baeldung/boot/jackson/model/Coffee.java diff --git a/spring-boot-modules/spring-boot-data-2/src/main/resources/coffee.properties b/spring-boot-modules/spring-boot-data/src/main/resources/coffee.properties similarity index 100% rename from spring-boot-modules/spring-boot-data-2/src/main/resources/coffee.properties rename to spring-boot-modules/spring-boot-data/src/main/resources/coffee.properties diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java index f1bc35a8ce..961ab8979c 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/AbstractCoffeeIntegrationTest.java @@ -1,15 +1,16 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeConstants; +import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.format.DateTimeFormatter; + import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; -import java.time.format.DateTimeFormatter; - -import static com.baeldung.boot.jackson.config.CoffeeConstants.FIXED_DATE; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.boot.jackson.config.CoffeeConstants; @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public abstract class AbstractCoffeeIntegrationTest { diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java index d690de1b9c..ed5baf239c 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeCustomizerIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeCustomizerConfig; import org.springframework.context.annotation.Import; +import com.baeldung.boot.jackson.config.CoffeeCustomizerConfig; + @Import(CoffeeCustomizerConfig.class) public class CoffeeCustomizerIntegrationTest extends AbstractCoffeeIntegrationTest { } diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java index 62b1d42152..0c77948d8e 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeHttpConverterIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeHttpConverterConfiguration; import org.springframework.context.annotation.Import; +import com.baeldung.boot.jackson.config.CoffeeHttpConverterConfiguration; + @Import(CoffeeHttpConverterConfiguration.class) public class CoffeeHttpConverterIntegrationTest extends AbstractCoffeeIntegrationTest { } diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java index 52a55394c0..da9251de99 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeJacksonBuilderIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeJacksonBuilderConfig; import org.springframework.context.annotation.Import; +import com.baeldung.boot.jackson.config.CoffeeJacksonBuilderConfig; + @Import(CoffeeJacksonBuilderConfig.class) public class CoffeeJacksonBuilderIntegrationTest extends AbstractCoffeeIntegrationTest { } diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java index 34743ceba5..1226eacbf2 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeObjectMapperIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeObjectMapperConfig; import org.springframework.context.annotation.Import; +import com.baeldung.boot.jackson.config.CoffeeObjectMapperConfig; + @Import(CoffeeObjectMapperConfig.class) public class CoffeeObjectMapperIntegrationTest extends AbstractCoffeeIntegrationTest { } diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java similarity index 99% rename from spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java rename to spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java index 69bbd5be2a..38dc4a76cd 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java +++ b/spring-boot-modules/spring-boot-data/src/test/java/com/baeldung/boot/jackson/app/CoffeeRegisterModuleIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung.boot.jackson.app; -import com.baeldung.boot.jackson.config.CoffeeRegisterModuleConfig; import org.springframework.context.annotation.Import; +import com.baeldung.boot.jackson.config.CoffeeRegisterModuleConfig; + @Import(CoffeeRegisterModuleConfig.class) public class CoffeeRegisterModuleIntegrationTest extends AbstractCoffeeIntegrationTest { } diff --git a/spring-boot-modules/spring-boot-deployment/pom.xml b/spring-boot-modules/spring-boot-deployment/pom.xml index a1819c4f38..890a5be58f 100644 --- a/spring-boot-modules/spring-boot-deployment/pom.xml +++ b/spring-boot-modules/spring-boot-deployment/pom.xml @@ -113,7 +113,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.18 + ${maven-failsafe-plugin.version} @@ -181,6 +181,7 @@ 2.2 3.1.7 4.5.8 + 2.18 \ No newline at end of file diff --git a/spring-boot-documentation/README.md b/spring-boot-modules/spring-boot-documentation/README.md similarity index 100% rename from spring-boot-documentation/README.md rename to spring-boot-modules/spring-boot-documentation/README.md diff --git a/spring-boot-documentation/springwolf/docker-compose.yml b/spring-boot-modules/spring-boot-documentation/docker-compose.yml similarity index 100% rename from spring-boot-documentation/springwolf/docker-compose.yml rename to spring-boot-modules/spring-boot-documentation/docker-compose.yml diff --git a/spring-boot-modules/spring-boot-documentation/pom.xml b/spring-boot-modules/spring-boot-documentation/pom.xml new file mode 100644 index 0000000000..3ac2799258 --- /dev/null +++ b/spring-boot-modules/spring-boot-documentation/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + com.baeldung.spring-boot-documentation + spring-boot-documentation + 1.0.0-SNAPSHOT + spring-boot-documentation + Documentation Spring Event Driven API Using AsyncAPI and Springwolf + pom + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3/pom.xml + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.kafka + spring-kafka + + + io.swagger.core.v3 + swagger-core-jakarta + ${swagger-core-jakarta.version} + + + io.github.springwolf + springwolf-kafka + ${springwolf-kafka.version} + + + io.github.springwolf + springwolf-ui + ${springwolf-ui.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.kafka + spring-kafka-test + test + + + org.testcontainers + junit-jupiter + ${testcontainers-kafka.version} + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.boot.documentation.springwolf.SpringwolfApplication + + + + + + + 2.2.11 + 0.14.0 + 0.14.0 + 1.18.3 + + + diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java diff --git a/spring-boot-documentation/springwolf/src/main/resources/application.properties b/spring-boot-modules/spring-boot-documentation/src/main/resources/application.properties similarity index 100% rename from spring-boot-documentation/springwolf/src/main/resources/application.properties rename to spring-boot-modules/spring-boot-documentation/src/main/resources/application.properties diff --git a/spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java b/spring-boot-modules/spring-boot-documentation/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java similarity index 100% rename from spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java rename to spring-boot-modules/spring-boot-documentation/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java diff --git a/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json similarity index 94% rename from spring-boot-documentation/springwolf/src/test/resources/asyncapi.json rename to spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json index 0198733c1c..45be27f571 100644 --- a/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json +++ b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json @@ -18,7 +18,9 @@ "operationId": "incoming-topic_publish", "description": "More details for the incoming topic", "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } }, "message": { "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", @@ -32,7 +34,9 @@ "$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto" }, "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } } } } @@ -42,7 +46,9 @@ "operationId": "outgoing-topic_subscribe", "description": "More details for the outgoing topic", "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } }, "message": { "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", @@ -56,7 +62,9 @@ "$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto" }, "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } } } } diff --git a/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile new file mode 100644 index 0000000000..91a63074c1 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile @@ -0,0 +1,3 @@ +FROM ubuntu:jammy +COPY target/springboot-graalvm-docker /springboot-graalvm-docker +CMD ["/springboot-graalvm-docker"] diff --git a/spring-boot-modules/spring-boot-graalvm-docker/README.md b/spring-boot-modules/spring-boot-graalvm-docker/README.md new file mode 100644 index 0000000000..10a764053e --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image) diff --git a/spring-boot-modules/spring-boot-graalvm-docker/pom.xml b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml new file mode 100644 index 0000000000..a3a1b148c2 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + com.baeldung + spring-boot-graalvm-docker + 1.0.0 + spring-boot-graalvm-docker + Spring Boot GrralVM with Docker + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java new file mode 100644 index 0000000000..53e11aa749 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.graalvmdockerimage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class GraalvmDockerImageApplication { + + public static void main(String[] args) { + SpringApplication.run(GraalvmDockerImageApplication.class, args); + } + +} + +@RestController +class HelloController { + + @GetMapping + public String hello() { + return "Hello GraalVM"; + } +} diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/spring-boot-modules/spring-boot-graphql/pom.xml b/spring-boot-modules/spring-boot-graphql/pom.xml index 628babbd3f..d3c122709d 100644 --- a/spring-boot-modules/spring-boot-graphql/pom.xml +++ b/spring-boot-modules/spring-boot-graphql/pom.xml @@ -18,7 +18,7 @@ kr.motd.maven os-maven-plugin - 1.7.0 + ${os-maven-plugin.version} @@ -43,17 +43,6 @@ - - 3.19.2 - 0.6.1 - 1.43.2 - 2.13.1.RELEASE - 1.5.1 - 1.3.5 - 1.6.2 - 3.3.2 - - org.springframework.boot @@ -88,7 +77,7 @@ jakarta.annotation jakarta.annotation-api - ${jakarta.annotation.version} + ${jakarta.annotation-api.version} true @@ -119,4 +108,16 @@ + + 3.19.2 + 0.6.1 + 1.43.2 + 2.13.1.RELEASE + 1.5.1 + 1.3.5 + 1.6.2 + 3.3.2 + 1.7.0 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-groovy/pom.xml b/spring-boot-modules/spring-boot-groovy/pom.xml index ab1fef6865..151160bde5 100644 --- a/spring-boot-modules/spring-boot-groovy/pom.xml +++ b/spring-boot-modules/spring-boot-groovy/pom.xml @@ -50,7 +50,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 1.9.0 + ${gmavenplus-plugin.version} @@ -72,6 +72,7 @@ com.baeldung.springwithgroovy.SpringBootGroovyApplication 3.0.13 + 1.9.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jasypt/pom.xml b/spring-boot-modules/spring-boot-jasypt/pom.xml index 8595b9c639..70bbe35319 100644 --- a/spring-boot-modules/spring-boot-jasypt/pom.xml +++ b/spring-boot-modules/spring-boot-jasypt/pom.xml @@ -27,7 +27,7 @@ com.github.ulisesbocchio - jasypt-spring-boot-starter + jasypt-spring-boot-starter ${jasypt.version} @@ -47,7 +47,6 @@ - 2.0.0 + 3.0.5 - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-2/pom.xml b/spring-boot-modules/spring-boot-keycloak-2/pom.xml index 4c4f403776..7909e2e153 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-2/pom.xml @@ -11,16 +11,11 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT - - 21.0.1 - - org.springframework.boot @@ -88,4 +83,8 @@ + + 21.0.1 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml index 035c226b6d..34c0653fbd 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index a4d6e18fd5..ebba1f7f67 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -12,9 +12,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -55,7 +55,7 @@ wsdl4j wsdl4j - 1.6.3 + ${wsdl4j.version} org.springframework.boot @@ -103,9 +103,10 @@ - com.baeldung.keycloak.SpringBoot + com.baeldung.keycloak.SpringBootKeycloakApp 4.0.0 - 2.5.0 + 1.6.3 + 3.1.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/Customer.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/Customer.java index 3293446b1d..b0aff5e724 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/Customer.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/Customer.java @@ -1,9 +1,9 @@ package com.baeldung.keycloak; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Customer { diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java index 06c41e9b1d..d04fff8378 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java @@ -10,8 +10,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @Component public class KeycloakLogoutHandler implements LogoutHandler { diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java index 1ad22d9397..eb7767480f 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -2,6 +2,7 @@ package com.baeldung.keycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -11,6 +12,7 @@ import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @EnableWebSecurity @@ -27,18 +29,30 @@ class SecurityConfig { return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } + @Order(1) @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests() - .antMatchers("/customers*") - .hasRole("USER") + .requestMatchers(new AntPathRequestMatcher("/")) + .permitAll() .anyRequest() - .permitAll(); + .authenticated(); http.oauth2Login() .and() .logout() .addLogoutHandler(keycloakLogoutHandler) .logoutSuccessUrl("/"); + return http.build(); + } + + @Order(2) + @Bean + public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .requestMatchers(new AntPathRequestMatcher("/customers*")) + .hasRole("USER") + .anyRequest() + .authenticated(); http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); } diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java similarity index 80% rename from spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java rename to spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java index 90d7e774a4..a6f978fb3f 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java @@ -6,11 +6,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication - -public class SpringBoot { +public class SpringBootKeycloakApp { public static void main(String[] args) { - SpringApplication.run(SpringBoot.class, args); + SpringApplication.run(SpringBootKeycloakApp.class, args); } @Bean diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/WebController.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/WebController.java index bbd96c8135..8843aee25a 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/WebController.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/WebController.java @@ -8,7 +8,7 @@ import java.security.Principal; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @Controller public class WebController { diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/ProductsEndpoint.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/ProductsEndpoint.java index 58f7739af0..b072789078 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/ProductsEndpoint.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/ProductsEndpoint.java @@ -10,7 +10,7 @@ import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import java.util.Map; @Endpoint diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java index 336c8364aa..116516acfe 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java +++ b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java @@ -4,10 +4,9 @@ import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.baeldung.keycloak.SpringBoot; @ExtendWith(SpringExtension.class) -@SpringBootTest(classes = { SpringBoot.class }) +@SpringBootTest(classes = { SpringBootKeycloakApp.class }) public class KeycloakContextIntegrationTest { @Test diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloaksoap/KeycloakSoapLiveTest.java b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloaksoap/KeycloakSoapLiveTest.java index 171c7bf330..508061396f 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloaksoap/KeycloakSoapLiveTest.java +++ b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloaksoap/KeycloakSoapLiveTest.java @@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; diff --git a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml index b429339417..31c0f4bd02 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml @@ -9,10 +9,9 @@ Demo project for Spring Boot Logging with Log4J2 - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-mvc-4/pom.xml b/spring-boot-modules/spring-boot-mvc-4/pom.xml index dbbb03ad0e..0ae05a764b 100644 --- a/spring-boot-modules/spring-boot-mvc-4/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-4/pom.xml @@ -9,9 +9,10 @@ Module For Spring Boot MVC Web - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java index 80c75aa8b5..cedc60bd92 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java @@ -4,10 +4,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Objects; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; public class HelloWorldServlet extends HttpServlet { private static final long serialVersionUID = 1L; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java index f276f94b7c..dbb8ea1b32 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java @@ -4,10 +4,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Objects; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; public class SpringHelloWorldServlet extends HttpServlet { private static final long serialVersionUID = 1L; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java index 3f51a4ab69..b2d6f249a5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java @@ -2,7 +2,7 @@ package com.baeldung.common.error; import org.springframework.boot.web.servlet.ServletRegistrationBean; -import javax.servlet.Servlet; +import jakarta.servlet.Servlet; public class SpringHelloServletRegistrationBean extends ServletRegistrationBean { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java index eadd40355a..7fd83fd59a 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java @@ -4,9 +4,9 @@ import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRegistration; public class WebAppInitializer implements WebApplicationInitializer { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java index 49dd9404b7..ee70a142be 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java @@ -1,9 +1,9 @@ package com.baeldung.servlets.servlets; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java index 992976ca0e..62706be348 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java @@ -1,10 +1,10 @@ package com.baeldung.servlets.servlets.javaee; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" }) diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java index c7b373064f..299a1b5d95 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java @@ -1,9 +1,9 @@ package com.baeldung.servlets.servlets.javaee; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java index ce3eae7ce0..eab5869cd5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java @@ -1,6 +1,6 @@ package com.baeldung.utils; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java index 8c7f2f932a..40acc1801f 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java @@ -1,6 +1,6 @@ package com.baeldung.utils.controller; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java index 080f660c40..f59d00f871 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java @@ -1,32 +1,34 @@ package com.baeldung.utils; import com.baeldung.utils.controller.UtilsController; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; + import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.mockito.MockitoAnnotations.openMocks; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -public class UtilsControllerIntegrationTest { +class UtilsControllerIntegrationTest { @InjectMocks private UtilsController utilsController; private MockMvc mockMvc; - @Before + @BeforeEach public void setup() { - MockitoAnnotations.initMocks(this); + openMocks(this); this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build(); } @Test - public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception { + void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception { String param = "testparam"; this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk()); } diff --git a/spring-boot-modules/spring-boot-mvc-5/pom.xml b/spring-boot-modules/spring-boot-mvc-5/pom.xml index 5a4f8a6cce..a516cab049 100644 --- a/spring-boot-modules/spring-boot-mvc-5/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-5/pom.xml @@ -47,7 +47,7 @@ commons-configuration commons-configuration - 1.10 + ${commons-configuration.version} @@ -68,6 +68,7 @@ 3.0.0 com.baeldung.springboot.swagger.ArticleApplication 2021.0.5 + 1.10 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-birt/pom.xml b/spring-boot-modules/spring-boot-mvc-birt/pom.xml index 274932f06c..cc4b7f8283 100644 --- a/spring-boot-modules/spring-boot-mvc-birt/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-birt/pom.xml @@ -10,10 +10,9 @@ Module For Spring Boot Integration with BIRT - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-mvc/pom.xml b/spring-boot-modules/spring-boot-mvc/pom.xml index 369bcf799b..a251c5049b 100644 --- a/spring-boot-modules/spring-boot-mvc/pom.xml +++ b/spring-boot-modules/spring-boot-mvc/pom.xml @@ -91,6 +91,10 @@ aspectjweaver ${aspectjweaver.version} + + org.projectlombok + lombok + diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/RestValidationApplication.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/RestValidationApplication.java new file mode 100644 index 0000000000..b335aecac2 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/RestValidationApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.restvalidation; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = { "com.baeldung.restvalidation" }) +public class RestValidationApplication { + + public static void main(String[] args) { + SpringApplication.run(RestValidationApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/MessageConfig.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/MessageConfig.java new file mode 100644 index 0000000000..e37e2c9d78 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/MessageConfig.java @@ -0,0 +1,38 @@ +package com.baeldung.restvalidation.config; + +import javax.validation.MessageInterpolator; + +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator; + +@Configuration +public class MessageConfig { + + @Bean + public MessageSource messageSource() { + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.setBasename("classpath:CustomValidationMessages"); + messageSource.setDefaultEncoding("UTF-8"); + return messageSource; + } + + @Bean + public MessageInterpolator getMessageInterpolator(MessageSource messageSource) { + MessageSourceResourceBundleLocator resourceBundleLocator = new MessageSourceResourceBundleLocator(messageSource); + ResourceBundleMessageInterpolator messageInterpolator = new ResourceBundleMessageInterpolator(resourceBundleLocator); + return new RecursiveLocaleContextMessageInterpolator(messageInterpolator); + } + + @Bean + public LocalValidatorFactoryBean getValidator(MessageInterpolator messageInterpolator) { + LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); + bean.setMessageInterpolator(messageInterpolator); + return bean; + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/RecursiveLocaleContextMessageInterpolator.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/RecursiveLocaleContextMessageInterpolator.java new file mode 100644 index 0000000000..003a3d79b0 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/config/RecursiveLocaleContextMessageInterpolator.java @@ -0,0 +1,36 @@ +package com.baeldung.restvalidation.config; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.validation.MessageInterpolator; + +import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator; +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; + +public class RecursiveLocaleContextMessageInterpolator extends AbstractMessageInterpolator { + + private static final Pattern PATTERN_PLACEHOLDER = Pattern.compile("\\{([^}]+)\\}"); + + private final MessageInterpolator interpolator; + + public RecursiveLocaleContextMessageInterpolator(ResourceBundleMessageInterpolator interpolator) { + this.interpolator = interpolator; + } + + @Override + public String interpolate(MessageInterpolator.Context context, Locale locale, String message) { + int level = 0; + while (containsPlaceholder(message) && (level++ < 2)) { + message = this.interpolator.interpolate(message, context, locale); + } + return message; + } + + private boolean containsPlaceholder(String code) { + Matcher matcher = PATTERN_PLACEHOLDER.matcher(code); + return matcher.find(); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/InputFieldError.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/InputFieldError.java new file mode 100644 index 0000000000..06bd764d97 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/InputFieldError.java @@ -0,0 +1,12 @@ +package com.baeldung.restvalidation.response; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class InputFieldError { + private String field; + private String message; + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/UpdateUserResponse.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/UpdateUserResponse.java new file mode 100644 index 0000000000..7eb400cd2c --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/response/UpdateUserResponse.java @@ -0,0 +1,17 @@ +package com.baeldung.restvalidation.response; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.List; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UpdateUserResponse { + + private List fieldErrors; + +} diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/User.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/User.java new file mode 100644 index 0000000000..f9a7d1a9b5 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/User.java @@ -0,0 +1,15 @@ +package com.baeldung.restvalidation.service1; + +import javax.validation.constraints.NotEmpty; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @NotEmpty + private String email; + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/UserService1.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/UserService1.java new file mode 100644 index 0000000000..790b5031e6 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service1/UserService1.java @@ -0,0 +1,36 @@ +package com.baeldung.restvalidation.service1; + +import org.springframework.http.*; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.Valid; + +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@RestController +public class UserService1 { + + @PutMapping(value = "/user1", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity updateUser(@RequestBody @Valid User user, + BindingResult bindingResult) { + if (bindingResult.hasFieldErrors()) { + + List fieldErrorList = bindingResult.getFieldErrors().stream() + .map(error -> new InputFieldError(error.getField(), error.getDefaultMessage())) + .collect(Collectors.toList()); + + UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse); + } + else { + // Update logic... + return ResponseEntity.status(HttpStatus.OK).build(); + } + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/User.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/User.java new file mode 100644 index 0000000000..a2e567766c --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/User.java @@ -0,0 +1,15 @@ +package com.baeldung.restvalidation.service2; + +import javax.validation.constraints.NotEmpty; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @NotEmpty(message = "{validation.email.notEmpty}") + private String email; + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/UserService2.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/UserService2.java new file mode 100644 index 0000000000..4593a2b1bd --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service2/UserService2.java @@ -0,0 +1,40 @@ +package com.baeldung.restvalidation.service2; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.Valid; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@RestController +public class UserService2 { + + @PutMapping(value = "/user2", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity updateUser(@RequestBody @Valid User user, + BindingResult bindingResult) { + if (bindingResult.hasFieldErrors()) { + + List fieldErrorList = bindingResult.getFieldErrors().stream() + .map(error -> new InputFieldError(error.getField(), error.getDefaultMessage())) + .collect(Collectors.toList()); + + UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse); + } + else { + // Update logic... + return ResponseEntity.status(HttpStatus.OK).build(); + } + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmpty.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmpty.java new file mode 100644 index 0000000000..93c7052d5b --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmpty.java @@ -0,0 +1,32 @@ +package com.baeldung.restvalidation.service3; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Documented +@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) +@Retention(RUNTIME) +@Constraint(validatedBy = { FieldNotEmptyValidator.class }) +public @interface FieldNotEmpty { + + String message() default "{validation.notEmpty}"; + + String field() default "Field"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmptyValidator.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmptyValidator.java new file mode 100644 index 0000000000..356efc590b --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/FieldNotEmptyValidator.java @@ -0,0 +1,16 @@ +package com.baeldung.restvalidation.service3; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class FieldNotEmptyValidator implements ConstraintValidator { + + private String message; + private String field; + + @Override + public boolean isValid(Object value, ConstraintValidatorContext context) { + return (value != null && !value.toString().trim().isEmpty()); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/User.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/User.java new file mode 100644 index 0000000000..97b38feba4 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/User.java @@ -0,0 +1,13 @@ +package com.baeldung.restvalidation.service3; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @FieldNotEmpty(message = "{validation.notEmpty}", field = "{field.personalEmail}") + private String email; + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/UserService3.java b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/UserService3.java new file mode 100644 index 0000000000..e506b63d8e --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/java/com/baeldung/restvalidation/service3/UserService3.java @@ -0,0 +1,40 @@ +package com.baeldung.restvalidation.service3; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.Valid; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@RestController +public class UserService3 { + + @PutMapping(value = "/user3", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity updateUser(@RequestBody @Valid User user, + BindingResult bindingResult) { + if (bindingResult.hasFieldErrors()) { + + List fieldErrorList = bindingResult.getFieldErrors().stream() + .map(error -> new InputFieldError(error.getField(), error.getDefaultMessage())) + .collect(Collectors.toList()); + + UpdateUserResponse updateResponse = new UpdateUserResponse(fieldErrorList); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(updateResponse); + } + else { + // Update logic... + return ResponseEntity.status(HttpStatus.OK).build(); + } + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages.properties b/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages.properties new file mode 100644 index 0000000000..58cabc30c9 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages.properties @@ -0,0 +1,3 @@ +field.personalEmail=Personal Email +validation.notEmpty={field} cannot be empty +validation.email.notEmpty=Email cannot be empty \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages_zh.properties b/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages_zh.properties new file mode 100644 index 0000000000..b4fbe909bb --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/resources/CustomValidationMessages_zh.properties @@ -0,0 +1,3 @@ +field.personalEmail=個人電郵 +validation.notEmpty={field}不能是空白 +validation.email.notEmpty=電郵不能留空 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages.properties b/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages.properties new file mode 100644 index 0000000000..90d3c88a8f --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages.properties @@ -0,0 +1 @@ +javax.validation.constraints.NotEmpty.message=The field cannot be empty \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages_zh.properties b/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages_zh.properties new file mode 100644 index 0000000000..04f415911c --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/main/resources/ValidationMessages_zh.properties @@ -0,0 +1 @@ +javax.validation.constraints.NotEmpty.message=本欄不能留空 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service1/UserService1IntegrationTest.java b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service1/UserService1IntegrationTest.java new file mode 100644 index 0000000000..969a6c17a6 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service1/UserService1IntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.restvalidation.service1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Objects; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.restvalidation.RestValidationApplication; +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class) +class UserService1IntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void whenUpdateValidEmail_thenReturnsOK() { + + // When + ResponseEntity responseEntity = updateUser(new User("test@email.com"), null); + + // Then + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), null); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("The field cannot be empty", error.getMessage()); + } + + @Test + void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), "zh-tw"); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("本欄不能留空", error.getMessage()); + } + + private ResponseEntity updateUser(User user, String language) { + + HttpHeaders headers = new HttpHeaders(); + if (Objects.nonNull(language)) { + headers.set(HttpHeaders.ACCEPT_LANGUAGE, language); + } + + return restTemplate.exchange( + "/user1", + HttpMethod.PUT, + new HttpEntity<>(user, headers), + UpdateUserResponse.class + ); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service2/UserService2IntegrationTest.java b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service2/UserService2IntegrationTest.java new file mode 100644 index 0000000000..3e92229d7b --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service2/UserService2IntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.restvalidation.service2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Objects; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.restvalidation.RestValidationApplication; +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class) +class UserService2IntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void whenUpdateValidEmail_thenReturnsOK() { + + // When + ResponseEntity responseEntity = updateUser(new User("test@email.com"), null); + + // Then + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), null); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("Email cannot be empty", error.getMessage()); + } + + @Test + void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), "zh-tw"); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("電郵不能留空", error.getMessage()); + } + + private ResponseEntity updateUser(User user, String language) { + + HttpHeaders headers = new HttpHeaders(); + if (Objects.nonNull(language)) { + headers.set(HttpHeaders.ACCEPT_LANGUAGE, language); + } + + return restTemplate.exchange( + "/user2", + HttpMethod.PUT, + new HttpEntity<>(user, headers), + UpdateUserResponse.class + ); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service3/UserService3IntegrationTest.java b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service3/UserService3IntegrationTest.java new file mode 100644 index 0000000000..8bc4d460ea --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc/src/test/java/com/baeldung/restvalidation/service3/UserService3IntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.restvalidation.service3; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Objects; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.restvalidation.RestValidationApplication; +import com.baeldung.restvalidation.response.InputFieldError; +import com.baeldung.restvalidation.response.UpdateUserResponse; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RestValidationApplication.class) +class UserService3IntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void whenUpdateValidEmail_thenReturnsOK() { + + // When + ResponseEntity responseEntity = updateUser(new User("test@email.com"), null); + + // Then + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + void whenUpdateEmptyEmail_thenReturnsErrorMessageInEnglish() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), null); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("Personal Email cannot be empty", error.getMessage()); + } + + @Test + void whenUpdateEmptyEmailWithLanguageHeaderEqualsToZh_thenReturnsErrorMessageInChinese() { + + // When + ResponseEntity responseEntity = updateUser(new User(""), "zh-tw"); + + // Then + InputFieldError error = responseEntity.getBody().getFieldErrors().get(0); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertEquals("個人電郵不能是空白", error.getMessage()); + } + + private ResponseEntity updateUser(User user, String language) { + + HttpHeaders headers = new HttpHeaders(); + if (Objects.nonNull(language)) { + headers.set(HttpHeaders.ACCEPT_LANGUAGE, language); + } + + return restTemplate.exchange( + "/user3", + HttpMethod.PUT, + new HttpEntity<>(user, headers), + UpdateUserResponse.class + ); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-performance/pom.xml b/spring-boot-modules/spring-boot-performance/pom.xml index 38f5758c1f..d63bb450b5 100644 --- a/spring-boot-modules/spring-boot-performance/pom.xml +++ b/spring-boot-modules/spring-boot-performance/pom.xml @@ -25,7 +25,7 @@ de.codecentric chaos-monkey-spring-boot - ${chaos.monkey.version} + ${chaos-monkey-spring-boot.version} @@ -48,7 +48,7 @@ com.baeldung.lazyinitialization.Application - 2.0.0 + 2.0.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-2/pom.xml b/spring-boot-modules/spring-boot-properties-2/pom.xml index 2c74f7f186..60ee9538c1 100644 --- a/spring-boot-modules/spring-boot-properties-2/pom.xml +++ b/spring-boot-modules/spring-boot-properties-2/pom.xml @@ -30,7 +30,7 @@ commons-lang commons-lang - 2.6 + ${commons-lang.version} diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java index 72c45afbb2..d7e948ca9a 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java +++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java @@ -1,6 +1,7 @@ package com.baeldung.configurationproperties; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.ConstructorBinding; @ConfigurationProperties(prefix = "mail.credentials") public class ImmutableCredentials { @@ -9,12 +10,19 @@ public class ImmutableCredentials { private final String username; private final String password; + @ConstructorBinding public ImmutableCredentials(String authMethod, String username, String password) { this.authMethod = authMethod; this.username = username; this.password = password; } + public ImmutableCredentials(String username, String password) { + this.username = username; + this.password = password; + this.authMethod = "Default"; + } + public String getAuthMethod() { return authMethod; } diff --git a/spring-boot-modules/spring-boot-react/pom.xml b/spring-boot-modules/spring-boot-react/pom.xml index dc0c6914c9..05ff6811c4 100644 --- a/spring-boot-modules/spring-boot-react/pom.xml +++ b/spring-boot-modules/spring-boot-react/pom.xml @@ -52,11 +52,128 @@ + + + default-jdk9-and-above + + + + com.github.eirslett + frontend-maven-plugin + + + install node + + install-node-and-yarn + + + true + ${node.version} + ${yarn.version} + + + + yarn install + + yarn + + none + + true + + + + yarn test + + yarn + + none + + test + + true + + + + + yarn build + + yarn + + compile + + true + + + + + + + + + integration-jdk9-and-above + + + + com.github.eirslett + frontend-maven-plugin + + + install node + + install-node-and-yarn + + + true + ${node.version} + ${yarn.version} + + + + yarn install + + yarn + + none + + true + + + + yarn test + + yarn + + none + + test + + true + + + + + yarn build + + yarn + + compile + + true + + + + + + + + + maven-resources-plugin - 3.1.0 + ${maven-resources-plugin.version} copy-resources @@ -135,6 +252,7 @@ 11 11 + 3.1.0 1.6 v14.18.0 v1.12.1 diff --git a/spring-boot-modules/spring-boot-redis/pom.xml b/spring-boot-modules/spring-boot-redis/pom.xml index e0ae5d388f..fa6b5a59c1 100644 --- a/spring-boot-modules/spring-boot-redis/pom.xml +++ b/spring-boot-modules/spring-boot-redis/pom.xml @@ -44,13 +44,13 @@ slf4j-simple - 0.7.3 + ${embedded-redis.version} test org.springframework spring-webflux - 6.0.3 + ${spring-webflux.version} test @@ -74,6 +74,8 @@ 15 + 6.0.3 + 0.7.3 diff --git a/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java b/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java index b4378a9248..a1173f40ae 100644 --- a/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java @@ -31,9 +31,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; +/** + * This was failing as a unit test in integrated environment + * probably due to parallel execution of tests. + */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -class ResilientAppControllerIntegrationTest { +class ResilientAppControllerManualTest { private final Logger LOGGER = LoggerFactory.getLogger(getClass()); diff --git a/spring-boot-modules/spring-boot-security-2/README.md b/spring-boot-modules/spring-boot-security-2/README.md new file mode 100644 index 0000000000..2774f60c43 --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Difference Between permitAll() and anonymous() in Spring Security](https://www.baeldung.com/spring-security-permitall-vs-anonymous) diff --git a/spring-boot-modules/spring-boot-security-2/pom.xml b/spring-boot-modules/spring-boot-security-2/pom.xml new file mode 100644 index 0000000000..db094f33a6 --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + spring-boot-security-2 + spring-boot-security-1 + jar + Spring Boot Security Auto-Configuration + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.springframework.boot + spring-boot-autoconfigure + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java new file mode 100644 index 0000000000..150fe399d1 --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.permitallanonymous; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan("com.baeldung.permitallanonymous.*") +public class SecuredEcommerceApplication { + public static void main(String[] args) { + SpringApplication.run(SecuredEcommerceApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java new file mode 100644 index 0000000000..d76075016a --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java @@ -0,0 +1,29 @@ +package com.baeldung.permitallanonymous.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class EcommerceController { + + //can be accessed by only logged-in users + @GetMapping("/private/showCart") + public @ResponseBody String showCart() { + return "Show Cart"; + } + + //can be accessed by both anonymous and authenticated users + @GetMapping("/public/showProducts") + public @ResponseBody String listProducts() { + return "List Products"; + } + + //can be access by only anonymous users not by authenticated users + @GetMapping("/public/registerUser") + public @ResponseBody String registerUser() { + return "Register User"; + } + +} + diff --git a/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java new file mode 100644 index 0000000000..c0a5f6972f --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java @@ -0,0 +1,33 @@ +package com.baeldung.permitallanonymous.filter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class AuditInterceptor extends OncePerRequestFilter { + private final Logger logger = LoggerFactory.getLogger(AuditInterceptor.class); + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication instanceof AnonymousAuthenticationToken) { + logger.info("Audit anonymous user"); + } + if (authentication instanceof UsernamePasswordAuthenticationToken) { + logger.info("Audit registered user"); + } + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java new file mode 100644 index 0000000000..566ec49e42 --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java @@ -0,0 +1,46 @@ +package com.baeldung.permitallanonymous.security; + +import com.baeldung.permitallanonymous.filter.AuditInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +@Configuration +@EnableWebSecurity +public class EcommerceWebSecurityConfig { + @Bean + public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { + UserDetails user = User.withUsername("spring") + .password(passwordEncoder.encode("secret")) + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.addFilterAfter(new AuditInterceptor(), AnonymousAuthenticationFilter.class) + .authorizeRequests() + .antMatchers("/private/**").authenticated().and().httpBasic() + .and().authorizeRequests() + .antMatchers("/public/showProducts").permitAll() + .antMatchers("/public/registerUser").anonymous(); + + return http.build(); + } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security-2/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java b/spring-boot-modules/spring-boot-security-2/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java new file mode 100644 index 0000000000..3c73caf1fd --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.permitallanonymous; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SecuredEcommerceApplication.class) +@AutoConfigureMockMvc +public class SecureEcommerceApplicationUnitTest { + @Autowired + private MockMvc mockMvc; + private static final Logger logger = LoggerFactory.getLogger(SecureEcommerceApplicationUnitTest.class); + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToUserRegisterPage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/registerUser")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Register User")); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToUserRegisterPage_thenDenyAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/registerUser")) + .andExpect(MockMvcResultMatchers.status().isForbidden()); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToProductLinePage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/showProducts")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("List Products")); + } + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToProductLinePage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/showProducts")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("List Products")); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToCartPage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/private/showCart")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Show Cart")); + } + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToCartPage_thenDenyAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/private/showCart")) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } +} diff --git a/spring-boot-modules/spring-boot-security/README.md b/spring-boot-modules/spring-boot-security/README.md index d848f798ba..64a7a69e3a 100644 --- a/spring-boot-modules/spring-boot-security/README.md +++ b/spring-boot-modules/spring-boot-security/README.md @@ -12,7 +12,6 @@ This module contains articles about Spring Boot Security - [Spring @EnableWebSecurity vs. @EnableGlobalMethodSecurity](https://www.baeldung.com/spring-enablewebsecurity-vs-enableglobalmethodsecurity) - [Spring Security – Configuring Different URLs](https://www.baeldung.com/spring-security-configuring-urls) - ### Spring Boot Security Auto-Configuration - mvn clean install diff --git a/spring-boot-modules/spring-boot-springdoc-2/pom.xml b/spring-boot-modules/spring-boot-springdoc-2/pom.xml index 1ea52667c5..dace3d17ef 100644 --- a/spring-boot-modules/spring-boot-springdoc-2/pom.xml +++ b/spring-boot-modules/spring-boot-springdoc-2/pom.xml @@ -112,7 +112,7 @@ - 2.1.0 + 2.2.0 1.4 diff --git a/spring-boot-modules/spring-boot-ssl-bundles/README.md b/spring-boot-modules/spring-boot-ssl-bundles/README.md new file mode 100644 index 0000000000..840cc21583 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Securing Spring Boot 3 Applications With SSL Bundles](https://www.baeldung.com/spring-boot-security-ssl-bundles) diff --git a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml new file mode 100644 index 0000000000..4802e9ec58 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + springbootsslbundles + spring-boot-ssl-bundles + jar + Module for showing usage of SSL Bundles + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.apache.httpcomponents.client5 + httpclient5-fluent + ${apache.client5.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 5.0.3 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SSLBundlesApp.java b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SSLBundlesApp.java new file mode 100644 index 0000000000..f6cfb35d1e --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SSLBundlesApp.java @@ -0,0 +1,19 @@ +package com.baeldung.springbootsslbundles; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.boot.ssl.SslBundles; + +@SpringBootApplication +public class SSLBundlesApp { + public static void main(String[] args) { + SpringApplication.run(SSLBundlesApp.class, args); + } + @Bean + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) { + return restTemplateBuilder.setSslBundle(sslBundles.getBundle("secure-service")).build(); + } +} diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureRestTemplateConfig.java b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureRestTemplateConfig.java new file mode 100644 index 0000000000..48eda219dd --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureRestTemplateConfig.java @@ -0,0 +1,38 @@ +package com.baeldung.springbootsslbundles; + +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ssl.NoSuchSslBundleException; +import org.springframework.boot.ssl.SslBundle; +import org.springframework.boot.ssl.SslBundles; +import org.springframework.context.annotation.Bean; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.SSLContext; + +@Component +public class SecureRestTemplateConfig { + private final SSLContext sslContext; + + @Autowired + public SecureRestTemplateConfig(SslBundles sslBundles) throws NoSuchSslBundleException { + SslBundle sslBundle = sslBundles.getBundle("secure-service"); + this.sslContext = sslBundle.createSslContext(); + } + + @Bean + public RestTemplate secureRestTemplate() { + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create().setSslContext(this.sslContext).build(); + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(sslSocketFactory).build(); + HttpClient httpClient = HttpClients.custom().setConnectionManager(cm).evictExpiredConnections().build(); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + return new RestTemplate(factory); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureServiceRestApi.java b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureServiceRestApi.java new file mode 100644 index 0000000000..3ed919b957 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/java/com/baeldung/springbootsslbundles/SecureServiceRestApi.java @@ -0,0 +1,28 @@ +package com.baeldung.springbootsslbundles; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class SecureServiceRestApi { + private final RestTemplate restTemplate; + + @Autowired + public SecureServiceRestApi(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public String fetchData(String dataId) { + ResponseEntity response = restTemplate.exchange( + "https://secure-service.com/api/data/{id}", + HttpMethod.GET, + null, + String.class, + dataId + ); + return response.getBody(); + } +} diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/application.yml b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/application.yml new file mode 100644 index 0000000000..1598645805 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/application.yml @@ -0,0 +1,11 @@ +spring: + ssl: + bundle: + jks: + secure-service: + key: + alias: "secure-service" + keystore: + location: "classpath:keystore.p12" + password: "FooBar" + type: "PKCS12" \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/cert.pem b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/cert.pem new file mode 100644 index 0000000000..82ed122a80 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUCJcVMwyhLy/ln+ENMXbSWcsO0aswDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzA5MDUxNjAyMzdaFw0yNDA5 +MDQxNjAyMzdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDMNn+ZmPfR4FUyG6PVGBB2rOAnIHqFqYMVyDUOtZja +9CxpgbQjHRwwWaUWcYzLPOsvN/tMC8BazAFHSI2KIeNKgjAesv9JTumqgFXdOmw8 +KT7a9C1IQXnCMhlbp9J7c7CLvjAvZvZBghxFLc7xBZo9rWA67QMZoOhXvdMoKv4G +5v9qD1ZqIKlCxJQrdErVUKyZPztlIWNqzPy9BJzFlBea2ArfrASulqJuWGyO09+o +6ABNgUAicp/zfCOeKIe9cni0oZj6Buwk4eVdYESzVohBO52h95KtN17Y/Tw+U8W5 +Szq9tit6Vkupbe8tih7Bkdnj22WeCLVwWdXCp1kJw2kFDJTiC3wQRa6P0OrVpPGx +Z5SmG9eSCz22alA+I521ZG85hmPDt3BleYRYlCtcW7GFT/7zLBEwlN93lY5Os1jj +PRS8o5eIg8UhTbU4QEaZRYcLzaFy0asfKfa4ZF3mH5whh/w07SEEBAKDfQPpiz3T +migd+r9qUnPWeoE8Hi7lA1KzUd4YeM2yNHqXoQiARjHkM4yrX6vVlfT+itVbrpqF +a5J7PjL26w+DsxvRt9Ad5gpOdDzuy5m2V6lphMDjeZoG4OXgBzQQ1YxK1r6wkI4U +ZwRNrb+BxmQebQHnXKEXI7jgS45uoFENwolIHm9Dou5VYGLI0z+/pDReugCcw2lO +/QIDAQABo1MwUTAdBgNVHQ4EFgQUlSkON/OM9HCXeaQ7VWQuiEwY2iAwHwYDVR0j +BBgwFoAUlSkON/OM9HCXeaQ7VWQuiEwY2iAwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAD+8sPSQR3+A4F9z704OOy1Mo6bvbnIuK9UdN7d4/zh+e +AoloyTFPLPZIldg9hXwCvrKjrfqS5YUKmXIp9tetX7ns13CeDFcqVwZfPnqjzdNN +ad255LEwMjIUm9hSNEV6AQBKW8E+a590SrUamEdkFm4fcUB1LaINwyJjls7C0VB2 +JL50OloaUlv0IMnAPRVp0Adlt9xs69R2B8Q4i297FvHB1PI7VMLYqNnX2+tnvszO +HvWtIqm6foyReDLfC0n87cuEBV7/9304V5vgEj20TR19isd0LffJDD1ujDXvN8dS +uGOB1VLRxAPonr9Iqk358EJ1T22uEcMdKE+sMnCBjw2fYIYRfjhGN+m6U6sb4MrF +zFUI6qB7W7T/5iukiRb4pLQ0OGgKOwYxpZoxcB3Ldjo5x58uKNOTNJ5zEJ8HUofA +BNfty10D3m3DlSyYbf7m1UUM0jj2l83LBGQzhGGUZgCnCsMczLrj64Gvf2iLGmCF +gu5zrxL01dptBkvTsYJwYBA67BBS4FcgYNMGx3m1uPsVUUIguJxufXWYfbub74QV +a1SH1NjO8HR3DLDU+S92tyTKWOUzJ5qOegEsR2cutVRzDuVTsFy7kayuNv/uLRrG +3P2HnUo8PG/nmysReBk6CGycUiDTt55DoPYGoQ5l19xTlkIt7ulNg7yX5pwFMeE= +-----END CERTIFICATE----- diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/key.pem b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/key.pem new file mode 100644 index 0000000000..b4202e9a8e --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/key.pem @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIJpDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIblni8xi+83QCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECJSRFMcxzIKiBIIJUEqyZcVQEBL1 +6jkeo5TGxVwolLnCNpEuj8UwLoK5Z2N5oVwSPzD5rMYuPg6OXXWk6zReaaKBkRR2 +vlpkckA4o+aSXfzvEXYGd+rZ3EeIK43zquIBjymlcN++FbEYOtAY1SoQm7FtyvdN +4QW7MOONUJcnN3EgRSRic2CCa0k6NSREfrBWaa+OcYB4C/JEuA2xgkCUw8bCcos6 +mksoF6mZDQearirNankMDR7gLQt9pdK7S55T4sCrFpL072s3k7lV0WtvTE/CQ8Wu +pdBKVPvpvkR1S9n3ajGMWVYBjkRuD0MMn1eGMW6t3mRI8+C15zTp9DjzySJTMzUm +C3l/m9VQBFewuHLziJFylqy7kgxrUUe39FShHYkJZDprZSYE33Lz67o8oHpLkkIh +YccDm2bgqIbKfslbAIXD4BKq0QOUbi681XGRslZ7ZGduwNm3Xly0yuKmstzhnqQu +TLkBWcNeauYA7eeTTwAQq5My/xt+Ls72AwjOjP3kGSNCvmrLBP+4zpJayr+l+OYl +r5G6YNGE3p3QVY/Wn05OWeRE6eVqp1BXvgeLdqNyQXNpPITas0LDeVncexTNilNc +R788Le77m6grpxaX4xKbMKf1dtsRtPf+LvVNAdfVj9lQcEvi3ub0yjKGUhtRuxKi +STvVyJkJM7mV3FsUsYwsJZ2rBXbB2ifz6RCa8BDDwLGqZ54AZcK7OyvS6yRXf2ip +jZ2N09OIoN3WaTXytueqEPmiZ+M8Sirt9YLzNa74BrWsqyazUYMtib1exhp6EVPH +EVh+SlTdwQ//tPZNBx8TCB1s+bOHyzplXZ8JVg+AiuvZtyP20jS6oil2qvOcLR94 +e1hQaIPy6QXFFOTcDnmcTmUnaJKBvPFfqSVg58OeMb3RyQkZWvTkoxiE6PZwh3d1 +hqVzb+l91GDiLbYndGE1QrqBmxbGzM7PKqUr91cWBU8723CqGciWK+bjk4CxWx/F +yHX6nDwDgfuhPe90r7Xrjj9/61/xoaWhg25BZVOgn/e1akDK+8qjHxDhc/anE7xS +DIefhiukPuj/7oaxRIe/pKndztVub3W9EbyvHJArU+H6Ixy4qaulCXymp7Hqo/07 +4dUCVz2AGAIWqC0X6jUO8j2iHuOgbQg/oZFYOl8zn4q1ic1pFp/MJWaaWG9rAXPt +miT34Rv8lvJW9nqKAGuW8uRJ6xqyw8DcpmOMjFamPOZ8H66aOOsVJwTFmg3YlUAh +Cy3ITprdDbLPuX8MLJB7hJxKrqpXpnaY68x1MXAfp3tPkQ41u3Eif8riVY33+XEJ +9OZN8Xwnv+spej8CGmjiNP7WhvyjLJnzsTycXR3BE1TL9IzrKoebdiE1pVUv5tcL +lFCl5eatcxuU03JFQt+DjhcMBuM2AT2dfZ4WyHm2kKbOVTQA5snSFwpLt1ZS2G64 +7XCvx+zLbloqzRZkcKCr7hXgmpWLOECp2Wk98E2iHOHVkMINE5kB+iIXsg2Ii8pN +8UwIDF4VHF/c3hTESFrY3tVIYGauB9hqcBU4NDcZNRuRd6MSx9NZe55xzJ7uR4oV +Et0yNkmluk/EySpMrwLhe6t5I8vQEP9Ug00yobUuRob6rSp2pjkmRm2aPu4q042B +JFqGGwZWTXoa7+THIua9xWQh4Bmz7UZ6oO9rBll5pmoNO8SzaJwF1ZzE9RL2iFQW +px9u+85ee9+a6aQhvZjX0C/XYt0oHeoWpeoLTb97nGlZEv1GouHkjgNKLmcgz0Kd +WugrakcxJolplqfQmPaoPWGMT3ukXauyvSOFrG7eJKrzQSrv2GSqKsvHLgqvtqeL +cDjwESbSHRdGBvEz/L/XJfIba6jOI76GtbWFi9Co872V7SkNWHqOdwcEbb06phxH +1u+ZUy0caU8rLe9exLg1/VLkEDHPy4aSOkkcCkptWG/UwjGOa5HOMPzWDsayDeDT +7bFZlgl11ZZGoRAW+GZkHUCRglLqxKA1lSyK7Pv7cVXe6wniPbfMnyjZQZnRIk+q +UFr7hc2Buw1nISmRF6vx1jdwfA5A/ECNCCCHZ+XQhOO3xcKZeG6FGjr11oHK0H1g +aJve3tkrSYC4nXZfE7Lij5Cx+S1wTfZ8G+fGlSQa2jdsJUfRBy/TXkIorApbzFc1 +P1x05HXzSnMhLUWFYRqLWSVdBQua0w/CYyKEOPZUaFCRa67u1NLH0plA/j7h39ZA +1uTceFbjYQHTAObsNu5z/zaHd+xTc3WN9NFuXQKGxFdgs+duEZk1XZnD3V3DIlbJ +YobwhOiVLelUzBQZBYKEo2LJ71E0oOjIiq0TiCy5YsB9UGl9Un3jn50cKrq7IldF +MQLBl+ixbOLQ0KbVs7K1P7AegQwfgdmvG4jdjFx5Myq77GHgCgmtvngCYJjrF1Vo +OLxrKjk7dZ+Hmy60zPjgYkHyvOdZRUKfIhZrpCM5Al/xKUqhR6rPtr2U7lkHw9zT +gsK6rxXfvmJjIzSFBQzBah8K9rYzk/DScXMQ+3XY7fu6r2LTnfWxCKYhX/2eEoXW +/+t0HsRNoGCLB9g8sDAt2tDbjOsGRIdtfQ28Q56Pi91+IlGE5/n4iJ/bws5F1MXB +amG44iYYNPHUnkr3YsQeCiyh/1GgiLbIi3P6ZVJ5vG1a5oPGNolsABMZ5HZzd/aD +LgZDFjIMDzL5WaP2xhfnTjQsaowpulLE0/7mrc5KnfKxwdlDmLGjLIRsa5fXbL6W +rqezhAkgRrGRhnljMnCgZGpkHMtZN3S0u78/u17FvtlbyDFOev1y9cpvMmp/RAP3 +OXp7Wo3JELz/7aMkmVt6a++j9hxuX0vas6PPCoM0PGlTdWxPo2y96fFuW41j59vh +XY54kI5sBFibuvxLJOr9lXw8EuXJTNiyKuoEoXu2QKNHYSOZi1OPzrJRsKxEwNBh +8TP1G99H/gdlYEI/CPYOGbhWMq1qZyukDHjQaOMdzRIRYawx4GbQE1HeGla5bFSy +n0Gki5ApqQk8b6muUxDXBgPdQKFL6o7KYhAg+8JsGvnByh7qVZl2kmwxjx2bJIcj +o7BBRSYLSWdW3cguXojtgoN2NcFZZON4IEDSBuu/1ESgi2a2W5T9NClK/3ZagPmJ +hX2T2qTTkVjWQ+xM15SD46s4s+5nZX2kGE1DHwtYSKgdHYR9n81po7CuEqVP1n/G +7NNrMLXj3PGrZ2vzKDGSAU1LzLOUrJ4m +-----END ENCRYPTED PRIVATE KEY----- diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/keystore.p12 b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/keystore.p12 new file mode 100644 index 0000000000..f58b355467 Binary files /dev/null and b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/keystore.p12 differ diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/static/index.html b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/static/index.html new file mode 100644 index 0000000000..117910cc89 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/main/resources/static/index.html @@ -0,0 +1,13 @@ + + + + + Spring SSL Bundler Demo Application + + +

Spring SSL Bundler Demo Application

+

+ This is a sample application that can be built as native executable. +

+ + diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java new file mode 100644 index 0000000000..6c9a2fb3f0 --- /dev/null +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java @@ -0,0 +1,12 @@ +package com.baeldung.springbootsslbundles; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringContextTest { + @Test + void contextLoads() { + + } +} diff --git a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java index 5c24368ce6..9a1bf547db 100644 --- a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java +++ b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java @@ -3,10 +3,11 @@ package com.baeldung.swaggerkeycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; @@ -24,16 +25,19 @@ public class GlobalSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .requestMatchers(HttpMethod.OPTIONS) + + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests((requests) -> requests.requestMatchers(HttpMethod.OPTIONS) .permitAll() .requestMatchers("/api/**") .authenticated() .anyRequest() - .permitAll(); - http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + .permitAll()); + + http.oauth2ResourceServer((oauth2) -> oauth2 + .jwt(Customizer.withDefaults()) + ); + return http.build(); } diff --git a/spring-boot-modules/spring-boot-swagger-springfox/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java b/spring-boot-modules/spring-boot-swagger-springfox/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java index 79c35e025e..bffe0659a6 100644 --- a/spring-boot-modules/spring-boot-swagger-springfox/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java +++ b/spring-boot-modules/spring-boot-swagger-springfox/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java @@ -8,6 +8,6 @@ public class SwaggerController { @RequestMapping("/myproject") public String getRedirectUrl() { - return "redirect:swagger-ui.html"; + return "redirect:swagger-ui/"; } } \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-telegram/.gitignore b/spring-boot-modules/spring-boot-telegram/.gitignore new file mode 100644 index 0000000000..a8e6c9dbce --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/.gitignore @@ -0,0 +1,35 @@ +HELP.md +target/ +.mvn +mvnw +mvnw.cmd +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/spring-boot-modules/spring-boot-telegram/README.md b/spring-boot-modules/spring-boot-telegram/README.md new file mode 100644 index 0000000000..4cd6560bc0 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Creating a Telegram Bot with Spring Boot](https://www.baeldung.com/spring-boot-telegram-bot) diff --git a/spring-boot-modules/spring-boot-telegram/pom.xml b/spring-boot-modules/spring-boot-telegram/pom.xml new file mode 100644 index 0000000000..67fdf197f8 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + com.baelding + spring-boot-telegram + 0.0.1-SNAPSHOT + spring-boot-telegram + Demo project for Spring Boot with Spring Data Redis + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.telegram + telegrambots-spring-boot-starter + ${telegrambots.version} + + + org.telegram + telegrambots-abilities + ${telegrambots.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 17 + 6.7.0 + + + diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java new file mode 100644 index 0000000000..5c529bf15c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java @@ -0,0 +1,9 @@ +package com.baeldung.telegram; + +public class Constants { + + public static final String START_DESCRIPTION = "Starts the bot"; + + public static final String CHAT_STATES = "chatStates"; + public static final String START_TEXT = "Welcome to Baeldung Pizza Bot.\nPlease enter your name"; +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java new file mode 100644 index 0000000000..367c5a4c7c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java @@ -0,0 +1,30 @@ +package com.baeldung.telegram; + +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow; + +import java.util.List; + +public class KeyboardFactory { +public static ReplyKeyboard getPizzaToppingsKeyboard() { + KeyboardRow row = new KeyboardRow(); + row.add("Margherita"); + row.add("Pepperoni"); + return new ReplyKeyboardMarkup(List.of(row)); +} + + public static ReplyKeyboard getPizzaOrDrinkKeyboard(){ + KeyboardRow row = new KeyboardRow(); + row.add("Pizza"); + row.add("Drink"); + return new ReplyKeyboardMarkup(List.of(row)); + } + + public static ReplyKeyboard getYesOrNo() { + KeyboardRow row = new KeyboardRow(); + row.add("Yes"); + row.add("No"); + return new ReplyKeyboardMarkup(List.of(row)); + } +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java new file mode 100644 index 0000000000..802cb586d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java @@ -0,0 +1,48 @@ +package com.baeldung.telegram; + +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.abilitybots.api.bot.BaseAbilityBot; +import org.telegram.abilitybots.api.objects.Ability; +import org.telegram.abilitybots.api.objects.Flag; +import org.telegram.abilitybots.api.objects.Reply; +import org.telegram.telegrambots.meta.api.objects.Update; + +import java.util.function.BiConsumer; + +import static org.telegram.abilitybots.api.objects.Locality.USER; +import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC; +import static org.telegram.abilitybots.api.util.AbilityUtils.getChatId; + +@Component +public class PizzaBot extends AbilityBot { + + private final ResponseHandler responseHandler; + + public PizzaBot(Environment environment) { + super(environment.getProperty("BOT_TOKEN"), "baeldungbot"); + responseHandler = new ResponseHandler(silent, db); + } + +public Ability startBot() { + return Ability + .builder() + .name("start") + .info(Constants.START_DESCRIPTION) + .locality(USER) + .privacy(PUBLIC) + .action(ctx -> responseHandler.replyToStart(ctx.chatId())) + .build(); +} + +public Reply replyToButtons() { + BiConsumer action = (abilityBot, upd) -> responseHandler.replyToButtons(getChatId(upd), upd.getMessage()); + return Reply.of(action, Flag.TEXT,upd -> responseHandler.userIsActive(getChatId(upd))); +} + +@Override +public long creatorId() { + return 1L; +} +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java new file mode 100644 index 0000000000..862edc962c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java @@ -0,0 +1,132 @@ +package com.baeldung.telegram; + +import org.telegram.abilitybots.api.db.DBContext; +import org.telegram.abilitybots.api.sender.SilentSender; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardRemove; + +import java.util.Map; + +import static com.baeldung.telegram.Constants.START_TEXT; +import static com.baeldung.telegram.UserState.*; + +public class ResponseHandler { + private final SilentSender sender; + private final Map chatStates; + + public ResponseHandler(SilentSender sender, DBContext db) { + this.sender = sender; + chatStates = db.getMap(Constants.CHAT_STATES); + } + + public void replyToStart(long chatId) { + SendMessage message = new SendMessage(); + message.setChatId(chatId); + message.setText(START_TEXT); + sender.execute(message); + chatStates.put(chatId, AWAITING_NAME); + } + +public void replyToButtons(long chatId, Message message) { + if (message.getText().equalsIgnoreCase("/stop")) { + stopChat(chatId); + } + + switch (chatStates.get(chatId)) { + case AWAITING_NAME -> replyToName(chatId, message); + case FOOD_DRINK_SELECTION -> replyToFoodDrinkSelection(chatId, message); + case PIZZA_TOPPINGS -> replyToPizzaToppings(chatId, message); + case AWAITING_CONFIRMATION -> replyToOrder(chatId, message); + default -> unexpectedMessage(chatId); + } +} + + private void unexpectedMessage(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("I did not expect that."); + sender.execute(sendMessage); + } + +private void stopChat(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("Thank you for your order. See you soon!\nPress /start to order again"); + chatStates.remove(chatId); + sendMessage.setReplyMarkup(new ReplyKeyboardRemove(true)); + sender.execute(sendMessage); +} + + private void replyToOrder(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("yes".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We will deliver it soon. Thank you!\nOrder another?"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, FOOD_DRINK_SELECTION); + } else if ("no".equalsIgnoreCase(message.getText())) { + stopChat(chatId); + } else { + sendMessage.setText("Please select yes or no"); + sendMessage.setReplyMarkup(KeyboardFactory.getYesOrNo()); + sender.execute(sendMessage); + } + } + + private void replyToPizzaToppings(long chatId, Message message) { + if ("margherita".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "You selected Margherita Pizza.\nWe will deliver it soon. Thank you!\nOrder again?", + KeyboardFactory.getYesOrNo(), AWAITING_CONFIRMATION); + } else if ("pepperoni".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "We finished the Pepperoni Pizza.\nSelect another Topping", + KeyboardFactory.getPizzaToppingsKeyboard(), PIZZA_TOPPINGS); + } else { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("We don't sell " + message.getText() + " Pizza.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + } + } + + private void promptWithKeyboardForState(long chatId, String text, ReplyKeyboard YesOrNo, UserState awaitingReorder) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText(text); + sendMessage.setReplyMarkup(YesOrNo); + sender.execute(sendMessage); + chatStates.put(chatId, awaitingReorder); + } + +private void replyToFoodDrinkSelection(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("drink".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We don't sell drinks.\nBring your own drink!! :)"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } else if ("pizza".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We love Pizza in here.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, UserState.PIZZA_TOPPINGS); + } else { + sendMessage.setText("We don't sell " + message.getText() + ". Please select from the options below."); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } +} + +private void replyToName(long chatId, Message message) { + promptWithKeyboardForState(chatId, "Hello " + message.getText() + ". What would you like to have?", + KeyboardFactory.getPizzaOrDrinkKeyboard(), + UserState.FOOD_DRINK_SELECTION); +} + + public boolean userIsActive(Long chatId) { + return chatStates.containsKey(chatId); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java new file mode 100644 index 0000000000..041478f42b --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.telegram; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.telegrambots.meta.TelegramBotsApi; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; + +@SpringBootApplication +public class SpringBootTelegramApplication { + + public static void main(String[] args) { + ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootTelegramApplication.class, args); + try { + TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class); + botsApi.registerBot(ctx.getBean("pizzaBot", AbilityBot.class)); + } catch (TelegramApiException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java new file mode 100644 index 0000000000..a0b53a6a02 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java @@ -0,0 +1,5 @@ +package com.baeldung.telegram; + +public enum UserState { + AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties new file mode 100644 index 0000000000..6b2753c3a8 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties @@ -0,0 +1,2 @@ +server.port=8081 +BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-2/README.md b/spring-boot-modules/spring-boot-testing-2/README.md index e6bc4c4590..1baf83bf34 100644 --- a/spring-boot-modules/spring-boot-testing-2/README.md +++ b/spring-boot-modules/spring-boot-testing-2/README.md @@ -13,4 +13,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring Web Service Integration Tests with @WebServiceServerTest](https://www.baeldung.com/spring-webserviceservertest) - [Spring Boot – Testing Redis With Testcontainers](https://www.baeldung.com/spring-boot-redis-testcontainers) - [Spring Boot – Keycloak Integration Testing with Testcontainers](https://www.baeldung.com/spring-boot-keycloak-integration-testing) +- [Difference Between @Spy and @SpyBean](https://www.baeldung.com/spring-spy-vs-spybean) - More articles: [[<-- prev]](../spring-boot-testing) diff --git a/spring-boot-modules/spring-boot-testing-2/pom.xml b/spring-boot-modules/spring-boot-testing-2/pom.xml index be8beaf700..f684d7ce97 100644 --- a/spring-boot-modules/spring-boot-testing-2/pom.xml +++ b/spring-boot-modules/spring-boot-testing-2/pom.xml @@ -43,7 +43,7 @@ org.springframework.ws spring-ws-test - 3.1.3 + ${spring-ws-test.version} test @@ -75,7 +75,7 @@ com.redis.testcontainers testcontainers-redis-junit-jupiter - 1.4.6 + ${testcontainers-redis-junit-jupiter.version} test @@ -85,7 +85,7 @@ org.jvnet.jaxb2.maven2 maven-jaxb2-plugin - 0.15.1 + ${maven-jaxb2-plugin.version} xjc @@ -107,8 +107,11 @@ com.baeldung.boot.Application + 3.1.3 1.17.2 1.10.0 + 1.4.6 + 0.15.1 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java new file mode 100644 index 0000000000..fd321a0e68 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java @@ -0,0 +1,6 @@ +package com.baeldung.spytest; + +public interface ExternalAlertService { + public boolean alert(Order order); + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java new file mode 100644 index 0000000000..f0b2f92bee --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java @@ -0,0 +1,18 @@ +package com.baeldung.spytest; + +import org.springframework.stereotype.Component; + +@Component +public class NotificationService { + + private ExternalAlertService externalAlertService; + + public void notify(Order order) { + System.out.println(order); + } + + public boolean raiseAlert(Order order) { + return externalAlertService.alert(order); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java new file mode 100644 index 0000000000..23f5a05e9d --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java @@ -0,0 +1,49 @@ +package com.baeldung.spytest; + +import java.util.UUID; + +public class Order { + + private UUID id; + + private String name; + + private OrderType orderType; + + private double orderQuantity; + + private String address; + + public Order(UUID id, String name, double orderQuantity, String address) { + this.id = id; + this.name = name; + this.orderQuantity = orderQuantity; + this.address = address; + } + + public enum OrderType { + INDIVIDUAL, BULK; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public double getOrderQuantity() { + return orderQuantity; + } + + public String getAddress() { + return address; + } +} + + diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java new file mode 100644 index 0000000000..90fe5ba2b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.spytest; + +import java.util.HashMap; +import java.util.UUID; + +import org.springframework.stereotype.Component; + +@Component +public class OrderRepository { + + public static final HashMap orders = new HashMap<>(); + + public Order save(Order order) { + UUID orderId = UUID.randomUUID(); + order.setId(orderId); + orders.put(UUID.randomUUID(), order); + return order; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java new file mode 100644 index 0000000000..47647b8721 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java @@ -0,0 +1,25 @@ +package com.baeldung.spytest; + +import org.springframework.stereotype.Service; + +@Service +public class OrderService { + + public final OrderRepository orderRepository; + + public final NotificationService notificationService; + + public OrderService(OrderRepository orderRepository, NotificationService notificationService) { + this.orderRepository = orderRepository; + this.notificationService = notificationService; + } + + public Order save(Order order) { + order = orderRepository.save(order); + notificationService.notify(order); + if (!notificationService.raiseAlert(order)) { + throw new RuntimeException("Alert not raised"); + } + return order; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java new file mode 100644 index 0000000000..d8d81378df --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spytest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpyTestApplication { + + public static void main(String[] args) { + SpringApplication.run(SpyTestApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java new file mode 100644 index 0000000000..96c7b09dfc --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java @@ -0,0 +1,35 @@ +package com.baeldung.spytest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; + +@SpringBootTest +class OrderServiceIntegrationTest { + + @Autowired + OrderRepository orderRepository; + @SpyBean + NotificationService notificationService; + @SpyBean + OrderService orderService; + + @Test + void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() { + + Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); + doReturn(true).when(notificationService) + .raiseAlert(any(Order.class)); + Order order = orderService.save(orderInput); + Assertions.assertNotNull(order); + Assertions.assertNotNull(order.getId()); + verify(notificationService).notify(any(Order.class)); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java new file mode 100644 index 0000000000..21ae849bcf --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java @@ -0,0 +1,41 @@ +package com.baeldung.spytest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class OrderServiceUnitTest { + + @Spy + OrderRepository orderRepository; + @Spy + NotificationService notificationService; + @InjectMocks + OrderService orderService; + + @Test + void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() { + + UUID orderId = UUID.randomUUID(); + Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); + doReturn(orderInput).when(orderRepository) + .save(any()); + doReturn(true).when(notificationService) + .raiseAlert(any(Order.class)); + Order order = orderService.save(orderInput); + Assertions.assertNotNull(order); + Assertions.assertEquals(orderId, order.getId()); + verify(notificationService).notify(any(Order.class)); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-spock/pom.xml b/spring-boot-modules/spring-boot-testing-spock/pom.xml index c82d88ccfb..db78143cb8 100644 --- a/spring-boot-modules/spring-boot-testing-spock/pom.xml +++ b/spring-boot-modules/spring-boot-testing-spock/pom.xml @@ -96,7 +96,6 @@ com.baeldung.boot.Application 2.4-M1-groovy-4.0 3.0.0 - 3.10.1 2.17.1
diff --git a/spring-boot-modules/spring-boot-testing/pom.xml b/spring-boot-modules/spring-boot-testing/pom.xml index 2098ac767d..257260fc3f 100644 --- a/spring-boot-modules/spring-boot-testing/pom.xml +++ b/spring-boot-modules/spring-boot-testing/pom.xml @@ -64,7 +64,7 @@ it.ozimov embedded-redis - ${redis.version} + ${embedded-redis.version} test @@ -121,8 +121,7 @@ 2.2.4 2.4-M1-groovy-4.0 3.0.0 - 3.10.1 - 0.7.2 + 0.7.2 2.5.0 2.17.1 diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java deleted file mode 100644 index e3877f09b0..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.listvalidation.controller; - -import com.baeldung.listvalidation.domain.JobAspirant; -import com.baeldung.listvalidation.groups.AllLevels; -import com.baeldung.listvalidation.groups.Junior; -import com.baeldung.listvalidation.groups.MidSenior; -import com.baeldung.listvalidation.groups.Senior; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -public class ApplyJobController { - @PostMapping("/applyLevelJunior") - public ResponseEntity applyLevelJunior(@Validated({Junior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @PostMapping("/applyLevelMidSenior") - public ResponseEntity applyLevelMidSenior(@Validated({MidSenior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @PostMapping("/applyLevelSenior") - public ResponseEntity applyLevelSenior(@Validated({Senior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; - } -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java deleted file mode 100644 index 8e3f8cc7ef..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface AllLevels { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java deleted file mode 100644 index 8aca819f18..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface Junior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java deleted file mode 100644 index ddea95f5e2..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface MidSenior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java deleted file mode 100644 index d09d3ea5d5..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface Senior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java b/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java deleted file mode 100644 index 978110633c..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.baeldung.listvalidation.application; - - -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -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.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; - -import java.nio.charset.StandardCharsets; -import java.util.Map; - -@RunWith(SpringRunner.class) -@WebMvcTest -@AutoConfigureMockMvc -public class ApplyJobControllerIntegrationTest { - - @Autowired - private MockMvc mockMvc; - private static final String[] CORRECT_PASSPORT_EXPIRY_DATES = {"2025-01-01", "2026-02-29", "2024-03-31"}; - private static final String[] INCORRECT_PASSPORT_EXPIRY_DATES = {"2020-01-01", "2021-02-29", "2022-03-31"}; - - private static final Map MAP_OF_JOB_LEVEL_TO_PASSPORT_ERRMSG = Map.of( - "Junior", "Active passport is mandatory for Junior Level Job Application" - , "MidSenior", "Active passport is mandatory for Mid-Senior Level Job Application" - , "Senior", "Active passport is mandatory for Senior Level Job Application" - ); - private static final Map MAP_OF_JOB_LEVEL_TO_AGREEMENT_ERRMSG = Map.of( - "Junior", "Terms and Conditions consent missing for Junior Level Job Application" - , "MidSenior", "Terms and Conditions consent missing for Mid-Senior Level Job Application" - , "Senior", "Terms and Conditions consent missing for Senior Level Job Application" - ); - private static final String[] USERS_INCORRECT_NAMES = {"Bob", "bob Marley", "Bob John Federik Marley", "Bob M@rley" - , " Bob Marley", "Bob Marley ", "Bob Marley"}; - - private static final String[] USERS_CORRECT_NAMES = {"Bob Marley", "Bob John Marley", "Bobby"}; - - private static final Map MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES = Map.of( - "Junior", new String[]{"1", "2", "3", "4"} - , "MidSenior", new String[]{"6", "7", "8", "9"} - , "Senior", new String[]{"11", "12", "13", "14"} - ); - private static final Map MAP_OF_JOBLEVEL_TO_MIN_ERRMSG = Map.of( - "Junior", "Years of experience cannot be less than 5 Years" - , "MidSenior", "Years of experience cannot be less than 10 Years" - , "Senior", "Years of experience cannot be less than 15 Years" - ); - private static final Map MAP_OF_JOBLEVEL_TO_MAX_ERRMSG = Map.of( - "Junior", "Years of experience cannot be more than 10 Years" - , "MidSenior", "Years of experience cannot be more than 15 Years" - , "Senior", "Years of experience cannot be more than 20 Years" - ); - private static final Map MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES = Map.of( - "Junior", new String[]{"11", "14", "20", "30"} - , "MidSenior", new String[]{"16", "20", "25", "40"} - , "Senior", new String[]{"21", "25", "30", "35"} - ); - private static final Map MAP_OF_INCORRECT_NAMES_TO_ERRMSG = Map.of( - "Bob", "Name should have at least 5 characters" - , "bob Marley", "Name should not start with a lower case character" - , "Bob John Federik Marley", "Name should have at most 20 characters" - , "Bob M@rley", "Name should contain only alphabets and space" - , " Bob Marley", "Name should not start with space" - , "Bob Marley ", "Name should not end with space" - , "Bob Marley", "Name should not contain consecutive spaces" - ); - - private static final Map MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES = Map.of( - "Junior", new String[]{"6", "7", "8", "9", "10"} - , "MidSenior", new String[]{"11", "12", "13", "14", "15"} - , "Senior", new String[]{"16", "17", "18", "19", "20"} - ); - - - private static String[] USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS = null; - private static String[] USERS_ALL_FIELDS_VALID_JSONS = null; - - @Before - public void prepareAllValidFieldsExceptForPsptAndAgmt() { - USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.size() * 5 * INCORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : INCORRECT_PASSPORT_EXPIRY_DATES) { - USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + false + "\"}"; - } - } - } - } - - } - @Before - public void prepareUserWithAllFieldsValid() { - USERS_ALL_FIELDS_VALID_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.size() * 5 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_ALL_FIELDS_VALID_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersInvalidNamesInValidMaxExpValidPassportValidAgreementJsons() { - USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_INCORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_INCORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersCorrectNamesIncorrectMinExpJsons() { - USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersIncorrectNamesIncorrectMinExpJsons() { - USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_INCORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_INCORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersCorrectNamesIncorrectMaxExpJsons() { - USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Test - public void whenAllFieldsValidExceptForPsptAndAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"agreement\":\"" + MAP_OF_JOB_LEVEL_TO_AGREEMENT_ERRMSG.get(jobLevel) - + "\",\"passportExpiryDate\":\"" + MAP_OF_JOB_LEVEL_TO_PASSPORT_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenUserWithAllFieldsValid_thenCorrectResponse() throws Exception { - MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8); - String[] users = USERS_ALL_FIELDS_VALID_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(textPlainUtf8)) - .andExpect(MockMvcResultMatchers.content().string("Application submitted successfully")); - } - } - @Test - public void whenValidUserNamesInValidMaxExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MAX_ERRMSG.get(jobLevel) - + "\"}")); - } - } - @Test - public void whenInvalidUserNamesInValidMaxExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - String name = jsonObject.getString("name"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"name\":\"" + MAP_OF_INCORRECT_NAMES_TO_ERRMSG.get(name) - + "\",\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MAX_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenValidUserNamesInValidMinExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MIN_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenInValidUserNamesInValidMinExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - String name = jsonObject.getString("name"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"name\":\"" + MAP_OF_INCORRECT_NAMES_TO_ERRMSG.get(name) - + "\",\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MIN_ERRMSG.get(jobLevel) + "\"}")); - } - } -} diff --git a/spring-boot-modules/spring-boot-validations/README.md b/spring-boot-modules/spring-boot-validations/README.md new file mode 100644 index 0000000000..0d07204f3f --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/README.md @@ -0,0 +1,3 @@ +### Relevant Articles + +- [Validate Boolean Type in Spring Boot](https://www.baeldung.com/spring-boot-validate-boolean-type) diff --git a/spring-boot-modules/spring-boot-validations/pom.xml b/spring-boot-modules/spring-boot-validations/pom.xml new file mode 100644 index 0000000000..13044471af --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + spring-boot-validations + spring-boot-validations + Demo of Validations in Spring Boot + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..c0490d50c6 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java @@ -0,0 +1,12 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java new file mode 100644 index 0000000000..d4ea9a6336 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java @@ -0,0 +1,33 @@ +package com.baeldung.controller; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.dto.BooleanObject; +import com.baeldung.service.ValidationService; + +@RestController +public class ValidationController { + + @Autowired + ValidationService service; + + @PostMapping("/validateBoolean") + public ResponseEntity processBooleanObject(@RequestBody @Valid BooleanObject booleanObj) { + return ResponseEntity.ok("BooleanObject is valid"); + } + + @PostMapping("/validateBooleanAtService") + public ResponseEntity processBooleanObjectAtService() { + BooleanObject boolObj = new BooleanObject(); + boolObj.setBoolField(Boolean.TRUE); + boolObj.setTrueField(Boolean.FALSE); + service.processBoolean(boolObj); + return ResponseEntity.ok("BooleanObject is valid"); + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java new file mode 100644 index 0000000000..82f0839acf --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java @@ -0,0 +1,37 @@ +package com.baeldung.controlleradvice; + +import java.util.stream.Collectors; + +import javax.validation.ConstraintViolationException; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public String handleValidationException(MethodArgumentNotValidException ex) { + return ex.getBindingResult() + .getFieldErrors() + .stream() + .map(e -> e.getDefaultMessage()) + .collect(Collectors.joining(",")); + } + + @ExceptionHandler(IllegalArgumentException.class) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public String handleIllegalArugmentException(IllegalArgumentException ex) { + return ex.getMessage(); + } + + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) + public String handleConstraintViolationException(ConstraintViolationException ex) { + return ex.getMessage(); + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java new file mode 100644 index 0000000000..01a8e0eba0 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java @@ -0,0 +1,21 @@ +package com.baeldung.deserializer; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +public class BooleanDeserializer extends JsonDeserializer { + @Override + public Boolean deserialize(JsonParser parser, DeserializationContext context) throws IOException { + String value = parser.getText(); + if (value != null && value.equals("+")) { + return Boolean.TRUE; + } else if (value != null && value.equals("-")) { + return Boolean.FALSE; + } else { + throw new IllegalArgumentException("Only values accepted as Boolean are + and -"); + } + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java new file mode 100644 index 0000000000..750b23fe11 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java @@ -0,0 +1,56 @@ +package com.baeldung.dto; + +import javax.validation.constraints.AssertFalse; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + +import com.baeldung.deserializer.BooleanDeserializer; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +public class BooleanObject { + + @NotNull(message = "boolField cannot be null") + Boolean boolField; + + @AssertTrue(message = "trueField must have true value") + Boolean trueField; + + @NotNull(message = "falseField cannot be null") + @AssertFalse(message = "falseField must have false value") + Boolean falseField; + + @JsonDeserialize(using = BooleanDeserializer.class) + Boolean boolStringVar; + + public Boolean getBoolField() { + return boolField; + } + + public void setBoolField(Boolean boolField) { + this.boolField = boolField; + } + + public Boolean getTrueField() { + return trueField; + } + + public void setTrueField(Boolean trueField) { + this.trueField = trueField; + } + + public Boolean getFalseField() { + return falseField; + } + + public void setFalseField(Boolean falseField) { + this.falseField = falseField; + } + + public Boolean getBoolStringVar() { + return boolStringVar; + } + + public void setBoolStringVar(Boolean boolStringVar) { + this.boolStringVar = boolStringVar; + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java new file mode 100644 index 0000000000..3fc7160bd5 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java @@ -0,0 +1,17 @@ +package com.baeldung.service; + +import javax.validation.Valid; + +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import com.baeldung.dto.BooleanObject; + +@Service +@Validated +public class ValidationService { + + public void processBoolean(@Valid BooleanObject booleanObj) { + // further processing + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java new file mode 100644 index 0000000000..f05d76e3f1 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java @@ -0,0 +1,125 @@ +package com.baeldung.controller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.service.ValidationService; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = ValidationController.class) +class ValidationControllerUnitTest { + + @Autowired + private MockMvc mockMvc; + + @TestConfiguration + static class EmployeeServiceImplTestContextConfiguration { + @Bean + public ValidationService validationService() { + return new ValidationService() { + }; + } + } + + @Autowired + ValidationService service; + + @Test + void whenNullInputForBooleanField_thenHttpBadRequestAsHttpResponse() throws Exception { + String postBody = "{\"boolField\":null,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"+\"}"; + + mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andExpect(status().isBadRequest()); + } + + @Test + void whenInvalidInputForTrueBooleanField_thenErrorResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":false,\"falseField\":false,\"boolStringVar\":\"+\"}"; + + String output = mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andReturn() + .getResponse() + .getContentAsString(); + + assertEquals("trueField must have true value", output); + } + + @Test + void whenInvalidInputForFalseBooleanField_thenErrorResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":true,\"boolStringVar\":\"+\"}"; + + String output = mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andReturn() + .getResponse() + .getContentAsString(); + + assertEquals("falseField must have false value", output); + } + + @Test + void whenInvalidBooleanFromJson_thenErrorResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"plus\"}"; + + String output = mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andReturn() + .getResponse() + .getContentAsString(); + + assertEquals("Only values accepted as Boolean are + and -", output); + } + + @Test + void whenAllBooleanFieldsValid_thenCorrectResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"+\"}"; + + String output = mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andReturn() + .getResponse() + .getContentAsString(); + + assertEquals("BooleanObject is valid", output); + } + + @Test + void givenAllBooleanFieldsValid_whenServiceValidationFails_thenErrorResponse() throws Exception { + mockMvc.perform(post("/validateBooleanAtService").contentType("application/json")) + .andExpect(status().isInternalServerError()); + } + + @Test + void whenNullInputForTrueBooleanField_thenCorrectResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":null,\"falseField\":false,\"boolStringVar\":\"+\"}"; + + mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andExpect(status().isOk()); + } + + @Test + void whenNullInputForFalseBooleanField_thenHttpBadRequestAsHttpResponse() throws Exception { + String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":null,\"boolStringVar\":\"+\"}"; + + String output = mockMvc.perform(post("/validateBoolean").contentType("application/json") + .content(postBody)) + .andReturn() + .getResponse() + .getContentAsString(); + + assertEquals("falseField cannot be null", output); + } +} diff --git a/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java new file mode 100644 index 0000000000..9ab04794c6 --- /dev/null +++ b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.dto; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class BooleanUnitTest { + + @Test + void givenInputAsString_whenStringToBoolean_thenValidBooleanConversion() { + assertEquals(Boolean.TRUE, Boolean.valueOf("TRUE")); + assertEquals(Boolean.FALSE, Boolean.valueOf("false")); + assertEquals(Boolean.TRUE, Boolean.parseBoolean("True")); + } + + @Test + void givenInputAsboolean_whenbooleanToBoolean_thenValidBooleanConversion() { + assertEquals(Boolean.TRUE, Boolean.valueOf(true)); + assertEquals(Boolean.FALSE, Boolean.valueOf(false)); + } +} diff --git a/spring-boot-modules/spring-caching/pom.xml b/spring-boot-modules/spring-caching/pom.xml index 7f68dbf3ec..c27ccf3348 100644 --- a/spring-boot-modules/spring-caching/pom.xml +++ b/spring-boot-modules/spring-caching/pom.xml @@ -78,7 +78,6 @@ 3.5.2 - 1.18.26 \ No newline at end of file diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md index 365a21781c..ee12036528 100644 --- a/spring-boot-rest/README.md +++ b/spring-boot-rest/README.md @@ -1,6 +1,6 @@ ## Spring Boot REST -This module contains articles about Spring Boot RESTful APIs. +### ! This module contains articles about Spring Boot RESTful APIs. It should not be moved or used to store the code for any further article. ### Relevant Articles diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index 74d46f0651..db646899ad 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -134,7 +134,7 @@ io.rest-assured rest-assured - 3.3.0 + ${rest-assured.version} provided @@ -163,7 +163,7 @@ com.baeldung.SpringBootRestApplication 1.4.11.1 3.1.0 - 3.3.2 + 3.3.0 2.3.7 diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 9c926bbe61..729dd8eaf1 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -19,7 +19,8 @@ spring-cloud-loadbalancer spring-cloud-config - spring-cloud-eureka + + spring-cloud-hystrix spring-cloud-bootstrap spring-cloud-ribbon-client @@ -27,18 +28,18 @@ spring-cloud-gateway spring-cloud-gateway-2 spring-cloud-stream - spring-cloud-stream-starters + spring-cloud-connectors-heroku spring-cloud-aws spring-cloud-consul - spring-cloud-zuul-eureka-integration + spring-cloud-kubernetes spring-cloud-open-service-broker spring-cloud-archaius spring-cloud-functions spring-cloud-vault - spring-cloud-security + spring-cloud-task spring-cloud-zuul spring-cloud-zuul-fallback @@ -46,7 +47,7 @@ spring-cloud-eureka-self-preservation spring-cloud-openfeign - spring-cloud-netflix-feign + spring-cloud-netflix-sidecar spring-cloud-sentinel spring-cloud-dapr diff --git a/spring-cloud-modules/spring-cloud-archaius/pom.xml b/spring-cloud-modules/spring-cloud-archaius/pom.xml index 4d7ca3943d..3e90c7390c 100644 --- a/spring-cloud-modules/spring-cloud-archaius/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/pom.xml @@ -40,6 +40,7 @@ org.springframework.cloud spring-cloud-starter-netflix-archaius + ${spring-cloud-starter-netflix-archaius.version} org.springframework.boot @@ -54,7 +55,8 @@ - 2.0.3.RELEASE + 2.2.10.RELEASE + 2.2.10.RELEASE \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml index 6e25ace6a8..600fedc774 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml @@ -36,7 +36,7 @@ org.projectlombok lombok - provided + ${lombok.version} @@ -44,6 +44,7 @@ 1.11.407 5.0.3 0.7.6 + 1.18.26 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml index f90570abc2..383ad6a780 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml @@ -37,6 +37,22 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + + + + + + 2.0.1.RELEASE diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml index 7fb5747739..2871f129b5 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml @@ -27,6 +27,15 @@ h2 runtime + + org.projectlombok + lombok + ${lombok.version} + + + 1.18.26 + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties index 2ea30b9ab7..597899bd16 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties index 42e114450d..44d5267d10 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties @@ -6,8 +6,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=always -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties index 059b87e4e7..89f8ee40fe 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties index ca3aed2263..1a689123cb 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties @@ -4,4 +4,4 @@ server.port=9411 eureka.client.region = default eureka.client.registryFetchIntervalSeconds = 5 -logging.level.org.springframework.web=debug +logging.level.org.springframework.web=INFO diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md new file mode 100644 index 0000000000..b76ae19f26 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md @@ -0,0 +1,7 @@ +## Spring Cloud Gateway + +This module contains articles about Spring Cloud Gateway + +### Relevant Articles: + +- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) \ No newline at end of file diff --git a/spring-boot-documentation/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml similarity index 52% rename from spring-boot-documentation/pom.xml rename to spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml index d718f33a99..3d64edc338 100644 --- a/spring-boot-documentation/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -1,25 +1,19 @@ - 4.0.0 - com.baeldung.spring-boot-documentation - spring-boot-documentation - 1.0.0-SNAPSHOT - spring-boot-documentation - pom + gateway-2 + gateway-2 + jar com.baeldung - parent-boot-3 + parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-3 + ../../../parent-boot-2 - - springwolf - - @@ -29,6 +23,13 @@ pom import + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + org.springframework.boot spring-boot-dependencies @@ -39,8 +40,15 @@ + + + org.springframework.cloud + spring-cloud-starter-gateway + + + - 3.3.2 + 2021.0.3 - + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java new file mode 100644 index 0000000000..e209b6cdf0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class CustomPredicatesApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(CustomPredicatesApplication.class) + .profiles("customroutes") + .run(args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java new file mode 100644 index 0000000000..ea58eb7e46 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java @@ -0,0 +1,43 @@ +package com.baeldung.springcloudgateway.custompredicates.config; + +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory; +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory.Config; +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +@Configuration +public class CustomPredicatesConfig { + + + @Bean + public GoldenCustomerRoutePredicateFactory goldenCustomer(GoldenCustomerService goldenCustomerService) { + return new GoldenCustomerRoutePredicateFactory(goldenCustomerService); + } + + + //@Bean + public RouteLocator routes(RouteLocatorBuilder builder, GoldenCustomerRoutePredicateFactory gf ) { + + return builder.routes() + .route("dsl_golden_route", r -> + r.predicate(gf.apply(new Config(true, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .route("dsl_common_route", r -> + r.predicate(gf.apply(new Config(false, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .build(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java new file mode 100644 index 0000000000..cb5c3a0b50 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java @@ -0,0 +1,102 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.factories; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import javax.validation.constraints.NotEmpty; + +import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; +import org.springframework.http.HttpCookie; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.server.ServerWebExchange; + +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +/** + * @author Philippe + * + */ +public class GoldenCustomerRoutePredicateFactory extends AbstractRoutePredicateFactory { + + private final GoldenCustomerService goldenCustomerService; + + public GoldenCustomerRoutePredicateFactory(GoldenCustomerService goldenCustomerService ) { + super(Config.class); + this.goldenCustomerService = goldenCustomerService; + } + + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("isGolden","customerIdCookie"); + } + + + @Override + public Predicate apply(Config config) { + + return (ServerWebExchange t) -> { + List cookies = t.getRequest() + .getCookies() + .get(config.getCustomerIdCookie()); + + boolean isGolden; + if ( cookies == null || cookies.isEmpty()) { + isGolden = false; + } + else { + String customerId = cookies.get(0).getValue(); + isGolden = goldenCustomerService.isGoldenCustomer(customerId); + } + + return config.isGolden()?isGolden:!isGolden; + }; + } + + + @Validated + public static class Config { + boolean isGolden = true; + + @NotEmpty + String customerIdCookie = "customerId"; + + + public Config() {} + + public Config( boolean isGolden, String customerIdCookie) { + this.isGolden = isGolden; + this.customerIdCookie = customerIdCookie; + } + + public boolean isGolden() { + return isGolden; + } + + public void setGolden(boolean value) { + this.isGolden = value; + } + + /** + * @return the customerIdCookie + */ + public String getCustomerIdCookie() { + return customerIdCookie; + } + + /** + * @param customerIdCookie the customerIdCookie to set + */ + public void setCustomerIdCookie(String customerIdCookie) { + this.customerIdCookie = customerIdCookie; + } + + + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java new file mode 100644 index 0000000000..82bf2e6ae9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java @@ -0,0 +1,26 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.service; + +import org.springframework.stereotype.Component; + +/** + * @author Philippe + * + */ +@Component +public class GoldenCustomerService { + + public boolean isGoldenCustomer(String customerId) { + + // TODO: Add some AI logic to check is this customer deserves a "golden" status ;^) + if ( "baeldung".equalsIgnoreCase(customerId)) { + return true; + } + else { + return false; + } + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java new file mode 100644 index 0000000000..d276597a6b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/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-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml new file mode 100644 index 0000000000..859aa60bda --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml @@ -0,0 +1,26 @@ +spring: + cloud: + gateway: + routes: + - id: golden_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - GoldenCustomer=true + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,true + - id: common_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - name: GoldenCustomer + args: + golden: false + customerIdCookie: customerId + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,false + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml new file mode 100644 index 0000000000..a33bca2055 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml @@ -0,0 +1,4 @@ +logging: + level: + org.springframework.cloud.gateway: DEBUG + reactor.netty.http.client: DEBUG diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties new file mode 100644 index 0000000000..d7a6c4e072 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/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-ejb-modules/wildfly/wildfly-jpa/src/main/resources/logback.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/logback.xml rename to spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java new file mode 100644 index 0000000000..d9988ceb5e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java @@ -0,0 +1,67 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Before; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +/** + * This test requires + */ +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("customroutes") +public class CustomPredicatesApplicationLiveTest { + + @LocalServerPort + String serverPort; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void givenNormalCustomer_whenCallHeadersApi_thenResponseForNormalCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + ResponseEntity response = restTemplate.getForEntity(url, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("false"); + + } + + @Test + void givenGoldenCustomer_whenCallHeadersApi_thenResponseForGoldenCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + RequestEntity request = RequestEntity + .get(URI.create(url)) + .header("Cookie", "customerId=baeldung") + .build(); + + ResponseEntity response = restTemplate.exchange(request, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("true"); + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java new file mode 100644 index 0000000000..33855cd15d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java @@ -0,0 +1,25 @@ +package com.baeldung.springcloudgateway.introduction; + +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-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java new file mode 100644 index 0000000000..1550265f22 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/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-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..90c8f570aa --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml index e7fe7e7485..f4d4073ef1 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml @@ -18,6 +18,7 @@ config discovery gateway + gateway-2 svc-book svc-rating customer-service diff --git a/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-server/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-server/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..6fc9dc1151 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-server/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + diff --git a/spring-cloud-modules/spring-cloud-contract/pom.xml b/spring-cloud-modules/spring-cloud-contract/pom.xml index 7a9c8c32cd..f2d0d1b5b0 100644 --- a/spring-cloud-modules/spring-cloud-contract/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/pom.xml @@ -41,28 +41,35 @@ org.springframework.cloud spring-cloud-contract-wiremock - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-contract-stub-runner - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-starter-contract-verifier - ${spring-cloud.version} + ${spring-cloud-contract.version} test + + org.codehaus.groovy + groovy + ${groovy.version} + 4.0.3 + 4.0.4 2.1.4.RELEASE 2.17.1 + 2.5.6 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml index 680e2e1795..234f8b1b60 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml @@ -16,30 +16,43 @@ + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-rest + + org.springframework.cloud spring-cloud-contract-wiremock test + org.springframework.cloud spring-cloud-contract-stub-runner test - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-data-rest - + com.baeldung.spring.cloud spring-cloud-contract-producer ${project.parent.version} + stubs test + + + * + * + + + io.rest-assured rest-assured @@ -50,6 +63,12 @@ + + + org.codehaus.groovy + groovy + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java index e21223e6ea..c7d8b695db 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java @@ -1,13 +1,13 @@ package com.baeldung.spring.cloud.springcloudcontractconsumer.controller; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; +import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -20,10 +20,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @AutoConfigureMockMvc @AutoConfigureJsonTesters -@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL, - ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090") public class BasicMathControllerIntegrationTest { + @Rule + public StubRunnerRule rule = new StubRunnerRule().downloadStub( + "com.baeldung.spring.cloud", + "spring-cloud-contract-producer") + .withPort(8090).failOnNoStubs(true); + @Autowired private MockMvc mockMvc; diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml index 35dd9596f7..eb80f8d3dd 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml @@ -16,19 +16,17 @@ - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - + org.springframework.boot spring-boot-starter-web + org.springframework.boot spring-boot-starter-data-rest + io.rest-assured rest-assured @@ -39,6 +37,18 @@ + + + org.springframework.cloud + spring-cloud-starter-contract-verifier + test + + + + org.codehaus.groovy + groovy + + @@ -46,7 +56,7 @@ org.springframework.cloud spring-cloud-contract-maven-plugin - 2.1.1.RELEASE + ${spring-cloud-contract.version} true com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java index 68f0db60eb..49eb255303 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.session.data.redis.config.ConfigureRedisAction; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.test.context.junit4.SpringRunner; @@ -39,5 +40,10 @@ public class DataFlowServerApplicationIntegrationTest { return factory; } + + @Bean + public static ConfigureRedisAction configureRedisAction() { + return ConfigureRedisAction.NO_OP; + } } } diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml index ba923c4ae6..3e2b1632c7 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml @@ -46,7 +46,6 @@ 1.3.1.RELEASE Edgware.SR6 5.2.12.Final - 1.11.20 3.1.0 diff --git a/spring-cloud-modules/spring-cloud-eureka/pom.xml b/spring-cloud-modules/spring-cloud-eureka/pom.xml index 23523f2c2f..599853c675 100644 --- a/spring-cloud-modules/spring-cloud-eureka/pom.xml +++ b/spring-cloud-modules/spring-cloud-eureka/pom.xml @@ -45,8 +45,6 @@ - 2.1.2.RELEASE - Greenwich.RELEASE 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml index 4fdfe2d9c2..08a85d191a 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml @@ -41,7 +41,7 @@ org.springframework.cloud - spring-cloud-starter-netflix-ribbon + spring-cloud-starter-loadbalancer org.springframework.cloud @@ -51,6 +51,20 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-webflux + + + io.projectreactor + reactor-test + test + + + org.springframework.boot + spring-boot-starter-test + 2.6.8 + com.github.tomakehurst wiremock @@ -75,9 +89,18 @@ + + + repository.spring.milestone + Spring Milestone Repository + https://repo.spring.io/release + + + + org.apache.maven.plugins maven-surefire-plugin 1 @@ -87,4 +110,9 @@ + + 17 + 17 + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java index a263624b28..97d8643e19 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java @@ -1,16 +1,15 @@ package com.baeldung.spring.cloud.client; -import com.baeldung.spring.cloud.model.Book; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.RequestMapping; - import java.util.List; -@FeignClient("books-service") -//@FeignClient(value="simple-books-client", url="${book.service.url}") +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.baeldung.spring.cloud.model.Book; + +@FeignClient(name = "books-service") public interface BooksClient { @RequestMapping("/books") List getBooks(); - } diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java index 2842eef435..7f4807e356 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -21,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @SpringBootTest @ActiveProfiles("test") +@EnableFeignClients @EnableConfigurationProperties @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { WireMockConfig.class }) @@ -29,12 +31,16 @@ class BooksClientIntegrationTest { @Autowired private WireMockServer mockBooksService; + @Autowired + private WireMockServer mockBooksService2; + @Autowired private BooksClient booksClient; @BeforeEach void setUp() throws IOException { setupMockBooksResponse(mockBooksService); + setupMockBooksResponse(mockBooksService2); } @Test diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java index 6747d14b88..10ea3ffa34 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java @@ -31,9 +31,6 @@ public class EurekaContainerConfig { + eurekaServer.getFirstMappedPort().toString() + "/eureka") .applyTo(configurableApplicationContext); - } - } - } diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java index f05df11ba3..5690c24d77 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerBooksClientIntegrationTest.java @@ -9,23 +9,39 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; +import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import static com.baeldung.spring.cloud.client.BookMocks.setupMockBooksResponse; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.moreThan; import static java.util.Arrays.asList; +import static org.assertj.core.api.BDDAssertions.then; import static org.junit.jupiter.api.Assertions.assertTrue; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + @SpringBootTest -@ActiveProfiles("ribbon-test") +@ActiveProfiles("test") @EnableConfigurationProperties +@EnableFeignClients @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = { RibbonTestConfig.class }) +@ContextConfiguration(classes = { TestConfig.class }) class LoadBalancerBooksClientIntegrationTest { @Autowired @@ -37,10 +53,22 @@ class LoadBalancerBooksClientIntegrationTest { @Autowired private BooksClient booksClient; + @Autowired + private LoadBalancerClientFactory clientFactory; + @BeforeEach void setUp() throws IOException { setupMockBooksResponse(mockBooksService); setupMockBooksResponse(secondMockBooksService); + + String serviceId = "books-service"; + RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(ServiceInstanceListSuppliers + .toProvider(serviceId, instance(serviceId, "localhost", false), instance(serviceId, "localhost", true)), + serviceId, -1); + } + + private static DefaultServiceInstance instance(String serviceId, String host, boolean secure) { + return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure); } @Test @@ -62,4 +90,53 @@ class LoadBalancerBooksClientIntegrationTest { new Book("Dune", "Frank Herbert"), new Book("Foundation", "Isaac Asimov")))); } + + @Test + void loadbalancerWorks() throws IOException { + + setupMockBooksResponse(mockBooksService); + setupMockBooksResponse(secondMockBooksService); + + ReactiveLoadBalancer reactiveLoadBalancer = this.clientFactory.getInstance("books-service", + ReactiveLoadBalancer.class, ServiceInstance.class); + + then(reactiveLoadBalancer).isInstanceOf(RoundRobinLoadBalancer.class); + then(reactiveLoadBalancer).isInstanceOf(ReactorLoadBalancer.class); + ReactorLoadBalancer loadBalancer = (ReactorLoadBalancer) reactiveLoadBalancer; + + for (int k = 0; k < 10; k++) { + booksClient.getBooks(); + } + + // order dependent on seedPosition -1 of RoundRobinLoadBalancer + List hosts = Arrays.asList("localhost", "localhost"); + + assertLoadBalancer(loadBalancer, hosts); + + mockBooksService.verify( + moreThan(0), getRequestedFor(WireMock.urlEqualTo("/books"))); + secondMockBooksService.verify( + moreThan(0), getRequestedFor(WireMock.urlEqualTo("/books"))); + } + + private void assertLoadBalancer(ReactorLoadBalancer loadBalancer, List hosts) { + for (String host : hosts) { + Mono> source = loadBalancer.choose(); + StepVerifier.create(source).consumeNextWith(response -> { + then(response).isNotNull(); + then(response.hasServer()).isTrue(); + + ServiceInstance instance = response.getServer(); + then(instance).isNotNull(); + then(instance.getHost()).as("instance host is incorrect %s", host).isEqualTo(host); + + if (host.contains("secure")) { + then(instance.isSecure()).isTrue(); + } + else { + then(instance.isSecure()).isFalse(); + } + }).verifyComplete(); + } + } } diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerIntegrationTest.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerIntegrationTest.java new file mode 100644 index 0000000000..eee4e7b860 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/LoadBalancerIntegrationTest.java @@ -0,0 +1,112 @@ +package com.baeldung.spring.cloud.client; + +import static org.assertj.core.api.BDDAssertions.then; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; +import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.github.tomakehurst.wiremock.WireMockServer; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@SpringBootTest +@EnableFeignClients +@EnableConfigurationProperties +@ExtendWith(SpringExtension.class) +@ActiveProfiles("test") +@ContextConfiguration(classes = { TestConfig.class }) +class LoadBalancerIntegrationTest { + + @Autowired + private LoadBalancerClientFactory clientFactory; + + @Autowired + private BooksClient booksClient; + + @Autowired + private WireMockServer mockBooksService; + + @Autowired + private WireMockServer secondMockBooksService; + + private void assertLoadBalancer(ReactorLoadBalancer loadBalancer, List hosts) { + for (String host : hosts) { + Mono> source = loadBalancer.choose(); + StepVerifier.create(source).consumeNextWith(response -> { + then(response).isNotNull(); + then(response.hasServer()).isTrue(); + + ServiceInstance instance = response.getServer(); + then(instance).isNotNull(); + then(instance.getHost()).as("instance host is incorrect %s", host).isEqualTo(host); + + if (host.contains("secure")) { + then(instance.isSecure()).isTrue(); + } + else { + then(instance.isSecure()).isFalse(); + } + }).verifyComplete(); + } + } + + @Test + void staticConfigurationWorks() { + String serviceId = "test-book-service"; + RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(ServiceInstanceListSuppliers + .toProvider(serviceId, instance(serviceId, "bookservice1", false), instance(serviceId, "bookservice2", false)), + serviceId, -1); + assertLoadBalancer(loadBalancer, Arrays.asList("bookservice1", "bookservice2")); + } + + private static DefaultServiceInstance instance(String serviceId, String host, boolean secure) { + return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure); + } + + @EnableAutoConfiguration + @SpringBootConfiguration(proxyBeanMethods = false) + @LoadBalancerClients({ @LoadBalancerClient(name = "books-service", configuration = MyBooksServiceConfig.class) }) + @EnableCaching + protected static class Config { + + } + + protected static class MyBooksServiceConfig { + + @Bean + public RoundRobinLoadBalancer roundRobinContextLoadBalancer(LoadBalancerClientFactory clientFactory, + Environment env) { + String serviceId = LoadBalancerClientFactory.getName(env); + return new RoundRobinLoadBalancer( + clientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId, -1); + } + + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java deleted file mode 100644 index 273ba182b1..0000000000 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/RibbonTestConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.spring.cloud.client; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.ServerList; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.cloud.netflix.ribbon.StaticServerList; -import org.springframework.context.annotation.Bean; -import org.springframework.test.context.ActiveProfiles; - -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -@TestConfiguration -@ActiveProfiles("ribbon-test") -public class RibbonTestConfig { - - @Autowired - private WireMockServer mockBooksService; - - @Autowired - private WireMockServer secondMockBooksService; - - @Bean(initMethod = "start", destroyMethod = "stop") - public WireMockServer mockBooksService() { - return new WireMockServer(options().dynamicPort()); - } - - @Bean(name="secondMockBooksService", initMethod = "start", destroyMethod = "stop") - public WireMockServer secondBooksMockService() { - return new WireMockServer(options().dynamicPort()); - } - - @Bean - public ServerList ribbonServerList() { - return new StaticServerList<>( - new Server("localhost", mockBooksService.port()), - new Server("localhost", secondMockBooksService.port())); - } - -} diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/TestConfig.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/TestConfig.java new file mode 100644 index 0000000000..b3770721b1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/TestConfig.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.cloud.client; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ActiveProfiles; + +import com.github.tomakehurst.wiremock.WireMockServer; + +@TestConfiguration +@ActiveProfiles("test") +public class TestConfig { + + @Bean(initMethod = "start", destroyMethod = "stop") + public WireMockServer mockBooksService() { + return new WireMockServer(options().port(80)); + } + + @Bean(name="secondMockBooksService", initMethod = "start", destroyMethod = "stop") + public WireMockServer secondBooksMockService() { + return new WireMockServer(options().port(81)); + } +} diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java index 82b7cddede..3d4f2822f4 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java @@ -11,7 +11,11 @@ public class WireMockConfig { @Bean(initMethod = "start", destroyMethod = "stop") public WireMockServer mockBooksService() { - return new WireMockServer(9561); + return new WireMockServer(80); } + @Bean(initMethod = "start", destroyMethod = "stop") + public WireMockServer mockBooksService2() { + return new WireMockServer(81); + } } diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml deleted file mode 100644 index 84a78d0ec7..0000000000 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-ribbon-test.yml +++ /dev/null @@ -1,3 +0,0 @@ -eureka: - client: - enabled: false diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-spring-cloud-balancer-test.yml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-spring-cloud-balancer-test.yml new file mode 100644 index 0000000000..ad11d46ae8 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-spring-cloud-balancer-test.yml @@ -0,0 +1,19 @@ +eureka: + client: + enabled: false + +spring: + application: + name: books-service + cloud: + loadbalancer: + ribbon: + enabled: false + discovery: + client: + simple: + instances: + books-service[0]: + uri: http://localhost:80 + books-service[1]: + uri: http://localhost:81 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml index dce11adf69..231d45004f 100644 --- a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml @@ -1,11 +1,19 @@ -#book: -# service: -# url: http://localhost:9561 - -books-service: - ribbon: - listOfServers: http://localhost:9561 - eureka: client: enabled: false + +spring: + application: + name: books-service + cloud: + loadbalancer: + ribbon: + enabled: false + discovery: + client: + simple: + instances: + books-service[0]: + uri: http://localhost:80 + books-service[1]: + uri: http://localhost:81 diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..fb1f109a18 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-functions/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-functions/src/test/resources/logback-test.xml index 8d4771e308..41283752a9 100644 --- a/spring-cloud-modules/spring-cloud-functions/src/test/resources/logback-test.xml +++ b/spring-cloud-modules/spring-cloud-functions/src/test/resources/logback-test.xml @@ -6,6 +6,8 @@ + + diff --git a/spring-cloud-modules/spring-cloud-kubernetes/kubernetes-guide/travel-agency-service/mongo-deployment.yaml b/spring-cloud-modules/spring-cloud-kubernetes/kubernetes-guide/travel-agency-service/mongo-deployment.yaml index 3d40581578..77a5efa13c 100644 --- a/spring-cloud-modules/spring-cloud-kubernetes/kubernetes-guide/travel-agency-service/mongo-deployment.yaml +++ b/spring-cloud-modules/spring-cloud-kubernetes/kubernetes-guide/travel-agency-service/mongo-deployment.yaml @@ -14,22 +14,24 @@ spec: selector: service: mongo --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: mongo spec: replicas: 1 + selector: + matchLabels: + name: mongodb-service template: metadata: labels: service: mongo - name: mongodb-service + name: mongodb-service spec: containers: - args: - mongod - - --smallfiles image: mongo:latest name: mongo env: diff --git a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml index f519b6316b..92d66c03df 100644 --- a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml @@ -58,6 +58,20 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + Camden.SR7 8.18.0 diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties index aa0dc6a382..0a31d79ee0 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties @@ -4,7 +4,7 @@ feign.okhttp.enabled=true server.port=8085 spring.main.allow-bean-definition-overriding=true -logging.level.com.baeldung.cloud.openfeign.client=DEBUG +logging.level.com.baeldung.cloud.openfeign.client=INFO feign.hystrix.enabled=true spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java b/spring-cloud-modules/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java index 98e25ac9c4..4204588428 100644 --- a/spring-cloud-modules/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java +++ b/spring-cloud-modules/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java @@ -1,12 +1,13 @@ package com.baeldung.filters; import javax.servlet.http.HttpServletRequest; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.ZuulFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; + public class SimpleFilter extends ZuulFilter { private static Logger log = LoggerFactory.getLogger(SimpleFilter.class); @@ -31,7 +32,8 @@ public class SimpleFilter extends ZuulFilter { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); - log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); + log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL() + .toString())); return null; } diff --git a/spring-cloud-modules/spring-cloud-security/auth-resource/pom.xml b/spring-cloud-modules/spring-cloud-security/auth-resource/pom.xml index 9362a71931..b4e29fce49 100644 --- a/spring-cloud-modules/spring-cloud-security/auth-resource/pom.xml +++ b/spring-cloud-modules/spring-cloud-security/auth-resource/pom.xml @@ -33,6 +33,21 @@ spring-security-jwt ${spring-jwt.version} + + com.sun.xml.bind + jaxb-core + ${jaxb-core.version} + + + javax.xml.bind + jaxb-api + ${jaxb-api.version} + + + com.sun.xml.bind + jaxb-impl + ${jaxb-impl.version} + diff --git a/spring-cloud-modules/spring-cloud-security/auth-server/pom.xml b/spring-cloud-modules/spring-cloud-security/auth-server/pom.xml index 234d9cde78..8c14b8fa74 100644 --- a/spring-cloud-modules/spring-cloud-security/auth-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-security/auth-server/pom.xml @@ -35,6 +35,21 @@ org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure + + com.sun.xml.bind + jaxb-core + ${jaxb-core.version} + + + javax.xml.bind + jaxb-api + ${jaxb-api.version} + + + com.sun.xml.bind + jaxb-impl + ${jaxb-impl.version} + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-security/pom.xml b/spring-cloud-modules/spring-cloud-security/pom.xml index ad6421384e..72d1d6cbfc 100644 --- a/spring-cloud-modules/spring-cloud-security/pom.xml +++ b/spring-cloud-modules/spring-cloud-security/pom.xml @@ -34,6 +34,9 @@ 2021.0.3 + 2.3.0.1 + 2.3.1 + 2.3.1 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml index eee5b27396..95176d1e5c 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml @@ -3,7 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung.spring.cloud spring-cloud-stream-starters 1.0.0-SNAPSHOT spring-cloud-stream-starters @@ -32,7 +31,7 @@ - 2021.0.0 + 2022.0.4 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml index 51e8703e6e..1a19415a3f 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml @@ -61,16 +61,21 @@ org.junit.vintage junit-vintage-engine + + org.codehaus.groovy + groovy + ${groovy.version} + + twitterhdfs org.springframework.boot spring-boot-maven-plugin - twitterhdfs @@ -83,6 +88,7 @@ 4.13.2 5.8.1 2.17.1 + 3.0.8 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..233cfa7e23 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml b/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml index 71275793ec..b7cd3e7726 100644 --- a/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml +++ b/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml @@ -19,8 +19,4 @@ spring: hibernate: dialect: org.hibernate.dialect.MySQL5Dialect batch: - initialize-schema: always -maven: - remoteRepositories: - springRepo: - url: https://repo.spring.io/libs-snapshot \ No newline at end of file + initialize-schema: always \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties index 1660dc8516..e69de29bb2 100644 --- a/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties @@ -1 +0,0 @@ -maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..2a5eefdd1f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml index 3960cfde5d..46b3e7047f 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml index c9bc120e4d..796b908bca 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml index 76d899447f..11cc992523 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml @@ -61,6 +61,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-fallback/pom.xml b/spring-cloud-modules/spring-cloud-zuul-fallback/pom.xml index ff62a99a00..fcf216cd6e 100644 --- a/spring-cloud-modules/spring-cloud-zuul-fallback/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-fallback/pom.xml @@ -22,7 +22,6 @@ 2020.0.3 2.2.7.RELEASE - 3.1.1 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..4ff950099a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + # Pattern of log message for console appender + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/spring-core-2/pom.xml b/spring-core-2/pom.xml index f6142cffb0..2d11cc2124 100644 --- a/spring-core-2/pom.xml +++ b/spring-core-2/pom.xml @@ -149,7 +149,7 @@ org.apache.maven.plugins maven-war-plugin - ${maven.version} + ${maven-war-plugin.version} false @@ -166,7 +166,7 @@ 3.6 2.1.0 3.22.0-GA - 3.2.2 + 3.2.2 \ No newline at end of file diff --git a/spring-core-4/pom.xml b/spring-core-4/pom.xml index 492a2ec5a2..fb544e29fd 100644 --- a/spring-core-4/pom.xml +++ b/spring-core-4/pom.xml @@ -74,7 +74,7 @@ org.apache.commons commons-text - ${apache-commons-text.version} + ${commons-text.version} @@ -84,8 +84,7 @@ 4.0.2 4.0.0 1.3.2 - 3.3.2 - 1.10.0 + 1.10.0 \ No newline at end of file diff --git a/spring-core/pom.xml b/spring-core/pom.xml index d1c155b92a..e369bc24d0 100644 --- a/spring-core/pom.xml +++ b/spring-core/pom.xml @@ -88,7 +88,6 @@ 1.5.2.RELEASE 1.10.19 1.3.2 - 3.3.2 \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java index a3c5445698..aa526b5403 100644 --- a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java @@ -7,7 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @Configuration public class AppConfigFunctionBean { diff --git a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java index 33a9c5c21e..2ef775ee4f 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java @@ -1,10 +1,10 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonAppContextBean; -import com.baeldung.scope.singletone.SingletonBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonAppContextBean; +import com.baeldung.scope.singleton.SingletonBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; diff --git a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java index 9f1874375e..0564dfb3c0 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.*; diff --git a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java index 5cf0c9170c..47014aa2d1 100644 --- a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java +++ b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.util.Assert; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java similarity index 94% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java index f4d57a0f63..4f5b3274c8 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.BeansException; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java similarity index 93% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java index 8d3a09b8fd..9c4cea4439 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.apache.log4j.Logger; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java index 8cdc56a6fa..2788af1701 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import java.util.function.Function; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java similarity index 88% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java index 4c3c9b69da..e5461826ef 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Lookup; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java index 55a91f8202..0e70d12e6e 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.ObjectFactory; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java similarity index 90% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java index 37d0ad9404..01a4a0ff11 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java index d0c2733765..df04957992 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java @@ -1,10 +1,9 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; -import com.baeldung.scope.singletone.SingletonLookupBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonLookupBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java index 1e3c652599..dac3461ceb 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java @@ -11,7 +11,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.config.scope.AppConfigFunctionBean; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = AppConfigFunctionBean.class) diff --git a/spring-credhub/pom.xml b/spring-credhub/pom.xml index 4604833d0b..defe378b6b 100644 --- a/spring-credhub/pom.xml +++ b/spring-credhub/pom.xml @@ -27,7 +27,7 @@ org.springframework.credhub spring-credhub-starter - 2.2.0 + ${spring-credhub-starter.version} com.google.code.gson @@ -36,8 +36,7 @@ - 8 - 8 + 2.2.0 UTF-8 diff --git a/spring-cucumber/pom.xml b/spring-cucumber/pom.xml index c6c163d7d1..042e81971f 100644 --- a/spring-cucumber/pom.xml +++ b/spring-cucumber/pom.xml @@ -45,6 +45,12 @@ ${cucumber.version} test + + org.junit.vintage + junit-vintage-engine + ${junit-vintage-engine.version} + test + org.apache.commons @@ -54,8 +60,9 @@ - 6.8.0 + 7.14.0 1.3.2 + 5.10.0 \ No newline at end of file diff --git a/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/CucumberOptionsApplication.java b/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/CucumberOptionsApplication.java new file mode 100644 index 0000000000..03082128b3 --- /dev/null +++ b/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/CucumberOptionsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.cucumberoptions; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CucumberOptionsApplication { + + public static void main(String[] args) { + SpringApplication.run(CucumberOptionsApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/HealthCheckController.java b/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/HealthCheckController.java new file mode 100644 index 0000000000..637dbdb540 --- /dev/null +++ b/spring-cucumber/src/main/java/com/baeldung/cucumberoptions/HealthCheckController.java @@ -0,0 +1,22 @@ +package com.baeldung.cucumberoptions; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HealthCheckController { + + @GetMapping(path = "/v1/status", produces = APPLICATION_JSON_VALUE) + public HttpStatus getV1Status() { + return ResponseEntity.ok().build().getStatusCode(); + } + + @GetMapping(path = "/v2/status", produces = APPLICATION_JSON_VALUE) + public HttpStatus getV2Status() { + return ResponseEntity.ok().build().getStatusCode(); + } +} \ No newline at end of file diff --git a/spring-cucumber/src/test/java/com/baeldung/cucumberoptions/HealthCheckStepDefsIntegrationTest.java b/spring-cucumber/src/test/java/com/baeldung/cucumberoptions/HealthCheckStepDefsIntegrationTest.java new file mode 100644 index 0000000000..999adadbef --- /dev/null +++ b/spring-cucumber/src/test/java/com/baeldung/cucumberoptions/HealthCheckStepDefsIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.cucumberoptions; + +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import com.baeldung.SpringIntegrationTest; + +public class HealthCheckStepDefsIntegrationTest extends SpringIntegrationTest { + + private ResponseEntity statusResponse; + + private ResponseEntity doGet(String url) { + return new RestTemplate().getForEntity(url, String.class); + } + + @When("^the client calls /v1/status") + public void checkV1Status() throws Throwable { + statusResponse = doGet("http://localhost:8082/v1/status"); + } + + @When("^the client calls /v2/status") + public void checkV2Status() throws Throwable { + statusResponse = doGet("http://localhost:8082/v2/status"); + } + + @Then("^the client receives (\\d+) status code$") + public void verifyStatusCode(int statusCode) throws Throwable { + final HttpStatus currentStatusCode = statusResponse.getStatusCode(); + assertThat(currentStatusCode.value(), is(statusCode)); + } +} \ No newline at end of file diff --git a/spring-cucumber/src/test/resources/com/baeldung/cucumberoptions/healthcheck.feature b/spring-cucumber/src/test/resources/com/baeldung/cucumberoptions/healthcheck.feature new file mode 100644 index 0000000000..33e07c1add --- /dev/null +++ b/spring-cucumber/src/test/resources/com/baeldung/cucumberoptions/healthcheck.feature @@ -0,0 +1,11 @@ +Feature: healthcheck endpoints can be verified + + @v1 + Scenario: v1 status is healthy + When the client calls /v1/status + Then the client receives 200 status code + + @v2 + Scenario: v2 status is healthy + When the client calls /v2/status + Then the client receives 200 status code diff --git a/spring-cucumber/src/test/resources/cucumber.properties b/spring-cucumber/src/test/resources/cucumber.properties new file mode 100644 index 0000000000..22c3379201 --- /dev/null +++ b/spring-cucumber/src/test/resources/cucumber.properties @@ -0,0 +1 @@ +cucumber.filter.tags=not @v2 \ No newline at end of file diff --git a/spring-di-2/pom.xml b/spring-di-2/pom.xml index 69333c74f1..0bd6c41a8c 100644 --- a/spring-di-2/pom.xml +++ b/spring-di-2/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-spring-5 + parent-spring-6 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-6 @@ -46,11 +46,6 @@ org.springframework spring-aspects - - javax.inject - javax.inject - ${javax.inject.version} - org.springframework.boot spring-boot-starter-test @@ -84,9 +79,8 @@ - 2.6.1 + 3.1.2 1.14.0 - 1 2.17.1 diff --git a/spring-di-2/src/main/java/com/baeldung/di/aspectj/PersonEntity.java b/spring-di-2/src/main/java/com/baeldung/di/aspectj/PersonEntity.java index f087a97c7e..758a942227 100644 --- a/spring-di-2/src/main/java/com/baeldung/di/aspectj/PersonEntity.java +++ b/spring-di-2/src/main/java/com/baeldung/di/aspectj/PersonEntity.java @@ -3,9 +3,9 @@ package com.baeldung.di.aspectj; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Transient; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Transient; @Entity @Configurable(preConstruction = true) diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldByNameInjectIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldByNameInjectIntegrationTest.java index d1a75d73ea..f7ca089355 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldByNameInjectIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldByNameInjectIntegrationTest.java @@ -3,8 +3,8 @@ package com.baeldung.wiring.configuration.inject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import javax.inject.Inject; -import javax.inject.Named; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldInjectIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldInjectIntegrationTest.java index 995f560701..c06205aee8 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldInjectIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldInjectIntegrationTest.java @@ -3,7 +3,7 @@ package com.baeldung.wiring.configuration.inject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import javax.inject.Inject; +import jakarta.inject.Inject; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldQualifierInjectIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldQualifierInjectIntegrationTest.java index 67fa2bf3d4..2a3e41f63f 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldQualifierInjectIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/inject/FieldQualifierInjectIntegrationTest.java @@ -3,7 +3,7 @@ package com.baeldung.wiring.configuration.inject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import javax.inject.Inject; +import jakarta.inject.Inject; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/FieldResourceInjectionIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/FieldResourceInjectionIntegrationTest.java index 938d557939..16430a0573 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/FieldResourceInjectionIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/FieldResourceInjectionIntegrationTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertNotNull; import java.io.File; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByQualifierResourceIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByQualifierResourceIntegrationTest.java index f49bf70aba..1c1e3388b5 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByQualifierResourceIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByQualifierResourceIntegrationTest.java @@ -9,7 +9,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceQualifier; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByTypeResourceIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByTypeResourceIntegrationTest.java index aecd02a1d5..660610753f 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByTypeResourceIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodByTypeResourceIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodResourceInjectionIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodResourceInjectionIntegrationTest.java index 4ef9368c28..0fcc2b1c50 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodResourceInjectionIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/MethodResourceInjectionIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/NamedResourceIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/NamedResourceIntegrationTest.java index 4339194f63..5aed1ac7cb 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/NamedResourceIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/NamedResourceIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/QualifierResourceInjectionIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/QualifierResourceInjectionIntegrationTest.java index cc8c669757..03f82adef3 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/QualifierResourceInjectionIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/QualifierResourceInjectionIntegrationTest.java @@ -9,7 +9,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceQualifier; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/SetterResourceInjectionIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/SetterResourceInjectionIntegrationTest.java index 90c8677bff..605f86172c 100644 --- a/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/SetterResourceInjectionIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/wiring/configuration/resource/SetterResourceInjectionIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.wiring.configuration.ApplicationContextTestResourceNameType; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.File; import static org.junit.Assert.assertEquals; diff --git a/spring-di-3/pom.xml b/spring-di-3/pom.xml index 2d635d1f85..ba1a18ae8c 100644 --- a/spring-di-3/pom.xml +++ b/spring-di-3/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-spring-5 + parent-spring-6 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-6 @@ -45,8 +45,10 @@ - 2.6.1 + 3.1.2 2.17.1 + 2.0.9 + 1.4.11 \ No newline at end of file diff --git a/spring-di-3/src/test/java/com/baeldung/dynamic/autowire/DynamicAutowireIntegrationTest.java b/spring-di-3/src/test/java/com/baeldung/dynamic/autowire/DynamicAutowireIntegrationTest.java index 56582ecb66..d93f94b0e3 100644 --- a/spring-di-3/src/test/java/com/baeldung/dynamic/autowire/DynamicAutowireIntegrationTest.java +++ b/spring-di-3/src/test/java/com/baeldung/dynamic/autowire/DynamicAutowireIntegrationTest.java @@ -7,7 +7,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = DynamicAutowireConfig.class) diff --git a/spring-di-4/pom.xml b/spring-di-4/pom.xml index c6572495cb..1eec8efcf0 100644 --- a/spring-di-4/pom.xml +++ b/spring-di-4/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../parent-boot-2 + ../parent-boot-3 diff --git a/spring-di-4/src/main/java/com/baeldung/sampleabstract/BallService.java b/spring-di-4/src/main/java/com/baeldung/sampleabstract/BallService.java index 0d951aac8b..541d8dfb6b 100644 --- a/spring-di-4/src/main/java/com/baeldung/sampleabstract/BallService.java +++ b/spring-di-4/src/main/java/com/baeldung/sampleabstract/BallService.java @@ -2,7 +2,7 @@ package com.baeldung.sampleabstract; import org.springframework.beans.factory.annotation.Autowired; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; public abstract class BallService { diff --git a/spring-di/pom.xml b/spring-di/pom.xml index cf3703096c..bae7263ef9 100644 --- a/spring-di/pom.xml +++ b/spring-di/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-spring-5 + parent-spring-6 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-6 @@ -48,11 +48,6 @@ spring-context ${spring.version} - - javax.inject - javax.inject - ${javax.inject.version} - com.google.guava guava @@ -71,7 +66,7 @@ org.springframework.boot spring-boot-test - ${mockito.spring.boot.version} + ${spring-boot.version} test @@ -89,11 +84,6 @@ - - javax.annotation - javax.annotation-api - ${annotation-api.version} - @@ -143,13 +133,8 @@ org.baeldung.org.baeldung.sample.App - 1.3.2 - 1.4.4.RELEASE - 1 - 1.5.2.RELEASE - 1.10.19 + 3.1.2 1.9.5 - 3.3.2 \ No newline at end of file diff --git a/spring-ejb-modules/ejb-beans/pom.xml b/spring-ejb-modules/ejb-beans/pom.xml index 6bfbb42a14..94f7963ad6 100644 --- a/spring-ejb-modules/ejb-beans/pom.xml +++ b/spring-ejb-modules/ejb-beans/pom.xml @@ -66,12 +66,12 @@ org.apache.activemq activemq-broker - ${activemq.broker.version} + ${activemq-broker.version} org.apache.activemq.tooling activemq-junit - ${activemq.junit.version} + ${activemq-junit.version} test @@ -187,8 +187,8 @@ 8.2.1.Final 3.2 5.2.3.RELEASE - 5.16.3 - 5.16.3 + 5.16.3 + 5.16.3 2.21.0 2.8 8.2.1.Final diff --git a/spring-ejb-modules/pom.xml b/spring-ejb-modules/pom.xml index c5d04dab25..bb4fe87a6d 100755 --- a/spring-ejb-modules/pom.xml +++ b/spring-ejb-modules/pom.xml @@ -17,10 +17,10 @@ - + spring-ejb-remote spring-ejb-client - wildfly + wildfly-mdb @@ -76,6 +76,7 @@ 12.0.0.Final 2.4 3.2 + 7.0 \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-mdb/README.md b/spring-ejb-modules/wildfly-mdb/README.md similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-mdb/README.md rename to spring-ejb-modules/wildfly-mdb/README.md diff --git a/spring-ejb-modules/wildfly/wildfly-mdb/pom.xml b/spring-ejb-modules/wildfly-mdb/pom.xml similarity index 82% rename from spring-ejb-modules/wildfly/wildfly-mdb/pom.xml rename to spring-ejb-modules/wildfly-mdb/pom.xml index 0784725cde..7498379ef9 100644 --- a/spring-ejb-modules/wildfly/wildfly-mdb/pom.xml +++ b/spring-ejb-modules/wildfly-mdb/pom.xml @@ -7,9 +7,9 @@ wildfly-mdb - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT + com.baeldung.spring.ejb + spring-ejb-modules + 1.0.0-SNAPSHOT diff --git a/spring-ejb-modules/wildfly/wildfly-mdb/src/com/baeldung/wildfly/mdb/ReadMessageMDB.java b/spring-ejb-modules/wildfly-mdb/src/com/baeldung/wildfly/mdb/ReadMessageMDB.java similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-mdb/src/com/baeldung/wildfly/mdb/ReadMessageMDB.java rename to spring-ejb-modules/wildfly-mdb/src/com/baeldung/wildfly/mdb/ReadMessageMDB.java diff --git a/spring-ejb-modules/wildfly/wildfly-mdb/src/com/baeldung/wildfly/mdb/SendMessageServlet.java b/spring-ejb-modules/wildfly-mdb/src/com/baeldung/wildfly/mdb/SendMessageServlet.java similarity index 100% rename from spring-ejb-modules/wildfly/wildfly-mdb/src/com/baeldung/wildfly/mdb/SendMessageServlet.java rename to spring-ejb-modules/wildfly-mdb/src/com/baeldung/wildfly/mdb/SendMessageServlet.java diff --git a/spring-ejb-modules/wildfly/pom.xml b/spring-ejb-modules/wildfly/pom.xml deleted file mode 100644 index f122e99001..0000000000 --- a/spring-ejb-modules/wildfly/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - 4.0.0 - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - wildfly - pom - - - com.baeldung.spring.ejb - spring-ejb-modules - 1.0.0-SNAPSHOT - - - - widlfly-web - wildfly-ear - wildfly-jpa - wildfly-ejb-interfaces - wildfly-ejb - wildfly-mdb - - - - - - - - javax - javaee-api - ${javaee-api.version} - provided - - - - org.wildfly.bom - wildfly-javaee7 - ${wildfly-javaee7.version} - import - pom - - - - org.hibernate - hibernate-core - ${hibernate-core.version} - provided - - - - com.baeldung.wildfly - wildlfy-ear - ${wildlfy.version} - ear - - - - com.baeldung.wildfly - wildlfy-web - ${wildlfy.version} - war - - - - com.baeldung.wildfly - wildlfy-jpa - ${wildlfy.version} - - - - com.baeldung.wildfly - wildfly-ejb - ${wildlfy.version} - - - - com.baeldung.wildfly - wildfly-ejb-interfaces - ${wildlfy.version} - - - - - - 7.0 - 10.1.0.Final - 5.2.3.Final - 0.0.1-SNAPSHOT - - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/widlfly-web/pom.xml b/spring-ejb-modules/wildfly/widlfly-web/pom.xml deleted file mode 100644 index 46c3f7d0bc..0000000000 --- a/spring-ejb-modules/wildfly/widlfly-web/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - widlfly-web - widlfly-web - war - - - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - - - - - - javax - javaee-api - ${javaee-api.version} - provided - - - - com.baeldung.wildfly - wildfly-jpa - ${wildlfy.version} - - - - com.baeldung.wildfly - wildfly-ejb-interfaces - ${wildlfy.version} - - - - com.baeldung.wildfly - wildfly-ejb - ${wildlfy.version} - - - - - 3.3.2 - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestEJBServlet.java b/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestEJBServlet.java deleted file mode 100644 index 57376e9c4a..0000000000 --- a/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestEJBServlet.java +++ /dev/null @@ -1,41 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.List; - -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import model.User; -import wildfly.beans.UserBeanLocal; - -/** - * Servlet implementation class TestEJBServlet - */ -public class TestEJBServlet extends HttpServlet { - - @EJB - private UserBeanLocal userBean; - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - List users = userBean.getUsers(); - - PrintWriter out = response.getWriter(); - - out.println(""); - out.println(""); - for (User user : users) { - out.print(user.getUsername()); - out.print(" " + user.getEmail() + "
"); - } - out.println(""); - out.println(""); - } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - doGet(request, response); - } -} diff --git a/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestJPAServlet.java b/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestJPAServlet.java deleted file mode 100644 index 609366c53a..0000000000 --- a/spring-ejb-modules/wildfly/widlfly-web/src/main/java/TestJPAServlet.java +++ /dev/null @@ -1,54 +0,0 @@ - -import java.io.IOException; -import java.util.List; - -import javax.annotation.Resource; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.transaction.UserTransaction; - -import model.User; - -/** - * Servlet implementation class TestJPAServlet - */ -public class TestJPAServlet extends HttpServlet { - private static final long serialVersionUID = 1L; - @PersistenceContext(unitName = "wildfly-jpa") - EntityManager em; - - @Resource - UserTransaction tx; - - /** - * @see HttpServlet#HttpServlet() - */ - public TestJPAServlet() { - super(); - // TODO Auto-generated constructor stub - } - - /** - * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) - */ - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Query q = em.createNamedQuery("User.findAll"); - List users = q.getResultList(); - response.getWriter() - .append("JPA users returned: " + users.size()); - } - - /** - * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) - */ - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // TODO Auto-generated method stub - doGet(request, response); - } - -} diff --git a/spring-ejb-modules/wildfly/widlfly-web/src/main/webapp/WEB-INF/web.xml b/spring-ejb-modules/wildfly/widlfly-web/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 5b3f664443..0000000000 --- a/spring-ejb-modules/wildfly/widlfly-web/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - widlfly-web - - index.html - index.htm - index.jsp - default.html - default.htm - default.jsp - - - - TestJPAServlet - TestJPAServlet - TestJPAServlet - - - TestJPAServlet - /TestJPAServlet - - - - TestEJBServlet - TestEJBServlet - TestEJBServlet - - - TestEJBServlet - /TestEJBServlet - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-ear/pom.xml b/spring-ejb-modules/wildfly/wildfly-ear/pom.xml deleted file mode 100644 index da321cb9eb..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ear/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - wildfly-ear - wildfly-ear - ear - - - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - - - - - - com.baeldung.wildfly - widlfly-web - ${wildlfy.version} - war - - - - com.baeldung.wildfly - wildfly-jpa - ${wildlfy.version} - - - - com.baeldung.wildfly - wildfly-ejb - - - - com.baeldung.wildfly - wildfly-ejb-interfaces - - - - - - - maven-ear-plugin - ${maven-ear-plugin.version} - - lib/ - ${defaultLibBundleDir.version} - - - com.baeldung.wildfly - widlfly-web - /wildfly - - - - - - org.wildfly.plugins - wildfly-maven-plugin - ${wildfly-maven-plugin.version} - - - - - - 2.10.1 - 1.2.0.Final - 7 - - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/pom.xml b/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/pom.xml deleted file mode 100644 index bc9159b667..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - 4.0.0 - wildfly-ejb-interfaces - wildfly-ejb-interfaces - - - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - - - - - - javax.ejb - javax.ejb-api - ${javax.ejb-api.version} - provided - - - - com.baeldung.wildfly - wildfly-jpa - ${wildlfy.version} - - - - - 3.2 - - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanLocal.java b/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanLocal.java deleted file mode 100644 index 16930cb5b9..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanLocal.java +++ /dev/null @@ -1,13 +0,0 @@ -package wildfly.beans; - -import java.util.List; - -import javax.ejb.Local; - -import model.User; - -@Local -public interface UserBeanLocal { - - List getUsers(); -} diff --git a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanRemote.java b/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanRemote.java deleted file mode 100644 index 5b57d4283f..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ejb-interfaces/src/main/java/wildfly/beans/UserBeanRemote.java +++ /dev/null @@ -1,13 +0,0 @@ -package wildfly.beans; - -import java.util.List; - -import javax.ejb.Remote; - -import model.User; - -@Remote -public interface UserBeanRemote { - - List getUsers(); -} diff --git a/spring-ejb-modules/wildfly/wildfly-ejb/pom.xml b/spring-ejb-modules/wildfly/wildfly-ejb/pom.xml deleted file mode 100644 index 36574bf984..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ejb/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - wildfly-ejb - wildfly-ejb - ejb - - - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - - - - - - javax.ejb - javax.ejb-api - ${ejb.version} - provided - - - - javax - javaee-api - provided - - - - org.hibernate - hibernate-core - - - - com.baeldung.wildfly - wildfly-ejb-interfaces - - - - - - - org.apache.maven.plugins - maven-ejb-plugin - - ${ejb.version} - - - - - - - 3.2 - - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-ejb/src/main/java/wildfly/beans/UserBean.java b/spring-ejb-modules/wildfly/wildfly-ejb/src/main/java/wildfly/beans/UserBean.java deleted file mode 100644 index 07e3cbcb32..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-ejb/src/main/java/wildfly/beans/UserBean.java +++ /dev/null @@ -1,24 +0,0 @@ -package wildfly.beans; - -import java.util.List; - -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import model.User; - -/** - * Session Bean implementation class UserBean - */ -@Stateless -public class UserBean implements UserBeanRemote, UserBeanLocal { - @PersistenceContext(unitName = "wildfly-jpa") - private EntityManager em; - - @Override - public List getUsers() { - return em.createNamedQuery("User.findAll") - .getResultList(); - } -} diff --git a/spring-ejb-modules/wildfly/wildfly-jpa/pom.xml b/spring-ejb-modules/wildfly/wildfly-jpa/pom.xml deleted file mode 100644 index 603e337510..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-jpa/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - 4.0.0 - wildfly-jpa - wildfly-jpa - - - com.baeldung.wildfly - wildfly - 0.0.1-SNAPSHOT - - - - - - - org.hibernate - hibernate-core - provided - - - - \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/java/model/User.java b/spring-ejb-modules/wildfly/wildfly-jpa/src/main/java/model/User.java deleted file mode 100644 index 3a3f95bf8c..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/java/model/User.java +++ /dev/null @@ -1,51 +0,0 @@ -package model; - -import java.io.Serializable; -import javax.persistence.*; - -/** - * The persistent class for the users database table. - * - */ -@Entity -@Table(name = "users") -@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u") -public class User implements Serializable { - private static final long serialVersionUID = 1L; - - @Id - private String username; - - private String email; - - @Column(name = "postal_number") - private Integer postalNumber; - - public User() { - } - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Integer getPostalNumber() { - return this.postalNumber; - } - - public void setPostalNumber(Integer postalNumber) { - this.postalNumber = postalNumber; - } - -} \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/META-INF/persistence.xml b/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 2aa6bc2cd7..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - java:/H2DS - model.User - - - - - - - - diff --git a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/data.sql b/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/data.sql deleted file mode 100644 index 03eafa534e..0000000000 --- a/spring-ejb-modules/wildfly/wildfly-jpa/src/main/resources/data.sql +++ /dev/null @@ -1 +0,0 @@ -INSERT INTO users (username, email, postal_number) VALUES ('user1', 'user1@baeldung.com', 1000), ('user2', 'user2@baeldung.com', 2); \ No newline at end of file diff --git a/spring-exceptions/pom.xml b/spring-exceptions/pom.xml index 8912cad674..49c44f88f2 100644 --- a/spring-exceptions/pom.xml +++ b/spring-exceptions/pom.xml @@ -181,7 +181,6 @@ 2.7 1.6.1 - 3.3.2 \ No newline at end of file diff --git a/spring-exceptions/src/main/java/com/baeldung/ex/beancreationexception/cause9/Config.java b/spring-exceptions/src/main/java/com/baeldung/ex/beancreationexception/cause9/Config.java new file mode 100644 index 0000000000..ef182c04b6 --- /dev/null +++ b/spring-exceptions/src/main/java/com/baeldung/ex/beancreationexception/cause9/Config.java @@ -0,0 +1,19 @@ +package com.baeldung.ex.beancreationexception.cause9; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Config { + + @Autowired + BeanFactory beanFactory; + + @Bean + public BeanB beanB() { + beanFactory.getBean("beanA"); + return new BeanB(); + } +} diff --git a/spring-integration/src/test/resources/logback-test.xml b/spring-integration/src/test/resources/logback-test.xml index 8f1be4eb7a..98bfc86d71 100644 --- a/spring-integration/src/test/resources/logback-test.xml +++ b/spring-integration/src/test/resources/logback-test.xml @@ -9,6 +9,8 @@ + + diff --git a/spring-jersey/pom.xml b/spring-jersey/pom.xml index 17d527ca6a..32f75aa676 100644 --- a/spring-jersey/pom.xml +++ b/spring-jersey/pom.xml @@ -221,7 +221,6 @@ 4.5.5 2.27.2 1.5.10.RELEASE - 3.3.2 \ No newline at end of file diff --git a/spring-kafka-2/README.md b/spring-kafka-2/README.md index d71e75f15c..318312ace6 100644 --- a/spring-kafka-2/README.md +++ b/spring-kafka-2/README.md @@ -7,3 +7,4 @@ This module contains articles about Spring with Kafka - [Implementing Retry in Kafka Consumer](https://www.baeldung.com/spring-retry-kafka-consumer) - [Spring Kafka: Configure Multiple Listeners on Same Topic](https://www.baeldung.com/spring-kafka-multiple-listeners-same-topic) - [Understanding Kafka Topics and Partitions](https://www.baeldung.com/kafka-topics-partitions) +- [How to Subscribe a Kafka Consumer to Multiple Topics](https://www.baeldung.com/kafka-subscribe-consumer-multiple-topics) diff --git a/spring-kafka-2/pom.xml b/spring-kafka-2/pom.xml index 76a82f6000..0bca20447d 100644 --- a/spring-kafka-2/pom.xml +++ b/spring-kafka-2/pom.xml @@ -53,7 +53,7 @@ org.testcontainers junit-jupiter - ${testcontainers-kafka.version} + ${testcontainers-junit-jupiter.version} test @@ -65,6 +65,7 @@ 1.16.2 + 1.16.2 \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java new file mode 100644 index 0000000000..741fb6bba4 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; + +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ConsumerFactory consumerFactory() { + Map config = new HashMap<>(); + config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(), new JsonDeserializer<>(PaymentData.class)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java new file mode 100644 index 0000000000..2135a27f39 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.kafka.annotation.EnableKafka; + +@EnableKafka +@SpringBootApplication +public class KafkaMultipleTopicsApplication { + public static void main(String[] args) { + SpringApplication.run(KafkaMultipleTopicsApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java new file mode 100644 index 0000000000..2cb0117bf1 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ProducerFactory producerFactory() { + Map config = new HashMap<>(); + config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaProducerFactory<>(config, new StringSerializer(), new JsonSerializer<>()); + } + + @Bean + public KafkaTemplate kafkaProducer() { + return new KafkaTemplate<>(producerFactory()); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java new file mode 100644 index 0000000000..e81138c089 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.StringJoiner; + +public class PaymentData { + private String paymentReference; + private String type; + private BigDecimal amount; + private Currency currency; + + public String getPaymentReference() { + return paymentReference; + } + + public void setPaymentReference(String paymentReference) { + this.paymentReference = paymentReference; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + @Override + public String toString() { + return new StringJoiner(", ", PaymentData.class.getSimpleName() + "[", "]") + .add("paymentReference='" + paymentReference + "'") + .add("type='" + type + "'") + .add("amount=" + amount) + .add("currency=" + currency) + .toString(); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java new file mode 100644 index 0000000000..fb640cca25 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Service; + +@Service +public class PaymentDataListener { + private final Logger log = LoggerFactory.getLogger(PaymentDataListener.class); + + @KafkaListener(topics = { "card-payments", "bank-transfers" }, groupId = "payments") + public void handlePaymentEvents(PaymentData paymentData, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + log.info("Event on topic={}, payload={}", topic, paymentData); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java index 7cfbdd5fb0..2919ae1d7b 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java @@ -8,29 +8,22 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; @Service public class TemperatureConsumer { - private CountDownLatch latch = new CountDownLatch(1); - Map> consumedRecords = new ConcurrentHashMap<>(); @KafkaListener(topics = "celcius-scale-topic", groupId = "group-1") public void consumer1(ConsumerRecord consumerRecord) { - computeConsumedRecord("consumer-1", consumerRecord.partition()); + trackConsumedPartitions("consumer-1", consumerRecord.partition()); } - private void computeConsumedRecord(String key, int consumerRecord) { - consumedRecords.computeIfAbsent(key, k -> new HashSet<>()); - consumedRecords.computeIfPresent(key, (k, v) -> { - v.add(String.valueOf(consumerRecord)); + private void trackConsumedPartitions(String consumerName, int partitionNumber) { + consumedRecords.computeIfAbsent(consumerName, k -> new HashSet<>()); + consumedRecords.computeIfPresent(consumerName, (k, v) -> { + v.add(String.valueOf(partitionNumber)); return v; }); } - - public CountDownLatch getLatch() { - return latch; - } } diff --git a/spring-kafka-2/src/main/resources/application.properties b/spring-kafka-2/src/main/resources/application.properties index 4725ace2d9..ed844cadf8 100644 --- a/spring-kafka-2/src/main/resources/application.properties +++ b/spring-kafka-2/src/main/resources/application.properties @@ -1,4 +1,4 @@ -spring.kafka.bootstrap-servers=localhost:9092 +spring.kafka.bootstrap-servers=localhost:9092,localhost:9093,localhost:9094 message.topic.name=baeldung long.message.topic.name=longMessage greeting.topic.name=greeting diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java index b6634ec7ed..9dfebb104e 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java @@ -19,7 +19,7 @@ import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; import org.springframework.kafka.test.context.EmbeddedKafka; @SpringBootTest(classes = MultipleListenersApplicationKafkaApp.class) -@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +@EmbeddedKafka(partitions = 1, controlledShutdown = true, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) class KafkaMultipleListenersIntegrationTest { @Autowired diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java new file mode 100644 index 0000000000..345e84b65b --- /dev/null +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java @@ -0,0 +1,78 @@ +package com.baeldung.spring.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.kafka.test.utils.ContainerTestUtils; + +@SpringBootTest(classes = KafkaMultipleTopicsApplication.class) +@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +public class KafkaMultipleTopicsIntegrationTest { + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + + @Autowired + private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + + @Autowired + private KafkaTemplate kafkaProducer; + + @SpyBean + private PaymentDataListener paymentsConsumer; + + @BeforeEach + void setUp() { + // wait for embedded Kafka + for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry.getListenerContainers()) { + ContainerTestUtils.waitForAssignment(messageListenerContainer, 2); + } + } + + @Test + public void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + CountDownLatch countDownLatch = new CountDownLatch(2); + doAnswer(invocation -> { + countDownLatch.countDown(); + return null; + }).when(paymentsConsumer) + .handlePaymentEvents(any(), any()); + + kafkaProducer.send(CARD_PAYMENTS_TOPIC, createCardPayment()); + kafkaProducer.send(BANK_TRANSFERS_TOPIC, createBankTransfer()); + + assertThat(countDownLatch.await(5, TimeUnit.SECONDS)).isTrue(); + } + + private PaymentData createCardPayment() { + PaymentData cardPayment = new PaymentData(); + cardPayment.setAmount(BigDecimal.valueOf(275)); + cardPayment.setPaymentReference("A184028KM0013790"); + cardPayment.setCurrency(Currency.getInstance("GBP")); + cardPayment.setType("card"); + return cardPayment; + } + + private PaymentData createBankTransfer() { + PaymentData bankTransfer = new PaymentData(); + bankTransfer.setAmount(BigDecimal.valueOf(150)); + bankTransfer.setPaymentReference("19ae2-18mk73-009"); + bankTransfer.setCurrency(Currency.getInstance("EUR")); + bankTransfer.setType("bank"); + return bankTransfer; + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java index 52cda85f90..daec8232bf 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java @@ -22,7 +22,7 @@ import com.baeldung.spring.kafka.retryable.RetryableApplicationKafkaApp; import com.fasterxml.jackson.databind.ObjectMapper; @SpringBootTest(classes = RetryableApplicationKafkaApp.class) -@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +@EmbeddedKafka(partitions = 1, controlledShutdown = true, brokerProperties = { "listeners=PLAINTEXT://localhost:9093", "port=9093" }) public class KafkaRetryableIntegrationTest { @ClassRule public static EmbeddedKafkaBroker embeddedKafka = new EmbeddedKafkaBroker(1, true, "multitype"); diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java index 309c87125a..4413239c78 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java @@ -7,10 +7,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.kafka.test.EmbeddedKafkaBroker; import org.springframework.kafka.test.context.EmbeddedKafka; -import java.util.concurrent.TimeUnit; - @SpringBootTest(classes = ThermostatApplicationKafkaApp.class) -@EmbeddedKafka(partitions = 2, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) +@EmbeddedKafka(partitions = 2, controlledShutdown = true, brokerProperties = {"listeners=PLAINTEXT://localhost:9094", "port=9094"}) public class KafkaTopicsAndPartitionsIntegrationTest { @ClassRule public static EmbeddedKafkaBroker embeddedKafka = new EmbeddedKafkaBroker(1, true, "multitype"); @@ -24,7 +22,7 @@ public class KafkaTopicsAndPartitionsIntegrationTest { @Test public void givenTopic_andConsumerGroup_whenConsumersListenToEvents_thenConsumeItCorrectly() throws Exception { service.measureCelsiusAndPublish(10000); - consumer.getLatch().await(1, TimeUnit.SECONDS); + Thread.sleep(1000); System.out.println(consumer.consumedRecords); } } diff --git a/spring-kafka/pom.xml b/spring-kafka/pom.xml index c013be32e3..7ff7a9710a 100644 --- a/spring-kafka/pom.xml +++ b/spring-kafka/pom.xml @@ -26,12 +26,12 @@ org.springframework.boot spring-boot-starter-actuator - 3.0.5 + ${spring-boot-starter-actuator.version} io.micrometer micrometer-registry-prometheus - 1.10.5 + ${micrometer-registry-prometheus.version} org.springframework.kafka @@ -90,6 +90,8 @@
+ 3.0.5 + 1.10.5 1.16.2 diff --git a/spring-katharsis/pom.xml b/spring-katharsis/pom.xml index 82be0555c3..595cde5109 100644 --- a/spring-katharsis/pom.xml +++ b/spring-katharsis/pom.xml @@ -33,7 +33,7 @@ io.katharsis katharsis-spring - ${katharsis.version} + ${katharsis-spring.version} org.apache.commons @@ -132,10 +132,9 @@ - 3.0.2 + 3.0.2 0.9.10 1.6.1 - 3.3.2 \ No newline at end of file diff --git a/spring-mobile/pom.xml b/spring-mobile/pom.xml index 0c279c0d62..d96faf3274 100644 --- a/spring-mobile/pom.xml +++ b/spring-mobile/pom.xml @@ -37,28 +37,16 @@ org.apache.maven.plugins maven-war-plugin - ${maven-war-plugin.version} org.apache.maven.plugins maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - --add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED - - 1.1.5.RELEASE - 11 - 11 - 3.3.2 \ No newline at end of file diff --git a/spring-native/pom.xml b/spring-native/pom.xml index 55f17c833f..97eb33c1c7 100644 --- a/spring-native/pom.xml +++ b/spring-native/pom.xml @@ -17,17 +17,27 @@ - spring-release - Spring release - https://repo.spring.io/release + spring-milestone + Spring Milestone + https://repo.spring.io/milestone + + + spring-snapshot + Spring Snapshot + https://repo.spring.io/snapshot - spring-release - Spring release - https://repo.spring.io/release + spring-plugins-snapshot + Spring Plugins Snapshot + https://repo.spring.io/plugins-snapshot + + + spring-plugins-milestone + Spring Plugins Milestone + https://repo.spring.io/plugins-milestone diff --git a/spring-pulsar/pom.xml b/spring-pulsar/pom.xml index 4c2fc0d9b4..05debcab1c 100644 --- a/spring-pulsar/pom.xml +++ b/spring-pulsar/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-pulsar 0.0.1-SNAPSHOT @@ -26,7 +27,7 @@ org.springframework.pulsar spring-pulsar-spring-boot-starter - 0.2.0 + ${spring-pulsar-spring-boot-starter.version} @@ -45,4 +46,8 @@ + + 0.2.0 + + diff --git a/spring-reactive-modules/pom.xml b/spring-reactive-modules/pom.xml index e75682da78..61a3c3d17d 100644 --- a/spring-reactive-modules/pom.xml +++ b/spring-reactive-modules/pom.xml @@ -17,16 +17,15 @@ - spring-5-data-reactive - spring-5-data-reactive-2 - spring-5-reactive - spring-5-reactive-2 - spring-5-reactive-3 - spring-5-reactive-client - spring-5-reactive-client-2 - spring-5-reactive-filters - spring-5-reactive-oauth - spring-5-reactive-security + spring-reactive-data + spring-reactive-2 + spring-reactive-3 + spring-reactive-client + spring-reactive-client-2 + spring-reactive-filters + spring-reactive-oauth + spring-reactive-security + spring-reactive-data-couchbase spring-reactive spring-reactive-exceptions spring-reactor @@ -63,7 +62,4 @@ - - - \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/application.properties b/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/application.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/spring-reactive-modules/spring-5-reactive-3/README.md b/spring-reactive-modules/spring-5-reactive-3/README.md deleted file mode 100644 index 38036f929b..0000000000 --- a/spring-reactive-modules/spring-5-reactive-3/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## Spring 5 Reactive Project - -This module contains articles about reactive Spring 5. - -- [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) -- [Reading Flux Into a Single InputStream Using Spring Reactive WebClient](https://www.baeldung.com/spring-reactive-read-flux-into-inputstream) -- [Spring Boot FeignClient vs. WebClient](https://www.baeldung.com/spring-boot-feignclient-vs-webclient) -- [Cancel an Ongoing Flux in Spring WebFlux](https://www.baeldung.com/spring-webflux-cancel-flux) -- More articles: [[<-- prev]](../spring-5-reactive-2) diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/resources/application.properties b/spring-reactive-modules/spring-5-reactive-3/src/main/resources/application.properties deleted file mode 100644 index 815cc2b76d..0000000000 --- a/spring-reactive-modules/spring-5-reactive-3/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -# application properties \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/WebSecurityConfig.java b/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/WebSecurityConfig.java deleted file mode 100644 index 384e26ac8c..0000000000 --- a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/WebSecurityConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.reactive.actuator; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; - -@Configuration -@EnableWebFluxSecurity -public class WebSecurityConfig { - - @Bean - public SecurityWebFilterChain securitygWebFilterChain( - ServerHttpSecurity http) { - - return http.authorizeExchange() - .pathMatchers("/actuator/**").permitAll() - .anyExchange().authenticated() - .and().build(); - } - -} diff --git a/spring-reactive-modules/spring-5-reactive/README.md b/spring-reactive-modules/spring-5-reactive/README.md deleted file mode 100644 index f3148fe696..0000000000 --- a/spring-reactive-modules/spring-5-reactive/README.md +++ /dev/null @@ -1,14 +0,0 @@ -## Spring 5 Reactive Project - -This module contains articles about reactive Spring 5 - -### The Course -The "REST With Spring" Classes: https://bit.ly/restwithspring - -### Relevant Articles - -- [Exploring the Spring 5 WebFlux URL Matching](https://www.baeldung.com/spring-5-mvc-url-matching) -- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets) -- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header) -- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive) -- More articles: [[next -->]](../spring-5-reactive-2) diff --git a/spring-reactive-modules/spring-5-reactive/pom.xml b/spring-reactive-modules/spring-5-reactive/pom.xml deleted file mode 100644 index 212281b6f9..0000000000 --- a/spring-reactive-modules/spring-5-reactive/pom.xml +++ /dev/null @@ -1,165 +0,0 @@ - - - 4.0.0 - spring-5-reactive - 0.0.1-SNAPSHOT - spring-5-reactive - jar - spring 5 sample project about new features - - - com.baeldung.spring.reactive - spring-reactive-modules - 1.0.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.springframework.boot - spring-boot-starter-integration - - - org.springframework.boot - spring-boot-starter-websocket - - - javax.json.bind - javax.json.bind-api - - - org.projectlombok - lombok - compile - - - org.apache.geronimo.specs - geronimo-json_1.1_spec - ${geronimo-json_1.1_spec.version} - - - org.apache.johnzon - johnzon-jsonb - - - - org.apache.commons - commons-lang3 - - - - org.springframework.boot - spring-boot-devtools - runtime - - - org.springframework - spring-test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - io.projectreactor - reactor-test - test - - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-starter-data-redis - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.session - spring-session-core - - - org.springframework.session - spring-session-data-redis - - - org.apache.commons - commons-collections4 - ${commons-collections4.version} - test - - - io.reactivex.rxjava2 - rxjava - - - org.apache.httpcomponents - httpclient - - - io.netty - netty-all - - - - - - - maven-resources-plugin - 3.0.1 - - - copy-resources - validate - - copy-resources - - - - - src/main/assets - true - - - ${basedir}/target/classes/assets - - - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.reactive.Spring5ReactiveApplication - JAR - - - - - - - 1.1.3 - 1.0 - 1.0 - - - \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/assets/index.html b/spring-reactive-modules/spring-5-reactive/src/main/assets/index.html deleted file mode 100644 index 047514df1c..0000000000 --- a/spring-reactive-modules/spring-5-reactive/src/main/assets/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Baeldung: Static Content in Spring WebFlux - - -Example Spring Web Flux and web resources configuration - - \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java deleted file mode 100644 index 61927e47ab..0000000000 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.baeldung.websession.configuration; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; - -@Configuration -@EnableWebFluxSecurity -public class WebFluxSecurityConfig { - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - UserDetails admin = User - .withUsername("admin") - .password(encoder().encode("password")) - .roles("ADMIN") - .build(); - - UserDetails user = User - .withUsername("user") - .password(encoder().encode("password")) - .roles("USER") - .build(); - - return new MapReactiveUserDetailsService(admin, user); - } - - @Bean - public SecurityWebFilterChain webSessionSpringSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange() - .anyExchange().authenticated() - .and() - .httpBasic() - .securityContextRepository(new WebSessionServerSecurityContextRepository()) - .and() - .formLogin(); - - http.csrf().disable(); - - return http.build(); - - } - - @Bean - public PasswordEncoder encoder() { - return new BCryptPasswordEncoder(); - } -} diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties b/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties deleted file mode 100644 index dfe4a4d994..0000000000 --- a/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -logging.level.root=INFO -server.tomcat.max-keep-alive-requests=1 \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-2/.gitignore b/spring-reactive-modules/spring-reactive-2/.gitignore similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/.gitignore rename to spring-reactive-modules/spring-reactive-2/.gitignore diff --git a/spring-reactive-modules/spring-5-reactive-2/README.md b/spring-reactive-modules/spring-reactive-2/README.md similarity index 62% rename from spring-reactive-modules/spring-5-reactive-2/README.md rename to spring-reactive-modules/spring-reactive-2/README.md index 1cd3bf46c6..dbaebc370e 100644 --- a/spring-reactive-modules/spring-5-reactive-2/README.md +++ b/spring-reactive-modules/spring-reactive-2/README.md @@ -1,10 +1,12 @@ ## Spring 5 Reactive Project -This module contains articles about reactive Spring 5. +This module contains articles about reactive Spring Boot. - [Validation for Functional Endpoints in Spring 5](https://www.baeldung.com/spring-functional-endpoints-validation) - [Testing Reactive Streams Using StepVerifier and TestPublisher](https://www.baeldung.com/reactive-streams-step-verifier-test-publisher) - [Static Content in Spring WebFlux](https://www.baeldung.com/spring-webflux-static-content) - [Server-Sent Events in Spring](https://www.baeldung.com/spring-server-sent-events) - [Backpressure Mechanism in Spring WebFlux](https://www.baeldung.com/spring-webflux-backpressure) -- More articles: [[<-- prev]](../spring-5-reactive) [[next -->]](../spring-5-reactive-3) +- [Exploring the Spring 5 WebFlux URL Matching](https://www.baeldung.com/spring-5-mvc-url-matching) +- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header) +- More articles: [[<-- prev]](../spring-reactive) [[next -->]](../spring-reactive-3) diff --git a/spring-reactive-modules/spring-5-reactive-2/pom.xml b/spring-reactive-modules/spring-reactive-2/pom.xml similarity index 95% rename from spring-reactive-modules/spring-5-reactive-2/pom.xml rename to spring-reactive-modules/spring-reactive-2/pom.xml index 41c434fb92..13970851cd 100644 --- a/spring-reactive-modules/spring-5-reactive-2/pom.xml +++ b/spring-reactive-modules/spring-reactive-2/pom.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-2 + spring-reactive-2 0.0.1-SNAPSHOT spring-5-reactive-2 jar @@ -59,6 +59,10 @@ spring-security-test test + + org.springframework.boot + spring-boot-starter-tomcat + diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/controller/PathPatternController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/controller/PathPatternController.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/model/Foo.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/model/Foo.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/ConsumerSSEApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/ConsumerSSEApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/ConsumerSSEApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/ConsumerSSEApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/controller/ClientController.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/controller/ClientController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/controller/ClientController.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/consumer/controller/ClientController.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/ServerSSEApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/ServerSSEApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/ServerSSEApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/ServerSSEApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/controllers/ServerController.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/controllers/ServerController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/controllers/ServerController.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/serversentevents/server/controllers/ServerController.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/Actor.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/Actor.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java similarity index 98% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java index b7bb53600e..6007597220 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java +++ b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java @@ -32,7 +32,7 @@ public class ExploreSpring5URLPatternUsingRouterFunctions { .and(RouterFunctions.resources("/resources/**", new ClassPathResource("resources/"))); } - WebServer start() throws Exception { + WebServer start() { WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction()); HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler) .filter(new IndexRewriteFilter()) diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/util/CpuUtils.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/reactive/util/CpuUtils.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/FunctionalValidationsApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/AbstractValidationHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/FunctionalHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/AnnotatedRequestEntityValidationHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/CustomRequestEntityValidationHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/handlers/impl/OtherEntityValidationHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/AnnotatedRequestEntity.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/CustomRequestEntity.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/model/OtherEntity.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/routers/ValidationsRouters.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/validators/CustomRequestEntityValidator.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java b/spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java rename to spring-reactive-modules/spring-reactive-2/src/main/java/com/baeldung/validations/functional/validators/OtherEntityValidator.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/main/resources/application-assets-custom-location.properties b/spring-reactive-modules/spring-reactive-2/src/main/resources/application-assets-custom-location.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/main/resources/application-assets-custom-location.properties rename to spring-reactive-modules/spring-reactive-2/src/main/resources/application-assets-custom-location.properties diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/resources/files/hello.txt b/spring-reactive-modules/spring-reactive-2/src/main/resources/files/hello.txt similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/resources/files/hello.txt rename to spring-reactive-modules/spring-reactive-2/src/main/resources/files/hello.txt diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/resources/files/test/test.txt b/spring-reactive-modules/spring-reactive-2/src/main/resources/files/test/test.txt similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/resources/files/test/test.txt rename to spring-reactive-modules/spring-reactive-2/src/main/resources/files/test/test.txt diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/files/test/test.txt b/spring-reactive-modules/spring-reactive-2/src/main/resources/resources/test/test.txt similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/resources/files/test/test.txt rename to spring-reactive-modules/spring-reactive-2/src/main/resources/resources/test/test.txt diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/backpressure/BackpressureUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/backpressure/BackpressureUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/backpressure/BackpressureUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/backpressure/BackpressureUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/FluxUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/FluxUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/reactive/serversentsevents/ServiceSentEventLiveTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/serversentsevents/ServiceSentEventLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/reactive/serversentsevents/ServiceSentEventLiveTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/serversentsevents/ServiceSentEventLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java similarity index 97% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java index a77a67c6ba..113376318e 100644 --- a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java @@ -108,7 +108,7 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { } @Test - public void givenRouter_whenAccess_thenGot() throws Exception { + public void givenRouter_whenAccess_thenGot() { client.get() .uri("/resources/test/test.txt") .exchange() diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/PostExecutionUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/StepByStepUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/StepByStepUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/StepByStepUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/StepByStepUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/TestingTestPublisherUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/TestingTestPublisherUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/TestingTestPublisherUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/TestingTestPublisherUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/TimeBasedUnitTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/TimeBasedUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/stepverifier/TimeBasedUnitTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/stepverifier/TimeBasedUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java b/spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java rename to spring-reactive-modules/spring-reactive-2/src/test/java/com/baeldung/validations/functional/FunctionalEndpointValidationsLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/resources/assets/index.html b/spring-reactive-modules/spring-reactive-2/src/test/resources/assets/index.html similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/resources/assets/index.html rename to spring-reactive-modules/spring-reactive-2/src/test/resources/assets/index.html diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/resources/img/example-image.png b/spring-reactive-modules/spring-reactive-2/src/test/resources/img/example-image.png similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/resources/img/example-image.png rename to spring-reactive-modules/spring-reactive-2/src/test/resources/img/example-image.png diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive-2/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive-2/src/test/resources/logback-test.xml diff --git a/spring-reactive-modules/spring-5-reactive-2/src/test/resources/public/index.html b/spring-reactive-modules/spring-reactive-2/src/test/resources/public/index.html similarity index 100% rename from spring-reactive-modules/spring-5-reactive-2/src/test/resources/public/index.html rename to spring-reactive-modules/spring-reactive-2/src/test/resources/public/index.html diff --git a/spring-reactive-modules/spring-5-reactive-3/.gitignore b/spring-reactive-modules/spring-reactive-3/.gitignore similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/.gitignore rename to spring-reactive-modules/spring-reactive-3/.gitignore diff --git a/spring-reactive-modules/spring-reactive-3/README.md b/spring-reactive-modules/spring-reactive-3/README.md new file mode 100644 index 0000000000..4dbaa93226 --- /dev/null +++ b/spring-reactive-modules/spring-reactive-3/README.md @@ -0,0 +1,11 @@ +## Spring 5 Reactive Project + +This module contains articles about reactive Spring Boot. + +- [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) +- [Reading Flux Into a Single InputStream Using Spring Reactive WebClient](https://www.baeldung.com/spring-reactive-read-flux-into-inputstream) +- [Cancel an Ongoing Flux in Spring WebFlux](https://www.baeldung.com/spring-webflux-cancel-flux) +- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators) +- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets) +- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive) +- More articles: [[<-- prev]](../spring-reactive-2) diff --git a/spring-reactive-modules/spring-5-reactive-3/pom.xml b/spring-reactive-modules/spring-reactive-3/pom.xml similarity index 77% rename from spring-reactive-modules/spring-5-reactive-3/pom.xml rename to spring-reactive-modules/spring-reactive-3/pom.xml index d33b63e921..96f23f1339 100644 --- a/spring-reactive-modules/spring-5-reactive-3/pom.xml +++ b/spring-reactive-modules/spring-reactive-3/pom.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-3 + spring-reactive-3 0.0.1-SNAPSHOT spring-5-reactive-3 jar @@ -47,6 +47,22 @@ org.projectlombok lombok + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.session + spring-session-core + + + org.springframework.session + spring-session-data-redis + diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/webapp/WEB-INF/web.xml b/spring-reactive-modules/spring-reactive-3/src/main/WEB-INF/web.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/webapp/WEB-INF/web.xml rename to spring-reactive-modules/spring-reactive-3/src/main/WEB-INF/web.xml diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/databuffer/DataBufferToInputStream.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/Actor.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/Actor.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/Actor.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/Actor.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FormHandler.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FormHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FormHandler.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FormHandler.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FunctionalWebApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/FunctionalWebApplication.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/IndexRewriteFilter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/IndexRewriteFilter.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/RootServlet.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/RootServlet.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/RootServlet.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/functional/RootServlet.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/DownstreamServiceHealthIndicator.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/DownstreamServiceHealthIndicator.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/DownstreamServiceHealthIndicator.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/DownstreamServiceHealthIndicator.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/FeaturesEndpoint.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/FeaturesEndpoint.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/FeaturesEndpoint.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/FeaturesEndpoint.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/InfoWebEndpointExtension.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/InfoWebEndpointExtension.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/InfoWebEndpointExtension.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/InfoWebEndpointExtension.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java similarity index 73% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java index 600bff5948..19b83ee651 100644 --- a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java +++ b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/reactive/actuator/Spring5ReactiveApplication.java @@ -2,8 +2,10 @@ package com.baeldung.reactive.actuator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication +@ComponentScan(basePackages = "com.baeldung.reactive.actuator") public class Spring5ReactiveApplication { public static void main(String[] args) { diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webflux/logging/WebFluxLoggingExample.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/webflux/logging/WebFluxLoggingExample.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webflux/logging/WebFluxLoggingExample.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/webflux/logging/WebFluxLoggingExample.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/Application.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/Application.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/Application.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/Application.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/RedisConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/RedisConfig.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/SessionConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/SessionConfig.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java similarity index 89% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java index 964b544916..041c37e7fc 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java +++ b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java @@ -4,7 +4,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.config.EnableWebFlux; -import org.springframework.web.reactive.config.ResourceHandlerRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer; @Configuration diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/controller/SessionController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/controller/SessionController.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/transfer/CustomResponse.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websession/transfer/CustomResponse.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/Event.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/Event.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/Event.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/Event.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/WebSocketController.java similarity index 92% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java rename to spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/WebSocketController.java index bf4a463ae6..0c8f9debc9 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java +++ b/spring-reactive-modules/spring-reactive-3/src/main/java/com/baeldung/websocket/WebSocketController.java @@ -6,8 +6,6 @@ import org.slf4j.LoggerFactory; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; @ServerEndpoint("/event-emitter") public class WebSocketController { diff --git a/spring-reactive-modules/spring-reactive-3/src/main/resources/application.properties b/spring-reactive-modules/spring-reactive-3/src/main/resources/application.properties new file mode 100644 index 0000000000..767f8106dd --- /dev/null +++ b/spring-reactive-modules/spring-reactive-3/src/main/resources/application.properties @@ -0,0 +1,13 @@ +# application properties +management.endpoints.web.exposure.include=* + +info.app.name=Spring Boot 2 actuator Application +management.endpoint.health.group.custom.include=diskSpace,ping +management.endpoint.health.group.custom.show-components=always +management.endpoint.health.group.custom.show-details=always +management.endpoint.health.group.custom.status.http-mapping.up=207 + +spring.main.allow-bean-definition-overriding=true + +logging.level.root=INFO +server.tomcat.max-keep-alive-requests=1 \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/files/hello.txt b/spring-reactive-modules/spring-reactive-3/src/main/resources/files/hello.txt similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/resources/files/hello.txt rename to spring-reactive-modules/spring-reactive-3/src/main/resources/files/hello.txt diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-3/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-3/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/resources/static/client-websocket.html b/spring-reactive-modules/spring-reactive-3/src/main/resources/static/client-websocket.html similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/resources/static/client-websocket.html rename to spring-reactive-modules/spring-reactive-3/src/main/resources/static/client-websocket.html diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/SpringContextTest.java similarity index 75% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/SpringContextTest.java index bedb30fcaa..2dbd45349f 100644 --- a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/SpringContextTest.java +++ b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/SpringContextTest.java @@ -5,10 +5,10 @@ import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.reactive.Spring5ReactiveApplication; +import com.baeldung.functional.FunctionalWebApplication; @RunWith(SpringRunner.class) -@SpringBootTest(classes = Spring5ReactiveApplication.class) +@SpringBootTest(classes = FunctionalWebApplication.class) public class SpringContextTest { @Test diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/cancelflux/CancelFluxUnitTest.java b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/cancelflux/CancelFluxUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/cancelflux/CancelFluxUnitTest.java rename to spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/cancelflux/CancelFluxUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java rename to spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java rename to spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java similarity index 87% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java rename to spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java index 94979a18ca..79c694e6b9 100644 --- a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive-3/src/test/java/com/baeldung/reactive/actuator/ActuatorInfoIntegrationTest.java @@ -9,8 +9,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; -import java.io.IOException; - import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @@ -21,13 +19,13 @@ public class ActuatorInfoIntegrationTest { private TestRestTemplate restTemplate; @Test - public void whenGetInfo_thenReturns200() throws IOException { + public void whenGetInfo_thenReturns200() { final ResponseEntity responseEntity = this.restTemplate.getForEntity("/actuator/info", String.class); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); } @Test - public void whenFeatures_thenReturns200() throws IOException { + public void whenFeatures_thenReturns200() { final ResponseEntity responseEntity = this.restTemplate.getForEntity("/actuator/features", String.class); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); } diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/resources/baeldung-weekly.png b/spring-reactive-modules/spring-reactive-3/src/test/resources/baeldung-weekly.png similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/test/resources/baeldung-weekly.png rename to spring-reactive-modules/spring-reactive-3/src/test/resources/baeldung-weekly.png diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive-3/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive-3/src/test/resources/logback-test.xml diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json b/spring-reactive-modules/spring-reactive-3/src/test/resources/user-response.json similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/test/resources/user-response.json rename to spring-reactive-modules/spring-reactive-3/src/test/resources/user-response.json diff --git a/spring-reactive-modules/spring-5-reactive-client-2/README.md b/spring-reactive-modules/spring-reactive-client-2/README.md similarity index 87% rename from spring-reactive-modules/spring-5-reactive-client-2/README.md rename to spring-reactive-modules/spring-reactive-client-2/README.md index 04fe3c8f42..6b6a480f46 100644 --- a/spring-reactive-modules/spring-5-reactive-client-2/README.md +++ b/spring-reactive-modules/spring-reactive-client-2/README.md @@ -8,4 +8,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles - [Limiting the Requests per Second With WebClient](https://www.baeldung.com/spring-webclient-limit-requests-per-second) - [Stream Large Byte[] to File With WebClient](https://www.baeldung.com/webclient-stream-large-byte-array-to-file) -- More articles: [[<-- prev]](../spring-5-reactive-client) +- More articles: [[<-- prev]](../spring-reactive-client) diff --git a/spring-reactive-modules/spring-5-reactive-client-2/pom.xml b/spring-reactive-modules/spring-reactive-client-2/pom.xml similarity index 94% rename from spring-reactive-modules/spring-5-reactive-client-2/pom.xml rename to spring-reactive-modules/spring-reactive-client-2/pom.xml index e86134badc..5d5f3ebc2e 100644 --- a/spring-reactive-modules/spring-5-reactive-client-2/pom.xml +++ b/spring-reactive-modules/spring-reactive-client-2/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-client-2 - spring-5-reactive-client-2 + spring-reactive-client-2 + spring-reactive-client-2 jar - spring 5 sample project about new features + spring boot sample project about new features com.baeldung.spring.reactive @@ -93,10 +93,6 @@ org.apache.maven.plugins maven-compiler-plugin - - 1.8 - 1.8 - diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/LimitRequestsApp.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/LimitRequestsApp.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/LimitRequestsApp.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/LimitRequestsApp.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/DelayElements.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/DelayElements.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/DelayElements.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/DelayElements.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/GuavaRateLimit.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/GuavaRateLimit.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/GuavaRateLimit.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/GuavaRateLimit.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/LimitConcurrency.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/LimitConcurrency.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/LimitConcurrency.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/LimitConcurrency.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/Resilience4jRateLimit.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/Resilience4jRateLimit.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/Resilience4jRateLimit.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/Resilience4jRateLimit.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/ZipWithInterval.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/ZipWithInterval.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/ZipWithInterval.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/ZipWithInterval.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/Client.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/Client.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/Client.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/Client.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/RandomConsumer.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/RandomConsumer.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/RandomConsumer.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/client/utils/RandomConsumer.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/Concurrency.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/Concurrency.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/Concurrency.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/Concurrency.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/RandomController.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/RandomController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/RandomController.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/limitrequests/server/RandomController.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java b/spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java rename to spring-reactive-modules/spring-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/application.properties b/spring-reactive-modules/spring-reactive-client-2/src/main/resources/application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/application.properties rename to spring-reactive-modules/spring-reactive-client-2/src/main/resources/application.properties diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-client-2/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-client-2/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh b/spring-reactive-modules/spring-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh old mode 100755 new mode 100644 similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh rename to spring-reactive-modules/spring-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/run.sh b/spring-reactive-modules/spring-reactive-client-2/src/main/resources/streamlargefile/run.sh old mode 100755 new mode 100644 similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/run.sh rename to spring-reactive-modules/spring-reactive-client-2/src/main/resources/streamlargefile/run.sh diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/limitrequests/RandomControllerLiveTest.java b/spring-reactive-modules/spring-reactive-client-2/src/test/java/com/baeldung/limitrequests/RandomControllerLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/limitrequests/RandomControllerLiveTest.java rename to spring-reactive-modules/spring-reactive-client-2/src/test/java/com/baeldung/limitrequests/RandomControllerLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java b/spring-reactive-modules/spring-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java rename to spring-reactive-modules/spring-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive-client-2/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client-2/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive-client-2/src/test/resources/logback-test.xml diff --git a/spring-reactive-modules/spring-5-reactive-client/.gitignore b/spring-reactive-modules/spring-reactive-client/.gitignore similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/.gitignore rename to spring-reactive-modules/spring-reactive-client/.gitignore diff --git a/spring-reactive-modules/spring-5-reactive-client/README.md b/spring-reactive-modules/spring-reactive-client/README.md similarity index 82% rename from spring-reactive-modules/spring-5-reactive-client/README.md rename to spring-reactive-modules/spring-reactive-client/README.md index f1793070b3..ae72dc0e4a 100644 --- a/spring-reactive-modules/spring-5-reactive-client/README.md +++ b/spring-reactive-modules/spring-reactive-client/README.md @@ -9,8 +9,8 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls) - [Simultaneous Spring WebClient Calls](https://www.baeldung.com/spring-webclient-simultaneous-calls) - [Mocking a WebClient in Spring](https://www.baeldung.com/spring-mocking-webclient) -- [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters) - [Get List of JSON Objects with WebClient](https://www.baeldung.com/spring-webclient-json-list) - [Upload a File with WebClient](https://www.baeldung.com/spring-webclient-upload-file) - [How to Get Response Body When Testing the Status Code in WebFlux WebClient](https://www.baeldung.com/spring-webclient-get-response-body) -- More articles: [[next -->]](../spring-5-reactive-client-2) +- [Spring Boot FeignClient vs. WebClient](https://www.baeldung.com/spring-boot-feignclient-vs-webclient) +- More articles: [[next -->]](../spring-reactive-client-2) diff --git a/spring-reactive-modules/spring-5-reactive-client/pom.xml b/spring-reactive-modules/spring-reactive-client/pom.xml similarity index 93% rename from spring-reactive-modules/spring-5-reactive-client/pom.xml rename to spring-reactive-modules/spring-reactive-client/pom.xml index a0e5f7794e..94134e5271 100644 --- a/spring-reactive-modules/spring-5-reactive-client/pom.xml +++ b/spring-reactive-modules/spring-reactive-client/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-client - spring-5-reactive-client + spring-reactive-client + spring-reactive-client jar - spring 5 sample project about new features + spring boot sample project about new features com.baeldung.spring.reactive @@ -32,8 +32,9 @@ spring-boot-starter-webflux - org.springframework.boot - spring-boot-starter-security + org.springframework.cloud + spring-cloud-starter-openfeign + ${spring-cloud-starter-openfeign.version} org.projectreactor @@ -176,13 +177,12 @@ 1.0.1.RELEASE - 1.1.3 - 1.0 1.0 1.1.6 4.0.1 3.5.3 2.26.0 + 3.1.4 \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/enums/Role.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/enums/Role.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/enums/Role.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/enums/Role.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Employee.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/model/Employee.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Employee.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/model/Employee.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/EmployeeService.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/service/EmployeeService.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/EmployeeService.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/service/EmployeeService.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Client.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Client.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Client.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Client.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Item.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Item.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Item.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/Item.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/User.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/User.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/User.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/User.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/UserWithItem.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/UserWithItem.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/UserWithItem.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/reactive/webclient/simultaneous/UserWithItem.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/Product.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/Product.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/Product.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/Product.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsFeignClient.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/ProductsFeignClient.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsFeignClient.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/ProductsFeignClient.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebClientApplication.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/WebClientApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebClientApplication.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/WebClientApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebController.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/WebController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebController.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/WebController.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerService.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerService.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerService.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerService.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerServiceImpl.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerServiceImpl.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerServiceImpl.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/ReaderConsumerServiceImpl.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Book.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/model/Book.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Book.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/model/Book.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Reader.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/model/Reader.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Reader.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/json/model/Reader.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/WebClientStatusCodeHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomBadRequestException.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomBadRequestException.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomBadRequestException.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomBadRequestException.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomServerErrorException.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomServerErrorException.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomServerErrorException.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/status/exception/CustomServerErrorException.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/timeout/WebClientTimeoutProvider.java b/spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/timeout/WebClientTimeoutProvider.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/timeout/WebClientTimeoutProvider.java rename to spring-reactive-modules/spring-reactive-client/src/main/java/com/baeldung/webclient/timeout/WebClientTimeoutProvider.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/resources/application.properties b/spring-reactive-modules/spring-reactive-client/src/main/resources/application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/resources/application.properties rename to spring-reactive-modules/spring-reactive-client/src/main/resources/application.properties diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-client/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-client/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/webapp/WEB-INF/web.xml b/spring-reactive-modules/spring-reactive-client/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/webapp/WEB-INF/web.xml rename to spring-reactive-modules/spring-reactive-client/src/main/webapp/WEB-INF/web.xml diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceUnitTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceUnitTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/EmployeeServiceUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/webclient/simultaneous/ClientIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/webclient/simultaneous/ClientIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/webclient/simultaneous/ClientIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/reactive/webclient/simultaneous/ClientIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/WebClientStatusCodeHandlerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/json/ReaderConsumerServiceImplUnitTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/json/ReaderConsumerServiceImplUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/json/ReaderConsumerServiceImplUnitTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/json/ReaderConsumerServiceImplUnitTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/timeout/WebClientTimeoutIntegrationTest.java b/spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/timeout/WebClientTimeoutIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/timeout/WebClientTimeoutIntegrationTest.java rename to spring-reactive-modules/spring-reactive-client/src/test/java/com/baeldung/webclient/timeout/WebClientTimeoutIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive-client/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-client/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive-client/src/test/resources/logback-test.xml diff --git a/spring-reactive-modules/spring-5-data-reactive/README.md b/spring-reactive-modules/spring-reactive-data-couchbase/README.md similarity index 62% rename from spring-reactive-modules/spring-5-data-reactive/README.md rename to spring-reactive-modules/spring-reactive-data-couchbase/README.md index ecb6d01267..e38ef10562 100644 --- a/spring-reactive-modules/spring-5-data-reactive/README.md +++ b/spring-reactive-modules/spring-reactive-data-couchbase/README.md @@ -1,10 +1,9 @@ ## Spring Data Reactive Project -This module contains articles about reactive Spring 5 Data +This module contains articles about reactive Spring Data Couchbase ### The Course The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles -- [A Quick Look at R2DBC with Spring Data](https://www.baeldung.com/spring-data-r2dbc) - [Spring Data Reactive Repositories with Couchbase](https://www.baeldung.com/spring-data-reactive-couchbase) diff --git a/spring-reactive-modules/spring-5-data-reactive/pom.xml b/spring-reactive-modules/spring-reactive-data-couchbase/pom.xml similarity index 83% rename from spring-reactive-modules/spring-5-data-reactive/pom.xml rename to spring-reactive-modules/spring-reactive-data-couchbase/pom.xml index e4d3aeeddd..52b10f39d9 100644 --- a/spring-reactive-modules/spring-5-data-reactive/pom.xml +++ b/spring-reactive-modules/spring-reactive-data-couchbase/pom.xml @@ -1,10 +1,10 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-data-reactive - spring-5-data-reactive + spring-reactive-data-couchbase + spring-data-couchbase jar @@ -62,29 +62,11 @@ spring-boot-starter-test test - - org.springframework.boot - spring-boot-starter-webflux - org.springframework spring-tx ${spring-tx.version} - - org.springframework.data - spring-data-r2dbc - ${spring-data-r2dbc.version} - - - io.r2dbc - r2dbc-h2 - ${r2dbc-h2.version} - - - com.h2database - h2 - org.apache.httpcomponents httpclient @@ -152,8 +134,6 @@ 5.2.2.RELEASE - 1.0.0.RELEASE - 0.8.1.RELEASE 4.5.2 1.5.23 3.3.1.RELEASE diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java index 4e5bf9d5dc..0ca7c9a8d1 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/ReactiveCouchbaseApplication.java @@ -10,4 +10,4 @@ public class ReactiveCouchbaseApplication { public static void main(String[] args) { SpringApplication.run(ReactiveCouchbaseApplication.class, args); } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java index 81f19eebd6..cc9540eecb 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/CouchbaseProperties.java @@ -40,4 +40,4 @@ public class CouchbaseProperties { public int getPort() { return port; } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java index 059bd36cae..7ba12db2c6 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/N1QLReactiveCouchbaseConfiguration.java @@ -12,4 +12,4 @@ public class N1QLReactiveCouchbaseConfiguration extends ReactiveCouchbaseConfigu public N1QLReactiveCouchbaseConfiguration(CouchbaseProperties couchbaseProperties) { super(couchbaseProperties); } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java index a51b19ee22..1816082f7c 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ReactiveCouchbaseConfiguration.java @@ -45,4 +45,4 @@ public abstract class ReactiveCouchbaseConfiguration extends AbstractReactiveCou public IndexManager couchbaseIndexManager() { return new IndexManager(true, true, false); } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java index 9b4d9b0319..578a03ae19 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/configuration/ViewReactiveCouchbaseConfiguration.java @@ -10,4 +10,4 @@ public class ViewReactiveCouchbaseConfiguration extends ReactiveCouchbaseConfigu public ViewReactiveCouchbaseConfiguration(CouchbaseProperties couchbaseProperties) { super(couchbaseProperties); } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/Person.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/Person.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/Person.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/Person.java index 285de34df8..5a1b1eec18 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/Person.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/Person.java @@ -40,4 +40,4 @@ public class Person { public int hashCode() { return Objects.hash(id, firstName); } -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java index 6f73a77ceb..e78316e218 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepository.java @@ -13,4 +13,4 @@ import java.util.UUID; public interface N1QLPersonRepository extends ReactiveCrudRepository { Flux findAllByFirstName(final String firstName); -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java index 57dd149425..1225ed914a 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepository.java @@ -10,4 +10,4 @@ import java.util.UUID; @Repository @N1qlPrimaryIndexed public interface N1QLSortingPersonRepository extends ReactiveSortingRepository { -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java index 06c47c2393..4b3f0a7f1c 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepository.java @@ -17,4 +17,4 @@ public interface ViewPersonRepository extends ReactiveCrudRepository findByFirstName(String firstName); -} +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/resources/couchbase.properties b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/resources/couchbase.properties similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/resources/couchbase.properties rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/resources/couchbase.properties diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-data-couchbase/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-data-couchbase/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java similarity index 99% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java index 2a09fce4b0..082ad5061b 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/CouchbaseMockConfiguration.java @@ -1,16 +1,18 @@ package com.baeldung.couchbase.domain.repository; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collections; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.springframework.boot.test.context.TestConfiguration; + import com.baeldung.couchbase.configuration.CouchbaseProperties; import com.couchbase.mock.Bucket; import com.couchbase.mock.BucketConfiguration; import com.couchbase.mock.CouchbaseMock; -import org.springframework.boot.test.context.TestConfiguration; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.Collections; @TestConfiguration public class CouchbaseMockConfiguration { diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java similarity index 96% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java index c8dbbf429e..51bca948c0 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLPersonRepositoryLiveTest.java @@ -1,16 +1,19 @@ package com.baeldung.couchbase.domain.repository.n1ql; -import com.baeldung.couchbase.domain.Person; +import java.util.UUID; + 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 com.baeldung.couchbase.domain.Person; +import com.baeldung.couchbase.domain.repository.n1ql.N1QLPersonRepository; + import reactor.core.publisher.Flux; import reactor.test.StepVerifier; -import java.util.UUID; - @RunWith(SpringRunner.class) @SpringBootTest(properties = {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration"}) public class N1QLPersonRepositoryLiveTest { diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java similarity index 96% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java index 8c6ce137f1..dbc353a94b 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/n1ql/N1QLSortingPersonRepositoryLiveTest.java @@ -1,17 +1,20 @@ package com.baeldung.couchbase.domain.repository.n1ql; -import com.baeldung.couchbase.domain.Person; +import java.util.UUID; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.Sort; import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.couchbase.domain.Person; +import com.baeldung.couchbase.domain.repository.n1ql.N1QLSortingPersonRepository; + import reactor.core.publisher.Flux; import reactor.test.StepVerifier; -import java.util.UUID; - @RunWith(SpringRunner.class) @SpringBootTest(properties = {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration"}) public class N1QLSortingPersonRepositoryLiveTest { diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java similarity index 97% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java rename to spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java index 15688e1b80..038d4dec31 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive-data-couchbase/src/test/java/com/baeldung/couchbase/domain/repository/view/ViewPersonRepositoryIntegrationTest.java @@ -1,21 +1,22 @@ package com.baeldung.couchbase.domain.repository.view; +import java.util.UUID; + +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 com.baeldung.couchbase.configuration.CouchbaseProperties; import com.baeldung.couchbase.configuration.ViewReactiveCouchbaseConfiguration; import com.baeldung.couchbase.domain.Person; import com.baeldung.couchbase.domain.repository.CouchbaseMockConfiguration; -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.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import java.util.UUID; - @RunWith(SpringRunner.class) @SpringBootTest(properties = { "spring.couchbase.port=10010", "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration" }, classes = { CouchbaseMockConfiguration.class, ViewReactiveCouchbaseConfiguration.class, CouchbaseProperties.class }) diff --git a/spring-reactive-modules/spring-5-data-reactive-2/README.md b/spring-reactive-modules/spring-reactive-data/README.md similarity index 62% rename from spring-reactive-modules/spring-5-data-reactive-2/README.md rename to spring-reactive-modules/spring-reactive-data/README.md index ffc664b8af..259ab0be62 100644 --- a/spring-reactive-modules/spring-5-data-reactive-2/README.md +++ b/spring-reactive-modules/spring-reactive-data/README.md @@ -1,10 +1,11 @@ ## Spring Data Reactive Project -This module contains articles about reactive Spring 5 Data +This module contains articles about reactive Spring Boot Data ### The Course The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles +- [A Quick Look at R2DBC with Spring Data](https://www.baeldung.com/spring-data-r2dbc) - [Pagination in Spring Webflux and Spring Data Reactive](https://www.baeldung.com/spring-data-webflux-pagination) diff --git a/spring-reactive-modules/spring-5-data-reactive-2/pom.xml b/spring-reactive-modules/spring-reactive-data/pom.xml similarity index 80% rename from spring-reactive-modules/spring-5-data-reactive-2/pom.xml rename to spring-reactive-modules/spring-reactive-data/pom.xml index e5447ac038..03ea440b4f 100644 --- a/spring-reactive-modules/spring-5-data-reactive-2/pom.xml +++ b/spring-reactive-modules/spring-reactive-data/pom.xml @@ -1,10 +1,10 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-data-reactive-2 - spring-5-data-reactive-2 + spring-reactive-data + spring-reactive-data-2 jar @@ -13,10 +13,7 @@ 1.0.0-SNAPSHOT - - 8 - 8 UTF-8 @@ -57,11 +54,6 @@ lombok true - - org.springframework.boot - spring-boot-starter-test - test - io.projectreactor reactor-test @@ -72,6 +64,10 @@ validation-api 2.0.1.Final + + io.r2dbc + r2dbc-h2 + \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/PaginationApplication.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/PaginationApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/PaginationApplication.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/PaginationApplication.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/model/Product.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/model/Product.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/model/Product.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/model/Product.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/repository/ProductRepository.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/repository/ProductRepository.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/repository/ProductRepository.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/pagination/repository/ProductRepository.java diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/model/Player.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/model/Player.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/model/Player.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/model/Player.java diff --git a/spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java b/spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java rename to spring-reactive-modules/spring-reactive-data/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/init.sql b/spring-reactive-modules/spring-reactive-data/src/main/resources/init.sql similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/init.sql rename to spring-reactive-modules/spring-reactive-data/src/main/resources/init.sql diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-data/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-data/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-data-reactive-2/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java rename to spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java b/spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java similarity index 93% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java rename to spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java index 1af570587e..b5e859ae2f 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java @@ -1,6 +1,7 @@ package com.baeldung.r2dbc; +import com.baeldung.r2dbc.configuration.R2DBCConfiguration; import com.baeldung.r2dbc.model.Player; import com.baeldung.r2dbc.repository.PlayerRepository; import io.r2dbc.h2.H2ConnectionFactory; @@ -9,7 +10,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.test.context.junit4.SpringRunner; import reactor.core.publisher.Flux; import reactor.core.publisher.Hooks; @@ -20,7 +21,7 @@ import java.util.Arrays; import java.util.List; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = R2DBCConfiguration.class) public class R2dbcApplicationIntegrationTest { @@ -43,7 +44,7 @@ public class R2dbcApplicationIntegrationTest { "DROP TABLE IF EXISTS player;", "CREATE table player (id INT AUTO_INCREMENT NOT NULL, name VARCHAR2, age INT NOT NULL);"); - statements.forEach(it -> client.execute(it) // + statements.forEach(it -> client.sql(it) // .fetch() // .rowsUpdated() // .as(StepVerifier::create) // diff --git a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/SpringContextTest.java similarity index 85% rename from spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/SpringContextTest.java index dc7bcd1e37..facefd3144 100644 --- a/spring-reactive-modules/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java +++ b/spring-reactive-modules/spring-reactive-data/src/test/java/com/baeldung/r2dbc/SpringContextTest.java @@ -1,12 +1,10 @@ -package com.baeldung; +package com.baeldung.r2dbc; 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.r2dbc.R2dbcApplication; - @RunWith(SpringRunner.class) @SpringBootTest(classes = R2dbcApplication.class) public class SpringContextTest { diff --git a/spring-reactive-modules/spring-reactive-exceptions/README.md b/spring-reactive-modules/spring-reactive-exceptions/README.md index fc1a31b26f..f10774d188 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/README.md +++ b/spring-reactive-modules/spring-reactive-exceptions/README.md @@ -1,3 +1,3 @@ ## Relevant Articles - [How to Resolve Spring Webflux DataBufferLimitException](https://www.baeldung.com/spring-webflux-databufferlimitexception) -- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) +- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-filters/.gitignore b/spring-reactive-modules/spring-reactive-filters/.gitignore similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/.gitignore rename to spring-reactive-modules/spring-reactive-filters/.gitignore diff --git a/spring-reactive-modules/spring-5-reactive-filters/README.md b/spring-reactive-modules/spring-reactive-filters/README.md similarity index 76% rename from spring-reactive-modules/spring-5-reactive-filters/README.md rename to spring-reactive-modules/spring-reactive-filters/README.md index 815ca35442..9d73eae9ee 100644 --- a/spring-reactive-modules/spring-5-reactive-filters/README.md +++ b/spring-reactive-modules/spring-reactive-filters/README.md @@ -8,3 +8,4 @@ The "REST With Spring" Classes: https://bit.ly/restwithspring ### Relevant Articles - [Spring WebFlux Filters](https://www.baeldung.com/spring-webflux-filters) +- [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters) diff --git a/spring-reactive-modules/spring-5-reactive-filters/pom.xml b/spring-reactive-modules/spring-reactive-filters/pom.xml similarity index 81% rename from spring-reactive-modules/spring-5-reactive-filters/pom.xml rename to spring-reactive-modules/spring-reactive-filters/pom.xml index c9503d631a..67f7a11cb4 100644 --- a/spring-reactive-modules/spring-5-reactive-filters/pom.xml +++ b/spring-reactive-modules/spring-reactive-filters/pom.xml @@ -3,11 +3,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-filters + spring-reactive-filters 0.0.1-SNAPSHOT - spring-5-reactive-filters + spring-reactive-filters jar - spring 5 sample project about new features + spring boot sample project about new features com.baeldung.spring.reactive @@ -49,6 +49,12 @@ netty-all test + + com.github.tomakehurst + wiremock-standalone + ${wiremock-standalone.version} + test + @@ -65,4 +71,8 @@ + + 2.26.0 + + \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/filter/WebClientFilters.java b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/WebClientFilters.java similarity index 98% rename from spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/filter/WebClientFilters.java rename to spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/WebClientFilters.java index c98caf67b4..34fff3c4cb 100644 --- a/spring-reactive-modules/spring-5-reactive-client/src/main/java/com/baeldung/webclient/filter/WebClientFilters.java +++ b/spring-reactive-modules/spring-reactive-filters/src/main/java/com/baeldung/reactive/filters/WebClientFilters.java @@ -1,4 +1,4 @@ -package com.baeldung.webclient.filter; +package com.baeldung.reactive.filters; import java.io.PrintStream; import java.net.URI; diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/application.properties b/spring-reactive-modules/spring-reactive-filters/src/main/resources/application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/main/resources/application.properties rename to spring-reactive-modules/spring-reactive-filters/src/main/resources/application.properties diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-filters/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/resources/logback.xml rename to spring-reactive-modules/spring-reactive-filters/src/main/resources/logback.xml diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/filter/FilteredWebClientUnitTest.java b/spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/FilteredWebClientUnitTest.java similarity index 95% rename from spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/filter/FilteredWebClientUnitTest.java rename to spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/FilteredWebClientUnitTest.java index 675cd03d10..1350db0752 100644 --- a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/webclient/filter/FilteredWebClientUnitTest.java +++ b/spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/FilteredWebClientUnitTest.java @@ -1,8 +1,8 @@ -package com.baeldung.webclient.filter; +package com.baeldung.reactive.filters; -import static com.baeldung.webclient.filter.WebClientFilters.countingFilter; -import static com.baeldung.webclient.filter.WebClientFilters.loggingFilter; -import static com.baeldung.webclient.filter.WebClientFilters.urlModifyingFilter; +import static com.baeldung.reactive.filters.WebClientFilters.countingFilter; +import static com.baeldung.reactive.filters.WebClientFilters.loggingFilter; +import static com.baeldung.reactive.filters.WebClientFilters.urlModifyingFilter; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.get; diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java b/spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java rename to spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java rename to spring-reactive-modules/spring-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/README.md b/spring-reactive-modules/spring-reactive-oauth/README.md similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/README.md rename to spring-reactive-modules/spring-reactive-oauth/README.md diff --git a/spring-reactive-modules/spring-5-reactive-oauth/pom.xml b/spring-reactive-modules/spring-reactive-oauth/pom.xml similarity index 96% rename from spring-reactive-modules/spring-5-reactive-oauth/pom.xml rename to spring-reactive-modules/spring-reactive-oauth/pom.xml index 9c237607ba..9d2dbf6126 100644 --- a/spring-reactive-modules/spring-5-reactive-oauth/pom.xml +++ b/spring-reactive-modules/spring-reactive-oauth/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.reactive.oauth - spring-5-reactive-oauth + spring-reactive-oauth 1.0.0-SNAPSHOT - spring-5-reactive-oauth + spring-reactive-oauth jar WebFlux and Spring Security OAuth diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/SecurityConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/SecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/SecurityConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/SecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/MainController.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/MainController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/MainController.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/MainController.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/dto/Foo.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/dto/Foo.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/dto/Foo.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/web/dto/Foo.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientLoginApplication.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientLoginApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientLoginApplication.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientLoginApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java b/spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java rename to spring-reactive-modules/spring-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/application.yml b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/application.yml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/application.yml rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/application.yml diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/default-application.yml b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/default-application.yml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/default-application.yml rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/default-application.yml diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties b/spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties rename to spring-reactive-modules/spring-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthIntegrationTest.java b/spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthIntegrationTest.java rename to spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java b/spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java rename to spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java b/spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java rename to spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java b/spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java rename to spring-reactive-modules/spring-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java diff --git a/spring-reactive-modules/spring-5-reactive-oauth/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive-oauth/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive-oauth/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive-oauth/src/test/resources/logback-test.xml diff --git a/spring-reactive-modules/spring-5-reactive-security/.gitignore b/spring-reactive-modules/spring-reactive-security/.gitignore similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/.gitignore rename to spring-reactive-modules/spring-reactive-security/.gitignore diff --git a/spring-reactive-modules/spring-5-reactive-security/README.md b/spring-reactive-modules/spring-reactive-security/README.md similarity index 85% rename from spring-reactive-modules/spring-5-reactive-security/README.md rename to spring-reactive-modules/spring-reactive-security/README.md index 37f999648c..a25fa3728b 100644 --- a/spring-reactive-modules/spring-5-reactive-security/README.md +++ b/spring-reactive-modules/spring-reactive-security/README.md @@ -7,6 +7,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles -- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators) - [Guide to the AuthenticationManagerResolver in Spring Security](https://www.baeldung.com/spring-security-authenticationmanagerresolver) - [Spring Webflux and CORS](https://www.baeldung.com/spring-webflux-cors) diff --git a/spring-reactive-modules/spring-5-reactive-security/pom.xml b/spring-reactive-modules/spring-reactive-security/pom.xml similarity index 85% rename from spring-reactive-modules/spring-5-reactive-security/pom.xml rename to spring-reactive-modules/spring-reactive-security/pom.xml index e455940d83..cf34b21083 100644 --- a/spring-reactive-modules/spring-5-reactive-security/pom.xml +++ b/spring-reactive-modules/spring-reactive-security/pom.xml @@ -3,11 +3,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-5-reactive-security + spring-reactive-security 0.0.1-SNAPSHOT - spring-5-reactive-security + spring-reactive-security jar - spring 5 security sample project about new features + spring boot security sample project about new features com.baeldung.spring.reactive @@ -37,10 +37,6 @@ javax.json.bind javax.json.bind-api - - org.springframework.boot - spring-boot-starter-actuator - org.projectlombok lombok @@ -66,10 +62,6 @@ spring-boot-devtools runtime - - org.springframework - spring-test - org.springframework.boot spring-boot-starter-test @@ -84,12 +76,12 @@ io.reactivex.rxjava2 rxjava - ${rxjava-version} + ${rxjava.version} io.projectreactor reactor-test - ${project-reactor-test} + ${project-reactor-test.version} test @@ -118,11 +110,11 @@ 1.0.1.RELEASE - 2.1.12 + 2.1.12 1.1.3 1.0 1.0 - 3.1.6.RELEASE + 3.1.6.RELEASE \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverApplication.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverApplication.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/AuthResolverController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/CustomWebSecurityConfig.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/CustomWebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/authresolver/CustomWebSecurityConfig.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/authresolver/CustomWebSecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/CorsOnAnnotatedElementsApplication.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/CorsOnAnnotatedElementsApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/CorsOnAnnotatedElementsApplication.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/CorsOnAnnotatedElementsApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnClassController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnClassController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnClassController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnClassController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnMethodsController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnMethodsController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnMethodsController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/annotated/controllers/CorsOnMethodsController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/CorsGlobalConfigApplication.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/CorsGlobalConfigApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/CorsGlobalConfigApplication.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/CorsGlobalConfigApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/config/CorsGlobalConfiguration.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/config/CorsGlobalConfiguration.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/config/CorsGlobalConfiguration.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/config/CorsGlobalConfiguration.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/FurtherCorsConfigsController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/FurtherCorsConfigsController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/FurtherCorsConfigsController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/FurtherCorsConfigsController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/RegularRestController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/RegularRestController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/RegularRestController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/controllers/RegularRestController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/handlers/CorsGlobalFunctionalHandler.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/handlers/CorsGlobalFunctionalHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/handlers/CorsGlobalFunctionalHandler.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/handlers/CorsGlobalFunctionalHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/routers/CorsRouterFunctions.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/routers/CorsRouterFunctions.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/routers/CorsRouterFunctions.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/global/functional/routers/CorsRouterFunctions.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/CorsWebFilterApplication.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/CorsWebFilterApplication.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/CorsWebFilterApplication.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/CorsWebFilterApplication.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/config/CorsWebFilterConfig.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/config/CorsWebFilterConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/config/CorsWebFilterConfig.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/config/CorsWebFilterConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/FurtherCorsConfigsController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/FurtherCorsConfigsController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/FurtherCorsConfigsController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/FurtherCorsConfigsController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/RegularRestController.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/RegularRestController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/RegularRestController.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/controllers/RegularRestController.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/handlers/CorsWithWebFilterHandler.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/handlers/CorsWithWebFilterHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/handlers/CorsWithWebFilterHandler.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/handlers/CorsWithWebFilterHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/routers/CorsWithWebFilterRouterFunctions.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/routers/CorsWithWebFilterRouterFunctions.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/routers/CorsWithWebFilterRouterFunctions.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/reactive/cors/webfilter/functional/routers/CorsWithWebFilterRouterFunctions.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/Employee.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/Employee.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/Employee.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/Employee.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeConfig.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeConfig.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeCreationEvent.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeCreationEvent.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeCreationEvent.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeCreationEvent.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSecurityConfig.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSecurityConfig.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSecurityConfig.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketClient.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketClient.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketClient.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketClient.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketHandler.java b/spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketHandler.java rename to spring-reactive-modules/spring-reactive-security/src/main/java/com/baeldung/webflux/EmployeeWebSocketHandler.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/main/resources/application.properties b/spring-reactive-modules/spring-reactive-security/src/main/resources/application.properties similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/main/resources/application.properties rename to spring-reactive-modules/spring-reactive-security/src/main/resources/application.properties diff --git a/spring-reactive-modules/spring-reactive-security/src/main/resources/files/hello.txt b/spring-reactive-modules/spring-reactive-security/src/main/resources/files/hello.txt new file mode 100644 index 0000000000..b6fc4c620b --- /dev/null +++ b/spring-reactive-modules/spring-reactive-security/src/main/resources/files/hello.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt b/spring-reactive-modules/spring-reactive-security/src/main/resources/files/test/test.txt similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt rename to spring-reactive-modules/spring-reactive-security/src/main/resources/files/test/test.txt diff --git a/spring-reactive-modules/spring-reactive-security/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactive-security/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-reactive-modules/spring-reactive-security/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/static/client-websocket.html b/spring-reactive-modules/spring-reactive-security/src/main/resources/static/client-websocket.html similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/resources/static/client-websocket.html rename to spring-reactive-modules/spring-reactive-security/src/main/resources/static/client-websocket.html diff --git a/spring-reactive-modules/spring-5-reactive/src/main/webapp/WEB-INF/web.xml b/spring-reactive-modules/spring-reactive-security/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/webapp/WEB-INF/web.xml rename to spring-reactive-modules/spring-reactive-security/src/main/webapp/WEB-INF/web.xml diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/SpringContextTest.java similarity index 73% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/SpringContextTest.java index e6123de118..a0a7d9264a 100644 --- a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/SpringContextTest.java +++ b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/SpringContextTest.java @@ -1,13 +1,14 @@ package com.baeldung; -import com.baeldung.reactive.actuator.Spring5ReactiveApplication; 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.webflux.EmployeeWebSocketClient; + @RunWith(SpringRunner.class) -@SpringBootTest(classes = Spring5ReactiveApplication.class) +@SpringBootTest(classes = EmployeeWebSocketClient.class) public class SpringContextTest { @Test diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/authresolver/AuthResolverIntegrationTest.java b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/authresolver/AuthResolverIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/authresolver/AuthResolverIntegrationTest.java rename to spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/authresolver/AuthResolverIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnAnnotatedElementsLiveTest.java b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnAnnotatedElementsLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnAnnotatedElementsLiveTest.java rename to spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnAnnotatedElementsLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnGlobalConfigLiveTest.java b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnGlobalConfigLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnGlobalConfigLiveTest.java rename to spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnGlobalConfigLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnWebFilterLiveTest.java b/spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnWebFilterLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnWebFilterLiveTest.java rename to spring-reactive-modules/spring-reactive-security/src/test/java/com/baeldung/reactive/cors/CorsOnWebFilterLiveTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/resources/baeldung-weekly.png b/spring-reactive-modules/spring-reactive-security/src/test/resources/baeldung-weekly.png similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/resources/baeldung-weekly.png rename to spring-reactive-modules/spring-reactive-security/src/test/resources/baeldung-weekly.png diff --git a/spring-reactive-modules/spring-reactive/README.md b/spring-reactive-modules/spring-reactive/README.md index 7dfc7b2952..61d781b312 100644 --- a/spring-reactive-modules/spring-reactive/README.md +++ b/spring-reactive-modules/spring-reactive/README.md @@ -1,6 +1,5 @@ -### Spring Reactive Articles that are also part of the e-book -This module contains articles about Spring Reactive that are also part of an Ebook. +This module contains articles about Spring Reactive that **are also part of an Ebook.** ## Spring Reactive @@ -21,4 +20,4 @@ This module contains articles describing reactive processing in Spring. ### NOTE: -Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. +## Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. diff --git a/spring-reactive-modules/spring-reactive/pom.xml b/spring-reactive-modules/spring-reactive/pom.xml index 2281e6b0b4..f19809e302 100644 --- a/spring-reactive-modules/spring-reactive/pom.xml +++ b/spring-reactive-modules/spring-reactive/pom.xml @@ -6,9 +6,10 @@ spring-reactive - com.baeldung.spring.reactive - spring-reactive-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -90,6 +91,18 @@ + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + 3.4.16 1.3.10 diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java index fa10383c95..9cb8cdf003 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java @@ -24,10 +24,10 @@ public class ConsumerDebuggingApplication { @Bean public SecurityWebFilterChain debuggingConsumerSpringSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange() - .anyExchange() - .permitAll(); - http.csrf().disable(); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .permitAll()); + http.csrf(csrf -> csrf.disable()); return http.build(); } } diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java index ddf97ee5a8..d836a892aa 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java @@ -22,9 +22,9 @@ public class ServerDebuggingApplication { @Bean public SecurityWebFilterChain debuggingServerSpringSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange() - .anyExchange() - .permitAll(); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .permitAll()); return http.build(); } } diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java index 3458a175e4..549ae749f2 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java @@ -1,13 +1,13 @@ package com.baeldung.reactive.errorhandling; +import java.util.Map; + import org.springframework.boot.web.error.ErrorAttributeOptions; import org.springframework.boot.web.reactive.error.DefaultErrorAttributes; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.ServerRequest; -import java.util.Map; - @Component public class GlobalErrorAttributes extends DefaultErrorAttributes { diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java index 24583308cd..69f9a0420e 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java @@ -1,5 +1,7 @@ package com.baeldung.reactive.errorhandling; +import java.util.Map; + import org.springframework.boot.autoconfigure.web.WebProperties; import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler; import org.springframework.boot.web.error.ErrorAttributeOptions; @@ -16,15 +18,15 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Mono; -import java.util.Map; +import reactor.core.publisher.Mono; @Component @Order(-2) public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { - public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext, + public GlobalErrorWebExceptionHandler( + GlobalErrorAttributes g, ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) { super(g, new WebProperties.Resources(), applicationContext); super.setMessageWriters(serverCodecConfigurer.getWriters()); diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java index d49d9b4be2..f9e4ee4c35 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java @@ -5,6 +5,7 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; + import reactor.core.publisher.Mono; @Component diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java index 5f130ec035..aeea202c31 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java @@ -1,15 +1,15 @@ package com.baeldung.reactive.errorhandling; +import static org.springframework.http.MediaType.TEXT_PLAIN; +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; + import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; -import static org.springframework.http.MediaType.TEXT_PLAIN; -import static org.springframework.web.reactive.function.server.RequestPredicates.GET; -import static org.springframework.web.reactive.function.server.RequestPredicates.accept; - @Component public class Router { diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java index 67e54ad26a..69683452cd 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java @@ -1,6 +1,7 @@ package com.baeldung.reactive.security; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; @@ -12,18 +13,19 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.server.SecurityWebFilterChain; @EnableWebFluxSecurity +@Configuration @EnableReactiveMethodSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - return http.authorizeExchange() - .pathMatchers("/admin").hasAuthority("ROLE_ADMIN") - .anyExchange().authenticated() - .and() - .formLogin() - .and() - .csrf().disable() + return http + .authorizeExchange(exchanges -> exchanges + .pathMatchers("/admin").hasAuthority("ROLE_ADMIN") + .anyExchange().authenticated()) + .formLogin(formLogin -> formLogin + .loginPage("/login")) + .csrf(csrf -> csrf.disable()) .build(); } diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity5Application.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java similarity index 94% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity5Application.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java index bc0895a38b..4b20c678b5 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity5Application.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java @@ -13,11 +13,11 @@ import reactor.netty.http.server.HttpServer; @ComponentScan(basePackages = {"com.baeldung.reactive.security"}) @EnableWebFlux -public class SpringSecurity5Application { +public class SpringSecurity6Application { public static void main(String[] args) { try (AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(SpringSecurity5Application.class)) { + new AnnotationConfigApplicationContext(SpringSecurity6Application.class)) { context.getBean(DisposableServer.class).onDispose().block(); } } diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java index 3a62e7b8a5..c756f43893 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java @@ -16,9 +16,8 @@ public class WebClientApplication { @Bean public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http.csrf().disable() - .authorizeExchange() - .anyExchange().permitAll(); + http.csrf(csrf -> csrf.disable()) + .authorizeExchange(exchanges -> exchanges.anyExchange().permitAll()); return http.build(); } } diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java index fc98b70c0f..67c10e12a2 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java @@ -1,7 +1,9 @@ package com.baeldung.reactive.webflux.annotation; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; @@ -12,6 +14,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.server.SecurityWebFilterChain; @EnableWebFluxSecurity +@Configuration public class EmployeeWebSecurityConfig { @Bean @@ -27,12 +30,11 @@ public class EmployeeWebSecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .csrf().disable() - .authorizeExchange() + .csrf(csrf -> csrf.disable()) + .authorizeExchange(exchanges -> exchanges .pathMatchers(HttpMethod.POST, "/employees/update").hasRole("ADMIN") - .pathMatchers("/**").permitAll() - .and() - .httpBasic(); + .pathMatchers("/**").permitAll()) + .httpBasic(Customizer.withDefaults()); return http.build(); } diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java index 6bf39e4791..161c739ffb 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.reactive.server.WebTestClient; -@SpringBootTest(classes = SpringSecurity5Application.class) +@SpringBootTest(classes = SpringSecurity6Application.class) class SecurityIntegrationTest { @Autowired diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java index aaecb6498c..f109ab4887 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java @@ -7,7 +7,7 @@ import io.netty.handler.timeout.WriteTimeoutHandler; 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.boot.test.web.server.LocalServerPort; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.codec.CodecException; import org.springframework.http.HttpHeaders; diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java index f4d2f4384f..9274f836e6 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.web.reactive.server.WebTestClient; diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java index 6c7433dfe3..d476fb1e9a 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.ApplicationContext; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.reactive.server.WebTestClient; diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java index 3e09521e04..bf407dbbf7 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java @@ -14,10 +14,7 @@ import org.springframework.web.util.DefaultUriBuilderFactory; import reactor.core.publisher.Mono; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @WebFluxTest class WebClientRequestsWithParametersUnitTest { @@ -51,6 +48,7 @@ class WebClientRequestsWithParametersUnitTest { .uri("/products") .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products"); @@ -64,6 +62,7 @@ class WebClientRequestsWithParametersUnitTest { .build(2)) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/2"); @@ -77,6 +76,7 @@ class WebClientRequestsWithParametersUnitTest { .build(2, 13)) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/2/attributes/13"); @@ -93,6 +93,7 @@ class WebClientRequestsWithParametersUnitTest { .build()) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); @@ -109,6 +110,7 @@ class WebClientRequestsWithParametersUnitTest { .build("AndroidPhone", "black", "13/04/2019")) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13%2F04%2F2019"); @@ -123,6 +125,7 @@ class WebClientRequestsWithParametersUnitTest { .build()) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?tag%5B%5D=Snapdragon&tag%5B%5D=NFC"); @@ -137,6 +140,7 @@ class WebClientRequestsWithParametersUnitTest { .build()) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?category=Phones&category=Tablets"); @@ -151,6 +155,7 @@ class WebClientRequestsWithParametersUnitTest { .build()) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?category=Phones,Tablets"); @@ -176,6 +181,7 @@ class WebClientRequestsWithParametersUnitTest { .build()) .retrieve() .bodyToMono(String.class) + .onErrorResume(e -> Mono.empty()) .block(); verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); diff --git a/spring-reactive-modules/spring-reactor/pom.xml b/spring-reactive-modules/spring-reactor/pom.xml index 22eaa898bd..c2635765f0 100644 --- a/spring-reactive-modules/spring-reactor/pom.xml +++ b/spring-reactive-modules/spring-reactor/pom.xml @@ -37,7 +37,6 @@ - 2.0.2.RELEASE 2.0.8.RELEASE diff --git a/spring-remoting-modules/pom.xml b/spring-remoting-modules/pom.xml index 41d77c2969..8a5990fd1d 100644 --- a/spring-remoting-modules/pom.xml +++ b/spring-remoting-modules/pom.xml @@ -43,16 +43,10 @@ org.apache.maven.plugins maven-compiler-plugin ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - 11 - 11 \ No newline at end of file diff --git a/spring-scheduling/pom.xml b/spring-scheduling/pom.xml index 9010338fee..e374b2b890 100644 --- a/spring-scheduling/pom.xml +++ b/spring-scheduling/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../parent-boot-2 + ../parent-boot-3 @@ -33,21 +33,19 @@ org.springframework.boot spring-boot-starter-web - - javax.annotation - javax.annotation-api - ${annotation-api.version} - org.springframework spring-test test + + org.apache.commons + commons-lang3 + - 2.0.0 - 1.3.2 + 2.0.3 \ No newline at end of file diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/dynamic/DynamicSchedulingConfig.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/dynamic/DynamicSchedulingConfig.java index b29f9ab0ce..7b7c18f507 100644 --- a/spring-scheduling/src/main/java/com/baeldung/scheduling/dynamic/DynamicSchedulingConfig.java +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/dynamic/DynamicSchedulingConfig.java @@ -37,7 +37,7 @@ public class DynamicSchedulingConfig implements SchedulingConfigurer { Instant nextExecutionTime = lastCompletionTime.orElseGet(Date::new).toInstant() .plusMillis(tickService.getDelay()); - return Date.from(nextExecutionTime); + return Date.from(nextExecutionTime).toInstant(); } ); } diff --git a/spring-scheduling/src/main/java/com/baeldung/taskscheduler/ThreadPoolTaskSchedulerExamples.java b/spring-scheduling/src/main/java/com/baeldung/taskscheduler/ThreadPoolTaskSchedulerExamples.java index c0c6f37507..163be62591 100644 --- a/spring-scheduling/src/main/java/com/baeldung/taskscheduler/ThreadPoolTaskSchedulerExamples.java +++ b/spring-scheduling/src/main/java/com/baeldung/taskscheduler/ThreadPoolTaskSchedulerExamples.java @@ -2,7 +2,7 @@ package com.baeldung.taskscheduler; import java.util.Date; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; diff --git a/spring-security-modules/spring-security-azuread/README.md b/spring-security-modules/spring-security-azuread/README.md index 8b4d6d9666..1031455a45 100644 --- a/spring-security-modules/spring-security-azuread/README.md +++ b/spring-security-modules/spring-security-azuread/README.md @@ -1,2 +1,2 @@ ## Relevant Articles -- [Authenticating Users with AzureAD in Spring Boot](https://www.baeldung.com/spring-boot-azuerad-authenticate-users) +- [Authenticating Users with AzureAD in Spring Boot](https://www.baeldung.com/spring-boot-azuread-authenticate-users) diff --git a/spring-security-modules/spring-security-core-2/README.md b/spring-security-modules/spring-security-core-2/README.md index 80027ea42f..5f54dc1a50 100644 --- a/spring-security-modules/spring-security-core-2/README.md +++ b/spring-security-modules/spring-security-core-2/README.md @@ -8,7 +8,8 @@ This module contains articles about core Spring Security - [Prevent Cross-Site Scripting (XSS) in a Spring Application](https://www.baeldung.com/spring-prevent-xss) - [Guide to the AuthenticationManagerResolver in Spring Security](https://www.baeldung.com/spring-security-authenticationmanagerresolver) - [A Custom Spring SecurityConfigurer](https://www.baeldung.com/spring-security-custom-configurer) - +- [HttpSecurity vs. WebSecurity in Spring Security](https://www.baeldung.com/spring-security-httpsecurity-vs-websecurity) + ### Build the Project `mvn clean install` diff --git a/spring-security-modules/spring-security-core-2/pom.xml b/spring-security-modules/spring-security-core-2/pom.xml index e540d7bc01..5d77098869 100644 --- a/spring-security-modules/spring-security-core-2/pom.xml +++ b/spring-security-modules/spring-security-core-2/pom.xml @@ -15,6 +15,10 @@ ../../parent-boot-2 + + 5.8.4 + + org.springframework.boot @@ -49,6 +53,16 @@ org.springframework.security spring-security-test + + org.springframework.security + spring-security-web + ${spring.security.version} + + + org.springframework.security + spring-security-core + ${spring.security.version} + @@ -100,4 +114,4 @@ - \ No newline at end of file + diff --git a/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/HttpSecurityConfig.java b/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/HttpSecurityConfig.java new file mode 100644 index 0000000000..d6361255e5 --- /dev/null +++ b/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/HttpSecurityConfig.java @@ -0,0 +1,31 @@ +package com.baeldung.httpsecurityvswebsecurity; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +public class HttpSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // Given: HttpSecurity configured + + http.authorizeRequests() + .antMatchers("/public/**").permitAll() + .antMatchers("/admin/**").hasRole("ADMIN") + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login") + .permitAll() + .and() + .logout() + .permitAll(); + + // When: Accessing specific URLs + // Then: Access is granted based on defined rules + } +} diff --git a/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/WebSecurityConfig.java b/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/WebSecurityConfig.java new file mode 100644 index 0000000000..46a82918aa --- /dev/null +++ b/spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/httpsecurityvswebsecurity/WebSecurityConfig.java @@ -0,0 +1,35 @@ +package com.baeldung.httpsecurityvswebsecurity; + +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private UserDetailsService userDetailsService; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .userDetailsService(userDetailsService) + .passwordEncoder(new BCryptPasswordEncoder()); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/") + .permitAll() + .anyRequest() + .authenticated() + .and() + .formLogin(); + } +} diff --git a/spring-security-modules/spring-security-core/pom.xml b/spring-security-modules/spring-security-core/pom.xml index 0eb70c0853..03d7030057 100644 --- a/spring-security-modules/spring-security-core/pom.xml +++ b/spring-security-modules/spring-security-core/pom.xml @@ -100,4 +100,4 @@ - \ No newline at end of file + diff --git a/spring-security-modules/spring-security-ldap/src/test/java/com/baeldung/SpringContextTest.java b/spring-security-modules/spring-security-ldap/src/test/java/com/baeldung/SpringContextTest.java index a15ca31980..62b1ae908b 100644 --- a/spring-security-modules/spring-security-ldap/src/test/java/com/baeldung/SpringContextTest.java +++ b/spring-security-modules/spring-security-ldap/src/test/java/com/baeldung/SpringContextTest.java @@ -1,6 +1,5 @@ package com.baeldung; -import com.baeldung.SampleLDAPApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/spring-security-modules/spring-security-oauth2-testing/pom.xml b/spring-security-modules/spring-security-oauth2-testing/pom.xml index 93348cb48c..45fcf9bcce 100644 --- a/spring-security-modules/spring-security-oauth2-testing/pom.xml +++ b/spring-security-modules/spring-security-oauth2-testing/pom.xml @@ -14,7 +14,7 @@ ../../parent-boot-3 - 6.1.0 + 7.1.10 diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java index 500d876bc4..716900ea51 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java @@ -1,7 +1,8 @@ package com.baeldung; +import static org.springframework.security.config.Customizer.withDefaults; + import java.nio.charset.Charset; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -27,6 +28,7 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.oauth2.core.oidc.StandardClaimNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository; import org.springframework.stereotype.Service; @@ -34,6 +36,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @SpringBootApplication @@ -46,68 +49,66 @@ public class ReactiveResourceServerApplication { @Configuration @EnableWebFluxSecurity @EnableReactiveMethodSecurity - public class SecurityConfig { + static class SecurityConfig { @Bean - SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, Converter>> authoritiesConverter) { - http.oauth2ResourceServer() - .jwt() - .jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt) - .map(authorities -> new JwtAuthenticationToken(jwt, authorities))); - http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) - .csrf() - .disable(); - http.exceptionHandling() - .accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal() - .flatMap(principal -> { + SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults())); + http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()); + http.csrf(csrf -> csrf.disable()); + http.exceptionHandling(eh -> eh + .accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal().flatMap(principal -> { final var response = exchange.getResponse(); - response.setStatusCode(principal instanceof AnonymousAuthenticationToken ? HttpStatus.UNAUTHORIZED : HttpStatus.FORBIDDEN); - response.getHeaders() - .setContentType(MediaType.TEXT_PLAIN); + response.setStatusCode( + principal instanceof AnonymousAuthenticationToken ? HttpStatus.UNAUTHORIZED + : HttpStatus.FORBIDDEN); + response.getHeaders().setContentType(MediaType.TEXT_PLAIN); final var dataBufferFactory = response.bufferFactory(); - final var buffer = dataBufferFactory.wrap(ex.getMessage() - .getBytes(Charset.defaultCharset())); + final var buffer = dataBufferFactory.wrap(ex.getMessage().getBytes(Charset.defaultCharset())); return response.writeWith(Mono.just(buffer)) - .doOnError(error -> DataBufferUtils.release(buffer)); - })); + .doOnError(error -> DataBufferUtils.release(buffer)); + }))); - http.authorizeExchange() - .pathMatchers("/secured-route") - .hasRole("AUTHORIZED_PERSONNEL") - .anyExchange() - .authenticated(); + // @formatter:off + http.authorizeExchange(req -> req + .pathMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL").anyExchange() + .authenticated()); + // @formatter:on return http.build(); } - static interface AuthoritiesConverter extends Converter>> { + static interface ReactiveJwtAuthoritiesConverter extends Converter> { } @Bean - AuthoritiesConverter realmRoles2AuthoritiesConverter() { + ReactiveJwtAuthoritiesConverter realmRoles2AuthoritiesConverter() { return (Jwt jwt) -> { - final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")) - .orElse(Map.of()); + final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); @SuppressWarnings("unchecked") final var roles = (List) realmRoles.getOrDefault("roles", List.of()); - return Mono.just(roles.stream() - .map(SimpleGrantedAuthority::new) - .map(GrantedAuthority.class::cast) - .toList()); + return Flux.fromStream(roles.stream()).map(SimpleGrantedAuthority::new) + .map(GrantedAuthority.class::cast); }; } + + @Bean + ReactiveJwtAuthenticationConverter authenticationConverter( + Converter> authoritiesConverter) { + final var authenticationConverter = new ReactiveJwtAuthenticationConverter(); + authenticationConverter.setPrincipalClaimName(StandardClaimNames.PREFERRED_USERNAME); + authenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); + return authenticationConverter; + } } @Service public static class MessageService { public Mono greet() { - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> { - final var who = (JwtAuthenticationToken) ctx.getAuthentication(); - final var claims = who.getTokenAttributes(); - return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities()); - }) - .switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); + return ReactiveSecurityContextHolder.getContext().map(ctx -> { + final var who = (JwtAuthenticationToken) ctx.getAuthentication(); + return "Hello %s! You are granted with %s.".formatted(who.getName(), who.getAuthorities()); + }).switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); } @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") @@ -118,26 +119,23 @@ public class ReactiveResourceServerApplication { @RestController @RequiredArgsConstructor - public class GreetingController { + public static class GreetingController { private final MessageService messageService; @GetMapping("/greet") public Mono> greet() { - return messageService.greet() - .map(ResponseEntity::ok); + return messageService.greet().map(ResponseEntity::ok); } @GetMapping("/secured-route") public Mono> securedRoute() { - return messageService.getSecret() - .map(ResponseEntity::ok); + return messageService.getSecret().map(ResponseEntity::ok); } @GetMapping("/secured-method") @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") public Mono> securedMethod() { - return messageService.getSecret() - .map(ResponseEntity::ok); + return messageService.getSecret().map(ResponseEntity::ok); } } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java index 97893bc1fb..c13a20ca38 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -3,28 +3,49 @@ package com.baeldung; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import com.baeldung.ReactiveResourceServerApplication.MessageService; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.baeldung.ReactiveResourceServerApplication.SecurityConfig; +import com.c4_soft.springaddons.security.oauth2.test.AuthenticationFactoriesTestConf; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithJwt; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.ParameterizedAuthentication; -@Import({ MessageService.class }) +@Import({ MessageService.class, SecurityConfig.class }) +@ImportAutoConfiguration(AuthenticationFactoriesTestConf.class) @ExtendWith(SpringExtension.class) -@EnableReactiveMethodSecurity +@TestInstance(Lifecycle.PER_CLASS) class MessageServiceUnitTest { @Autowired MessageService messageService; + @Autowired + WithJwt.AuthenticationFactory authFactory; + + @MockBean + ReactiveJwtDecoder jwtDecoder; + /*----------------------------------------------------------------------------*/ /* greet() */ /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ @@ -43,10 +64,12 @@ class MessageServiceUnitTest { .block()); } - @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() { - assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet() + @ParameterizedTest + @MethodSource("allIdentities") + void givenUserIsAuthenticated_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities(@ParameterizedAuthentication Authentication auth) { + final var jwt = (JwtAuthenticationToken) auth; + final var expected = "Hello %s! You are granted with %s.".formatted(jwt.getTokenAttributes().get(StandardClaimNames.PREFERRED_USERNAME), auth.getAuthorities()); + assertEquals(expected, messageService.greet() .block()); } @@ -70,17 +93,25 @@ class MessageServiceUnitTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + @WithJwt("ch4mpy.json") + void givenUserIsCh4mpy_whenGetSecret_thenReturnSecret() { assertEquals("Only authorized personnel can read that", messageService.getSecret() .block()); } @Test - @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + @WithJwt("tonton-pirate.json") + void givenUserIsTontonPirate_whenGetSecret_thenThrowsAccessDeniedException() { assertThrows(AccessDeniedException.class, () -> messageService.getSecret() .block()); } + /*--------------------------------------------*/ + /* methodSource returning all test identities */ + /*--------------------------------------------*/ + private Stream allIdentities() { + final var authentications = authFactory.authenticationsFrom("ch4mpy.json", "tonton-pirate.json").toList(); + return authentications.stream(); + } + } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java index 1ee6fc7e87..d6bfbf4e2d 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -8,8 +8,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.test.web.reactive.server.WebTestClient; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithJwt; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockAuthentication; @SpringBootTest(webEnvironment = WebEnvironment.MOCK) @AutoConfigureWebTestClient @@ -33,7 +33,7 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithJwt("ch4mpy.json") void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { api.get() .uri("/greet") @@ -60,7 +60,7 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { api.get() .uri("/secured-route") @@ -72,7 +72,7 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { api.get() .uri("/secured-route") @@ -97,7 +97,7 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { api.get() .uri("/secured-method") @@ -109,7 +109,7 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { api.get() .uri("/secured-method") diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 6f55f287d8..f31bbe3ae8 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -5,16 +5,19 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.test.web.reactive.server.WebTestClient; import com.baeldung.ReactiveResourceServerApplication.GreetingController; import com.baeldung.ReactiveResourceServerApplication.MessageService; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockAuthentication; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.AuthenticationSource; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.ParameterizedAuthentication; import reactor.core.publisher.Mono; @@ -28,115 +31,88 @@ class SpringAddonsGreetingControllerUnitTest { WebTestClient api; /*-----------------------------------------------------------------------------*/ - /* /greet */ - /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /* /greet */ + /* + * This end-point secured with ".anyRequest().authenticated()" in SecurityConf + */ /*-----------------------------------------------------------------------------*/ @Test @WithAnonymousUser void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { - api.get() - .uri("/greet") - .exchange() - .expectStatus() - .isUnauthorized(); + api.get().uri("/greet").exchange().expectStatus().isUnauthorized(); } - @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + @ParameterizedTest + @AuthenticationSource({ + @WithMockAuthentication(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, name = "ch4mpy"), + @WithMockAuthentication(authorities = { "uncle", "PIRATE" }, name = "tonton-pirate") }) + void givenUserIsAuthenticated_whenGetGreet_thenOk(@ParameterizedAuthentication Authentication auth) throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(Mono.just(greeting)); - api.get() - .uri("/greet") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo(greeting); + api.get().uri("/greet").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(greeting); verify(messageService, times(1)).greet(); } /*---------------------------------------------------------------------------------------------------------------------*/ - /* /secured-route */ - /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /* /secured-route */ + /* + * This end-point is secured with + * ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in + * SecurityConf + */ /*---------------------------------------------------------------------------------------------------------------------*/ @Test @WithAnonymousUser void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { - api.get() - .uri("/secured-route") - .exchange() - .expectStatus() - .isUnauthorized(); + api.get().uri("/secured-route").exchange().expectStatus().isUnauthorized(); } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - api.get() - .uri("/secured-route") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo(secret); + api.get().uri("/secured-route").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(secret); } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - api.get() - .uri("/secured-route") - .exchange() - .expectStatus() - .isForbidden(); + api.get().uri("/secured-route").exchange().expectStatus().isForbidden(); } /*---------------------------------------------------------------------------------------------------------*/ - /* /secured-method */ - /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /* /secured-method */ + /* + * This end-point is secured with + * "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method + */ /*---------------------------------------------------------------------------------------------------------*/ @Test @WithAnonymousUser void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { - api.get() - .uri("/secured-method") - .exchange() - .expectStatus() - .isUnauthorized(); + api.get().uri("/secured-method").exchange().expectStatus().isUnauthorized(); } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - api.get() - .uri("/secured-method") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo(secret); + api.get().uri("/secured-method").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(secret); } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - api.get() - .uri("/secured-method") - .exchange() - .expectStatus() - .isForbidden(); + api.get().uri("/secured-method").exchange().expectStatus().isForbidden(); } } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/ch4mpy.json b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/ch4mpy.json new file mode 100644 index 0000000000..22f7bb2cea --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/ch4mpy.json @@ -0,0 +1,15 @@ +{ + "iss": "https://localhost:8443/realms/master", + "sub": "281c4558-550c-413b-9972-2d2e5bde6b9b", + "iat": 1695992542, + "exp": 1695992642, + "preferred_username": "ch4mpy", + "realm_access": { + "roles": [ + "admin", + "ROLE_AUTHORIZED_PERSONNEL" + ] + }, + "email": "ch4mp@c4-soft.com", + "scope": "openid email" +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/tonton-pirate.json b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/tonton-pirate.json new file mode 100644 index 0000000000..13a422f6fd --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/resources/tonton-pirate.json @@ -0,0 +1,15 @@ +{ + "iss": "https://localhost:8443/realms/master", + "sub": "2d2e5bde6b9b-550c-413b-9972-281c4558", + "iat": 1695992551, + "exp": 1695992651, + "preferred_username": "tonton-pirate", + "realm_access": { + "roles": [ + "uncle", + "PIRATE" + ] + }, + "email": "tonton-pirate@c4-soft.com", + "scope": "openid email" +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java index a30c60eab0..8258955afe 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java @@ -1,5 +1,7 @@ package com.baeldung; +import static org.springframework.security.config.Customizer.withDefaults; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -23,8 +25,10 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.oidc.StandardClaimNames; import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -43,56 +47,52 @@ public class ServletResourceServerApplication { @EnableWebSecurity static class SecurityConf { @Bean - SecurityFilterChain filterChain(HttpSecurity http, Converter> authoritiesConverter) throws Exception { - http.oauth2ResourceServer() - .jwt() - .jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt))); - http.sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .csrf() - .disable(); - http.exceptionHandling() - .authenticationEntryPoint((request, response, authException) -> { - response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\""); - response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase()); - }); + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults())); + http.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + http.csrf(csrf -> csrf.disable()); + http.exceptionHandling(eh -> eh.authenticationEntryPoint((request, response, authException) -> { + response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Bearer realm=\"Restricted Content\""); + response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase()); + })); - http.authorizeHttpRequests() - .requestMatchers("/secured-route") - .hasRole("AUTHORIZED_PERSONNEL") - .anyRequest() - .authenticated(); + // @formatter:off + http.authorizeHttpRequests(req -> req + .requestMatchers(new AntPathRequestMatcher("/secured-route")).hasRole("AUTHORIZED_PERSONNEL") + .anyRequest().authenticated()); + // @formatter:on return http.build(); } - static interface AuthoritiesConverter extends Converter> { + static interface JwtAuthoritiesConverter extends Converter> { } @Bean - AuthoritiesConverter realmRoles2AuthoritiesConverter() { + JwtAuthoritiesConverter realmRoles2AuthoritiesConverter() { return (Jwt jwt) -> { - final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")) - .orElse(Map.of()); + final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); @SuppressWarnings("unchecked") final var roles = (List) realmRoles.getOrDefault("roles", List.of()); - return roles.stream() - .map(SimpleGrantedAuthority::new) - .map(GrantedAuthority.class::cast) - .toList(); + return roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList(); }; } + + @Bean + JwtAuthenticationConverter authenticationConverter(Converter> authoritiesConverter) { + final var authenticationConverter = new JwtAuthenticationConverter(); + authenticationConverter.setPrincipalClaimName(StandardClaimNames.PREFERRED_USERNAME); + authenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); + return authenticationConverter; + } } @Service public static class MessageService { public String greet() { - final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext() - .getAuthentication(); - final var claims = who.getTokenAttributes(); - return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities()); + final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + return "Hello %s! You are granted with %s.".formatted(who.getName(), who.getAuthorities()); } @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java index 3c608d226e..ca237fb888 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -3,28 +3,49 @@ package com.baeldung; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import com.baeldung.ServletResourceServerApplication.MessageService; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.baeldung.ServletResourceServerApplication.SecurityConf; +import com.c4_soft.springaddons.security.oauth2.test.AuthenticationFactoriesTestConf; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithJwt; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.ParameterizedAuthentication; -@Import({ MessageService.class }) +@Import({ MessageService.class, SecurityConf.class }) +@ImportAutoConfiguration(AuthenticationFactoriesTestConf.class) @ExtendWith(SpringExtension.class) -@EnableMethodSecurity +@TestInstance(Lifecycle.PER_CLASS) class MessageServiceUnitTest { @Autowired MessageService messageService; + @Autowired + WithJwt.AuthenticationFactory authFactory; + + @MockBean + JwtDecoder jwtDecoder; + /*----------------------------------------------------------------------------*/ /* greet() */ /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ @@ -41,10 +62,12 @@ class MessageServiceUnitTest { assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); } - @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() { - assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet()); + @ParameterizedTest + @MethodSource("allIdentities") + void givenUserIsAuthenticated_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities(@ParameterizedAuthentication Authentication auth) { + final var jwt = (JwtAuthenticationToken) auth; + final var expected = "Hello %s! You are granted with %s.".formatted(jwt.getTokenAttributes().get(StandardClaimNames.PREFERRED_USERNAME), auth.getAuthorities()); + assertEquals(expected, messageService.greet()); } @Test @@ -65,15 +88,22 @@ class MessageServiceUnitTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + @WithJwt("ch4mpy.json") + void givenUserIsCh4mpy_whenGetSecret_thenReturnSecret() { assertEquals("Only authorized personnel can read that", messageService.getSecret()); } @Test - @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + @WithJwt("tonton-pirate.json") + void givenUserIsTontonPirate_whenGetSecret_thenThrowsAccessDeniedException() { assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); } + /*--------------------------------------------*/ + /* methodSource returning all test identities */ + /*--------------------------------------------*/ + private Stream allIdentities() { + final var authentications = authFactory.authenticationsFrom("ch4mpy.json", "tonton-pirate.json").toList(); + return authentications.stream(); + } } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java index 5bb539741f..4f2fe51787 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -12,8 +12,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.test.web.servlet.MockMvc; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithJwt; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockAuthentication; @SpringBootTest(webEnvironment = WebEnvironment.MOCK) @AutoConfigureMockMvc @@ -34,7 +34,7 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithJwt("ch4mpy.json") void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { api.perform(get("/greet")) .andExpect(status().isOk()) @@ -54,7 +54,7 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { api.perform(get("/secured-route")) .andExpect(status().isOk()) @@ -62,7 +62,7 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { api.perform(get("/secured-route")) .andExpect(status().isForbidden()); @@ -81,7 +81,7 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + @WithMockAuthentication("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { api.perform(get("/secured-method")) .andExpect(status().isOk()) @@ -89,7 +89,7 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth("admin") + @WithMockAuthentication("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { api.perform(get("/secured-method")) .andExpect(status().isForbidden()); diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 9162768930..2534d9919a 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -8,16 +8,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.test.web.servlet.MockMvc; import com.baeldung.ServletResourceServerApplication.GreetingController; import com.baeldung.ServletResourceServerApplication.MessageService; -import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; -import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockAuthentication; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.AuthenticationSource; +import com.c4_soft.springaddons.security.oauth2.test.annotations.parameterized.ParameterizedAuthentication; @WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) class SpringAddonsGreetingControllerUnitTest { @@ -40,9 +43,11 @@ class SpringAddonsGreetingControllerUnitTest { .andExpect(status().isUnauthorized()); } - @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) - void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + @ParameterizedTest + @AuthenticationSource({ + @WithMockAuthentication(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, name = "ch4mpy"), + @WithMockAuthentication(authorities = { "uncle", "PIRATE" }, name = "tonton-pirate") }) + void givenUserIsAuthenticated_whenGetGreet_thenOk(@ParameterizedAuthentication Authentication auth) throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(greeting); @@ -66,7 +71,7 @@ class SpringAddonsGreetingControllerUnitTest { } @Test - @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + @WithMockAuthentication({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); @@ -77,7 +82,7 @@ class SpringAddonsGreetingControllerUnitTest { } @Test - @WithMockJwtAuth({ "admin" }) + @WithMockAuthentication({ "admin" }) void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { api.perform(get("/secured-route")) .andExpect(status().isForbidden()); @@ -96,7 +101,7 @@ class SpringAddonsGreetingControllerUnitTest { } @Test - @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + @WithMockAuthentication({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); @@ -107,7 +112,7 @@ class SpringAddonsGreetingControllerUnitTest { } @Test - @WithMockJwtAuth(authorities = { "admin" }) + @WithMockAuthentication({ "admin" }) void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { api.perform(get("/secured-method")) .andExpect(status().isForbidden()); diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/ch4mpy.json b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/ch4mpy.json new file mode 100644 index 0000000000..22f7bb2cea --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/ch4mpy.json @@ -0,0 +1,15 @@ +{ + "iss": "https://localhost:8443/realms/master", + "sub": "281c4558-550c-413b-9972-2d2e5bde6b9b", + "iat": 1695992542, + "exp": 1695992642, + "preferred_username": "ch4mpy", + "realm_access": { + "roles": [ + "admin", + "ROLE_AUTHORIZED_PERSONNEL" + ] + }, + "email": "ch4mp@c4-soft.com", + "scope": "openid email" +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/tonton-pirate.json b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/tonton-pirate.json new file mode 100644 index 0000000000..13a422f6fd --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/resources/tonton-pirate.json @@ -0,0 +1,15 @@ +{ + "iss": "https://localhost:8443/realms/master", + "sub": "2d2e5bde6b9b-550c-413b-9972-281c4558", + "iat": 1695992551, + "exp": 1695992651, + "preferred_username": "tonton-pirate", + "realm_access": { + "roles": [ + "uncle", + "PIRATE" + ] + }, + "email": "tonton-pirate@c4-soft.com", + "scope": "openid email" +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-mvc-custom/pom.xml b/spring-security-modules/spring-security-web-mvc-custom/pom.xml index f21c6dbe40..41f24050b2 100644 --- a/spring-security-modules/spring-security-web-mvc-custom/pom.xml +++ b/spring-security-modules/spring-security-web-mvc-custom/pom.xml @@ -172,7 +172,6 @@ - 3.2.2 1.6.1 1.3.2 diff --git a/spring-security-modules/spring-security-web-mvc-custom/src/test/java/com/baeldung/web/interceptor/SessionTimerInterceptorIntegrationTest.java b/spring-security-modules/spring-security-web-mvc-custom/src/test/java/com/baeldung/web/interceptor/SessionTimerInterceptorIntegrationTest.java index 07bc22f184..873c28c6a2 100644 --- a/spring-security-modules/spring-security-web-mvc-custom/src/test/java/com/baeldung/web/interceptor/SessionTimerInterceptorIntegrationTest.java +++ b/spring-security-modules/spring-security-web-mvc-custom/src/test/java/com/baeldung/web/interceptor/SessionTimerInterceptorIntegrationTest.java @@ -49,7 +49,7 @@ public class SessionTimerInterceptorIntegrationTest { .andReturn() .getRequest() .getSession(); - Thread.sleep(51000); + Thread.sleep(5000); mockMvc.perform(get("/auth/foos").session((MockHttpSession) session)) .andExpect(status().is2xxSuccessful()); } diff --git a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController3.java b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationController.java similarity index 89% rename from spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController3.java rename to spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationController.java index 2dcb98286b..4f9b24cf36 100644 --- a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController3.java +++ b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationController.java @@ -8,9 +8,9 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller -public class SecurityController3 { +public class GetUserWithAuthenticationController { - public SecurityController3() { + public GetUserWithAuthenticationController() { super(); } diff --git a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationPrincipalAnnotationController.java similarity index 87% rename from spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java rename to spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationPrincipalAnnotationController.java index 93a2bfcacd..912b4c178c 100644 --- a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java +++ b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithAuthenticationPrincipalAnnotationController.java @@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController -public class SecurityController4 { +public class GetUserWithAuthenticationPrincipalAnnotationController { @GetMapping("/user") public String getUser(@AuthenticationPrincipal UserDetails userDetails) { diff --git a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController.java b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithPrincipalController.java similarity index 85% rename from spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController.java rename to spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithPrincipalController.java index ece442430f..ed3ea5b25d 100644 --- a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController.java +++ b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithPrincipalController.java @@ -8,9 +8,9 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller -public class SecurityController { +public class GetUserWithPrincipalController { - public SecurityController() { + public GetUserWithPrincipalController() { super(); } diff --git a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController1.java b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithSecurityContextHolderController.java similarity index 92% rename from spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController1.java rename to spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithSecurityContextHolderController.java index 1951e04dcb..c63271ef77 100644 --- a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController1.java +++ b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/GetUserWithSecurityContextHolderController.java @@ -11,12 +11,12 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller -public class SecurityController1 { +public class GetUserWithSecurityContextHolderController { @Autowired private ApplicationEventPublisher eventPublisher; - public SecurityController1() { + public GetUserWithSecurityContextHolderController() { super(); } diff --git a/spring-shell/pom.xml b/spring-shell/pom.xml index 506884b413..24fe5b0fb6 100644 --- a/spring-shell/pom.xml +++ b/spring-shell/pom.xml @@ -28,7 +28,6 @@ org.apache.maven.plugins maven-war-plugin - ${maven-war-plugin.version} src/main/webapp false @@ -39,7 +38,6 @@ 1.2.0.RELEASE - 3.3.2 \ No newline at end of file diff --git a/spring-soap/.gitignore b/spring-soap/.gitignore index cce17abdb9..2b04fd0719 100644 --- a/spring-soap/.gitignore +++ b/spring-soap/.gitignore @@ -1,2 +1,4 @@ /target/ sun-jaxb.episode + +**/gen/** \ No newline at end of file diff --git a/spring-soap/pom.xml b/spring-soap/pom.xml index 8188178d61..6c49f1f39c 100644 --- a/spring-soap/pom.xml +++ b/spring-soap/pom.xml @@ -30,6 +30,22 @@ spring-boot-starter-test test + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.xml.bind-api.version} + + + + org.glassfish.jaxb + jaxb-runtime + + + + javax.xml.bind + jaxb-api + @@ -42,7 +58,7 @@ org.codehaus.mojo jaxb2-maven-plugin - 1.6 + ${jaxb2-maven-plugin.version} xjc @@ -52,8 +68,10 @@ - ${project.basedir}/src/main/resources/ - ${project.basedir}/src/main/java + + src/main/resources/countries.xsd + + src/main/java false @@ -61,7 +79,7 @@ org.jvnet.jaxb2.maven2 maven-jaxb2-plugin - 0.14.0 + ${maven-jaxb2-plugin.version} @@ -83,4 +101,10 @@ + + 17 + 4.0.0 + 3.1.0 + 0.15.3 + \ No newline at end of file diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java index 745131767a..49020cec21 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java @@ -1,12 +1,14 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; +import com.baeldung.springsoap.client.gen.GetCountryRequest; +import com.baeldung.springsoap.client.gen.GetCountryResponse; + @Endpoint public class CountryEndpoint { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java index 8a0f58a64e..183027cdb6 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java @@ -1,12 +1,15 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + import org.springframework.stereotype.Component; import org.springframework.util.Assert; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; +import com.baeldung.springsoap.client.gen.Country; +import com.baeldung.springsoap.client.gen.Currency; @Component public class CountryRepository { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java index 930a961208..57636e9891 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java @@ -17,11 +17,11 @@ import org.springframework.xml.xsd.XsdSchema; public class WebServiceConfig extends WsConfigurerAdapter { @Bean - public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { + public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); - return new ServletRegistrationBean(servlet, "/ws/*"); + return new ServletRegistrationBean<>(servlet, "/ws/*"); } @Bean(name = "countries") diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java deleted file mode 100644 index bb196d625d..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java +++ /dev/null @@ -1,139 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlSchemaType; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for country complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType name="country">
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="population" type="{http://www.w3.org/2001/XMLSchema}int"/>
- *         <element name="capital" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="currency" type="{http://www.baeldung.com/springsoap/gen}currency"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "country", propOrder = { - "name", - "population", - "capital", - "currency" -}) -public class Country { - - @XmlElement(required = true) - protected String name; - protected int population; - @XmlElement(required = true) - protected String capital; - @XmlElement(required = true) - @XmlSchemaType(name = "string") - protected Currency currency; - - /** - * Gets the value of the name property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getName() { - return name; - } - - /** - * Sets the value of the name property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setName(String value) { - this.name = value; - } - - /** - * Gets the value of the population property. - * - */ - public int getPopulation() { - return population; - } - - /** - * Sets the value of the population property. - * - */ - public void setPopulation(int value) { - this.population = value; - } - - /** - * Gets the value of the capital property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getCapital() { - return capital; - } - - /** - * Sets the value of the capital property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setCapital(String value) { - this.capital = value; - } - - /** - * Gets the value of the currency property. - * - * @return - * possible object is - * {@link Currency } - * - */ - public Currency getCurrency() { - return currency; - } - - /** - * Sets the value of the currency property. - * - * @param value - * allowed object is - * {@link Currency } - * - */ - public void setCurrency(Currency value) { - this.currency = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java deleted file mode 100644 index 023a8103e5..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java +++ /dev/null @@ -1,40 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlEnum; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for currency. - * - *

The following schema fragment specifies the expected content contained within this class. - *

- *

- * <simpleType name="currency">
- *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *     <enumeration value="GBP"/>
- *     <enumeration value="EUR"/>
- *     <enumeration value="PLN"/>
- *   </restriction>
- * </simpleType>
- * 
- * - */ -@XmlType(name = "currency") -@XmlEnum -public enum Currency { - - GBP, - EUR, - PLN; - - public String value() { - return name(); - } - - public static Currency fromValue(String v) { - return valueOf(v); - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java deleted file mode 100644 index dcd5b1f08b..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for anonymous complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType>
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "", propOrder = { - "name" -}) -@XmlRootElement(name = "getCountryRequest") -public class GetCountryRequest { - - @XmlElement(required = true) - protected String name; - - /** - * Gets the value of the name property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getName() { - return name; - } - - /** - * Sets the value of the name property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setName(String value) { - this.name = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java deleted file mode 100644 index 11135c32e1..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for anonymous complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType>
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="country" type="{http://www.baeldung.com/springsoap/gen}country"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "", propOrder = { - "country" -}) -@XmlRootElement(name = "getCountryResponse") -public class GetCountryResponse { - - @XmlElement(required = true) - protected Country country; - - /** - * Gets the value of the country property. - * - * @return - * possible object is - * {@link Country } - * - */ - public Country getCountry() { - return country; - } - - /** - * Sets the value of the country property. - * - * @param value - * allowed object is - * {@link Country } - * - */ - public void setCountry(Country value) { - this.country = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java deleted file mode 100644 index e6d56d5aba..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java +++ /dev/null @@ -1,56 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlRegistry; - - -/** - * This object contains factory methods for each - * Java content interface and Java element interface - * generated in the com.baeldung.springsoap.client.gen package. - *

An ObjectFactory allows you to programatically - * construct new instances of the Java representation - * for XML content. The Java representation of XML - * content can consist of schema derived interfaces - * and classes representing the binding of schema - * type definitions, element declarations and model - * groups. Factory methods for each of these are - * provided in this class. - * - */ -@XmlRegistry -public class ObjectFactory { - - - /** - * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.springsoap.client.gen - * - */ - public ObjectFactory() { - } - - /** - * Create an instance of {@link GetCountryRequest } - * - */ - public GetCountryRequest createGetCountryRequest() { - return new GetCountryRequest(); - } - - /** - * Create an instance of {@link GetCountryResponse } - * - */ - public GetCountryResponse createGetCountryResponse() { - return new GetCountryResponse(); - } - - /** - * Create an instance of {@link Country } - * - */ - public Country createCountry() { - return new Country(); - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java deleted file mode 100644 index 9432e0c328..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/springsoap/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) -package com.baeldung.springsoap.client.gen; diff --git a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java index 3b071c286f..1150b8d91b 100644 --- a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java +++ b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java @@ -1,18 +1,19 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.GetCountryRequest; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.boot.test.web.server.LocalServerPort; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.ClassUtils; import org.springframework.ws.client.core.WebServiceTemplate; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.springsoap.client.gen.GetCountryRequest; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @@ -20,7 +21,8 @@ public class ApplicationIntegrationTest { private Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); - @LocalServerPort private int port = 0; + @LocalServerPort + private int port = 0; @Before public void init() throws Exception { @@ -34,6 +36,8 @@ public class ApplicationIntegrationTest { GetCountryRequest request = new GetCountryRequest(); request.setName("Spain"); - assertThat(ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request)).isNotNull(); + Object response = ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request); + + assertThat(response).isNotNull(); } } diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml index c529951b07..b57a014a8f 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml @@ -29,22 +29,22 @@ org.hibernate hibernate-validator - 6.0.10.Final + ${hibernate-validator.version} javax.validation validation-api - 2.0.1.Final + ${validation-api.version} org.openapitools openapi-generator - 3.3.4 + ${openapi-generator.version} com.fasterxml.jackson.core jackson-databind - 2.10.0.pr3 + ${jackson-databind.version} org.springdoc @@ -62,7 +62,7 @@ org.openapitools openapi-generator-maven-plugin - 5.1.0 + ${openapi-generator-maven-plugin.version} @@ -97,6 +97,11 @@ 3.0.0 2.17.1 1.7.0 + 6.0.10.Final + 2.0.1.Final + 3.3.4 + 2.10.0.pr3 + 5.1.0 \ No newline at end of file diff --git a/spring-swagger-codegen/spring-openapi-generator-api-client/pom.xml b/spring-swagger-codegen/spring-openapi-generator-api-client/pom.xml index f125018fb0..ee2c86238a 100644 --- a/spring-swagger-codegen/spring-openapi-generator-api-client/pom.xml +++ b/spring-swagger-codegen/spring-openapi-generator-api-client/pom.xml @@ -34,55 +34,55 @@ io.swagger swagger-annotations - ${swagger-annotations-version} + ${swagger-annotations.version} com.google.code.findbugs jsr305 - 3.0.2 + ${findbugs-jsr305.version} org.springframework spring-web - ${spring-web-version} + ${spring-web.version} com.fasterxml.jackson.core jackson-core - ${jackson-version} + ${jackson.version} com.fasterxml.jackson.core jackson-annotations - ${jackson-version} + ${jackson.version} com.fasterxml.jackson.core jackson-databind - ${jackson-version} + ${jackson.version} com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - ${jackson-version} + ${jackson.version} org.openapitools jackson-databind-nullable - ${jackson-databind-nullable-version} + ${jackson-databind-nullable.version} com.fasterxml.jackson.datatype jackson-datatype-jsr310 - ${jackson-version} + ${jackson.version} com.github.joschi.jackson jackson-datatype-threetenbp - ${jackson-threetenbp-version} + ${jackson-threetenbp.version} @@ -94,7 +94,7 @@ javax.annotation javax.annotation-api - 1.3.2 + ${javax.annotation-api.version} @@ -103,7 +103,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.0.0-M1 + ${maven-enforcer-plugin.version} enforce-maven @@ -123,7 +123,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.12 + ${maven-surefire-plugin.version} @@ -154,7 +154,7 @@ org.apache.maven.plugins maven-jar-plugin - 2.2 + ${maven-jar-plugin.version} @@ -169,7 +169,7 @@ org.codehaus.mojo build-helper-maven-plugin - 1.10 + ${build-helper-maven-plugin.version} add_sources @@ -200,7 +200,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.6.1 + ${maven-compiler-plugin.version} 1.8 1.8 @@ -209,7 +209,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + ${maven-javadoc-plugin.version} attach-javadocs @@ -222,7 +222,7 @@ org.apache.maven.plugins maven-source-plugin - 2.2.1 + ${maven-source-plugin.version} attach-sources @@ -243,7 +243,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + ${maven-gpg-plugin.version} sign-artifacts @@ -260,14 +260,25 @@ - 1.5.22 - 4.3.9.RELEASE - 2.11.1 + 1.5.22 + 4.3.9.RELEASE + 3.0.2 + 2.11.1 - 0.2.1 - 2.9.10 - 1.0.0 + 0.2.1 + 2.9.10 + 1.0.0 5.8.1 + 1.3.2 + + 3.0.0-M1 + 2.12 + 2.2 + 1.10 + 3.6.1 + 2.10.4 + 2.2.1 + 1.5 \ No newline at end of file diff --git a/spring-swagger-codegen/spring-swagger-codegen-api-client/pom.xml b/spring-swagger-codegen/spring-swagger-codegen-api-client/pom.xml index b2e97c7a49..35f4978411 100644 --- a/spring-swagger-codegen/spring-swagger-codegen-api-client/pom.xml +++ b/spring-swagger-codegen/spring-swagger-codegen-api-client/pom.xml @@ -40,13 +40,13 @@ io.swagger swagger-annotations - ${swagger-annotations-version} + ${swagger-annotations.version} org.springframework spring-web - ${spring-web-version} + ${spring-web.version} @@ -77,12 +77,12 @@ joda-time joda-time - ${jodatime-version} + ${jodatime.version} javax.annotation javax.annotation-api - 1.3.2 + ${javax.annotation-api.version} @@ -189,9 +189,10 @@ - 1.5.15 - 4.3.9.RELEASE - 2.9.9 + 1.5.15 + 4.3.9.RELEASE + 2.9.9 + 1.3.2 2.2 1.5 2.2.1 diff --git a/spring-vault/README.md b/spring-vault/README.md index 9e1d14ba6b..22fb0a7ff2 100644 --- a/spring-vault/README.md +++ b/spring-vault/README.md @@ -5,3 +5,4 @@ This module contains articles about Spring Vault ### Relevant Articles: - [Spring Vault](https://www.baeldung.com/spring-vault) +- [Secure Kubernetes Secrets with Vault](https://www.baeldung.com/spring-vault-kubernetes-secrets) diff --git a/spring-vault/pom.xml b/spring-vault/pom.xml index 7b89db2302..b3690c7b7f 100644 --- a/spring-vault/pom.xml +++ b/spring-vault/pom.xml @@ -36,7 +36,7 @@ org.springframework.vault spring-vault-core - ${spring.vault.core.version} + ${spring-vault-core.version} org.springframework.data @@ -51,10 +51,38 @@ spring-boot-starter-test test + + + ch.qos.logback + logback-classic + + + ch.qos.logback + logback-core + + + + org.slf4j + slf4j-api + + + + software.amazon.awssdk + auth + ${auth.version} + + + + org.springframework.cloud + spring-cloud-starter-vault-config + ${spring-cloud-starter-vault-config.version} + - 3.0.2 + 2.3.4 + 2.20.140 + 3.1.3 17 diff --git a/spring-vault/src/main/java/com/baeldung/springcloudvault/SpringCloudVaultTestApplication.java b/spring-vault/src/main/java/com/baeldung/springcloudvault/SpringCloudVaultTestApplication.java new file mode 100644 index 0000000000..cea416005d --- /dev/null +++ b/spring-vault/src/main/java/com/baeldung/springcloudvault/SpringCloudVaultTestApplication.java @@ -0,0 +1,25 @@ +package com.baeldung.springcloudvault; + + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; + +@SpringBootApplication +public class SpringCloudVaultTestApplication { + public static void main(String... args) { + SpringApplication.run(SpringCloudVaultTestApplication.class, args); + } + + @Bean + CommandLineRunner listSecrets(Environment env) { + return args -> { + var foo = env.getProperty("foo"); + Assert.notNull(foo, "foo must have a value"); + System.out.println("foo=" + foo); + }; + } +} diff --git a/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultConfig.java b/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultConfig.java new file mode 100644 index 0000000000..407e324a87 --- /dev/null +++ b/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultConfig.java @@ -0,0 +1,25 @@ +package com.baeldung.springvaultk8s; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.KubernetesAuthentication; +import org.springframework.vault.authentication.KubernetesAuthenticationOptions; +import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.config.AbstractVaultConfiguration; +import org.springframework.vault.config.EnvironmentVaultConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.net.URISyntaxException; + +@Configuration +@PropertySource("vault-config-k8s.properties") +@Import(EnvironmentVaultConfiguration.class) +public class VaultConfig { + +} diff --git a/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultK8SApplication.java b/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultK8SApplication.java new file mode 100644 index 0000000000..a61b67bf6e --- /dev/null +++ b/spring-vault/src/main/java/com/baeldung/springvaultk8s/VaultK8SApplication.java @@ -0,0 +1,45 @@ +package com.baeldung.springvaultk8s; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.vault.core.VaultKeyValueOperations; +import org.springframework.vault.core.VaultKeyValueOperationsSupport; +import org.springframework.vault.core.VaultTemplate; + +import java.util.List; +import java.util.Map; + +@SpringBootApplication +public class VaultK8SApplication { + + public static void main(String... args) { + SpringApplication.run(VaultK8SApplication.class, args); + } + + @Bean + CommandLineRunner listSecrets(VaultTemplate vault) { + + return args -> { + VaultKeyValueOperations ops = vault.opsForKeyValue("secrets", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2); + List secrets = ops.list(""); + if (secrets == null) { + System.out.println("No secrets found"); + return; + } + + secrets.forEach(s -> { + System.out.println("secret=" + s); + var response = ops.get(s); + var data = response.getRequiredData(); + + data.entrySet() + .forEach(e -> { + System.out.println("- key=" + e.getKey() + " => " + e.getValue()); + }); + }); + }; + } +} diff --git a/spring-vault/src/main/k8s/vault-csi-example.yaml b/spring-vault/src/main/k8s/vault-csi-example.yaml new file mode 100644 index 0000000000..8136554033 --- /dev/null +++ b/spring-vault/src/main/k8s/vault-csi-example.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: baeldung-csi-secrets + namespace: baeldung +spec: + # Vault CSI Provider + provider: vault + parameters: + # Vault role name to use during login + roleName: 'baeldung-test-role' + objects: | + - objectName: 'baeldung.properties' + secretPath: "secrets/data/baeldung-test" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-csi + namespace: baeldung +spec: + selector: + matchLabels: + app: nginx-csi + replicas: 1 # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx-csi + spec: + serviceAccountName: vault-test-sa + automountServiceAccountToken: true + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + volumeMounts: + - name: vault-secrets + mountPath: /vault/secrets + readOnly: true + volumes: + - name: vault-secrets + csi: + driver: 'secrets-store.csi.k8s.io' + readOnly: true + volumeAttributes: + secretProviderClass: baeldung-csi-secrets + + diff --git a/spring-vault/src/main/k8s/vault-injector-example.yaml b/spring-vault/src/main/k8s/vault-injector-example.yaml new file mode 100644 index 0000000000..4d0aad70a1 --- /dev/null +++ b/spring-vault/src/main/k8s/vault-injector-example.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + namespace: baeldung +spec: + selector: + matchLabels: + app: nginx + replicas: 1 # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + annotations: + vault.hashicorp.com/agent-inject: "true" + vault.hashicorp.com/agent-inject-secret-baeldung.properties: "secrets/baeldung-test" + vault.hashicorp.com/role: "baeldung-test-role" + vault.hashicorp.com/agent-inject-template-baeldung.properties: | + {{- with secret "secrets/baeldung-test" -}} + {{- range $k, $v := .Data.data }} + {{$k}}={{$v}} + {{- end -}} + {{ end }} + spec: + serviceAccountName: vault-test-sa + automountServiceAccountToken: true + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/spring-vault/src/main/k8s/vault-operator-example.yaml b/spring-vault/src/main/k8s/vault-operator-example.yaml new file mode 100644 index 0000000000..a77888905d --- /dev/null +++ b/spring-vault/src/main/k8s/vault-operator-example.yaml @@ -0,0 +1,58 @@ +--- +## +## Vault Connection +## +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultConnection +metadata: + namespace: baeldung + name: vault-local +spec: + # required configuration + # address to the Vault server. + address: http://vault.vault.svc.cluster.local:8200 +--- +## +## Vault Auth +## +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + namespace: baeldung + name: baeldung-test +spec: + # required configuration + # VaultConnectionRef of the corresponding VaultConnection CustomResource. + # If no value is specified the Operator will default to the `default` VaultConnection, + # configured in its own Kubernetes namespace. + vaultConnectionRef: vault-local + # Method to use when authenticating to Vault. + method: kubernetes + # Mount to use when authenticating to auth method. + mount: kubernetes + # Kubernetes specific auth configuration, requires that the Method be set to kubernetes. + kubernetes: + # role to use when authenticating to Vault + role: baeldung-test-role + # ServiceAccount to use when authenticating to Vault + # it is recommended to always provide a unique serviceAccount per Pod/application + serviceAccount: vault-test-sa +--- +## +## Vault-backed secret +## +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + namespace: baeldung + name: baeldung-test +spec: + vaultAuthRef: baeldung-test + mount: secrets + type: kv-v2 + path: baeldung-test + refreshAfter: 60s + hmacSecretData: true + destination: + create: true + name: baeldung-test diff --git a/spring-vault/src/main/resources/vault-config-k8s.properties b/spring-vault/src/main/resources/vault-config-k8s.properties new file mode 100644 index 0000000000..276d735fcb --- /dev/null +++ b/spring-vault/src/main/resources/vault-config-k8s.properties @@ -0,0 +1,4 @@ +vault.uri=http://localhost:8200 +vault.authentication=KUBERNETES +vault.kubernetes.role=baeldung-test-role +vault.kubernetes.service-account-token-file=sa-token.txt \ No newline at end of file diff --git a/spring-vault/src/test/java/com/baeldung/springcloudvault/SpringCloudVaultApplicationLiveTest.java b/spring-vault/src/test/java/com/baeldung/springcloudvault/SpringCloudVaultApplicationLiveTest.java new file mode 100644 index 0000000000..b4ece472a6 --- /dev/null +++ b/spring-vault/src/test/java/com/baeldung/springcloudvault/SpringCloudVaultApplicationLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.springcloudvault; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +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.core.env.Environment; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ActiveProfiles("vault") +@SpringBootTest(classes = SpringCloudVaultTestApplication.class) +public class SpringCloudVaultApplicationLiveTest { + + @Autowired + Environment env; + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + assertNotNull(env.getProperty("foo")); + } + +} diff --git a/spring-vault/src/test/resources/application-vault.properties b/spring-vault/src/test/resources/application-vault.properties new file mode 100644 index 0000000000..7226a3a6e4 --- /dev/null +++ b/spring-vault/src/test/resources/application-vault.properties @@ -0,0 +1,15 @@ +# Vault Properties +spring.config.import: vault:// +spring.cloud.vault.uri=http://localhost:8200 +spring.cloud.vault.authentication=KUBERNETES +spring.cloud.vault.kubernetes.role=baeldung-test-role + +# +spring.cloud.vault.kv.backend=secrets +spring.cloud.vault.kv.application-name=baeldung-test +# + +# NOTICE: the following property is only necessary when running the application +# outside Kubernetes +# Please refer to the article for instructions on how to create this file +spring.cloud.vault.kubernetes.service-account-token-file=sa-token.txt \ No newline at end of file diff --git a/spring-web-modules/pom.xml b/spring-web-modules/pom.xml index d513822ea3..2be896ad83 100644 --- a/spring-web-modules/pom.xml +++ b/spring-web-modules/pom.xml @@ -10,8 +10,9 @@ com.baeldung - parent-modules - 1.0.0-SNAPSHOT + parent-spring-5 + 0.0.1-SNAPSHOT + ../parent-spring-5 @@ -52,6 +53,7 @@ spring-thymeleaf-4 spring-thymeleaf-5 spring-web-url + spring-thymeleaf-attributes \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-5/pom.xml b/spring-web-modules/spring-mvc-basics-5/pom.xml index c957d669bd..e0d603e303 100644 --- a/spring-web-modules/spring-mvc-basics-5/pom.xml +++ b/spring-web-modules/spring-mvc-basics-5/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -30,8 +30,14 @@ tomcat-embed-jasper - javax.servlet - jstl + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + ${jakarta.servlet.jsp.jstl} + + + org.glassfish.web + jakarta.servlet.jsp.jstl + ${jakarta.servlet.jsp.jstl} org.springframework.boot @@ -53,6 +59,11 @@ jaxb-runtime ${jaxb-runtime.version} + + io.rest-assured + rest-assured + ${io.rest-assured.version} + @@ -73,6 +84,8 @@ 1.3.2 2.7.0 2.3.5 + 2.0.0 + 3.0.0 \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/jsonargs/JsonArgumentResolver.java b/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/jsonargs/JsonArgumentResolver.java index 3cb01dae32..94b8d12107 100644 --- a/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/jsonargs/JsonArgumentResolver.java +++ b/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/jsonargs/JsonArgumentResolver.java @@ -3,7 +3,7 @@ package com.baeldung.jsonargs; import java.io.IOException; import java.util.Objects; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.io.IOUtils; import org.springframework.core.MethodParameter; diff --git a/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/modelattribute/Employee.java b/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/modelattribute/Employee.java index 0ec3c5c374..2dacfe87d9 100644 --- a/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/modelattribute/Employee.java +++ b/spring-web-modules/spring-mvc-basics-5/src/main/java/com/baeldung/modelattribute/Employee.java @@ -1,6 +1,6 @@ package com.baeldung.modelattribute; -import javax.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Employee { diff --git a/spring-web-modules/spring-mvc-xml-2/pom.xml b/spring-web-modules/spring-mvc-xml-2/pom.xml index f4326ccf68..8c0062f538 100644 --- a/spring-web-modules/spring-mvc-xml-2/pom.xml +++ b/spring-web-modules/spring-mvc-xml-2/pom.xml @@ -19,12 +19,12 @@ org.springframework spring-web - ${org.springframework.version} + ${spring.version} org.springframework spring-webmvc - ${org.springframework.version} + ${spring.version} @@ -64,7 +64,7 @@ org.springframework.boot spring-boot-starter-test - ${spring-boot.version} + ${spring-boot-starter-test.version} test @@ -95,8 +95,6 @@ - 5.0.2.RELEASE - 1.5.10.RELEASE 5.1.40 4.4.5 4.5.2 diff --git a/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/pom.xml b/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/pom.xml index 38d019c683..d4fff21605 100644 --- a/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/pom.xml +++ b/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/pom.xml @@ -1,84 +1,84 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> - 4.0.0 + 4.0.0 - com.baeldung.spring-thymeleaf-attributes.module - accessing-session-attributes - 0.0.1-SNAPSHOT - war - - - com.baeldung.spring-thymeleaf-attributes - spring-thymeleaf-attributes + com.baeldung.spring-thymeleaf-attributes.module + accessing-session-attributes 0.0.1-SNAPSHOT - ../pom.xml - + war - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-thymeleaf - ${spring.boot.starter.thymeleaf} - - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.engine.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - - org.junit.jupiter - junit-jupiter-api - ${junit.jupiter.engine.version} - test - - + + com.baeldung.spring-thymeleaf-attributes + spring-thymeleaf-attributes + 0.0.1-SNAPSHOT + ../pom.xml + - - - - org.springframework.boot - spring-boot-maven-plugin - - - -Dfile.encoding="UTF-8" -Xdebug - -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 - - - - - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + ${spring.boot.starter.thymeleaf} + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.engine.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.engine.version} + test + + - - com.baeldung.accesing_session_attributes.SpringWebApplicationInitializer - UTF-8 - UTF-8 - UTF-8 - true - true - 5.9.3 - 5.3.1 - 3.1.1.RELEASE - 3.1.1 - + + + + org.springframework.boot + spring-boot-maven-plugin + + + -Dfile.encoding="UTF-8" -Xdebug + -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 + + + + + + + + com.baeldung.accesing_session_attributes.SpringWebApplicationInitializer + UTF-8 + UTF-8 + UTF-8 + true + true + 5.9.3 + 5.3.1 + 3.1.1.RELEASE + 3.1.1 + \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf/README.md b/spring-web-modules/spring-thymeleaf/README.md index b49095f5b1..7121085ac0 100644 --- a/spring-web-modules/spring-thymeleaf/README.md +++ b/spring-web-modules/spring-thymeleaf/README.md @@ -23,3 +23,20 @@ mvn cargo:run ### Security The user/password required is: user1/user1Pass + +### Endpoints + +All endpoints start with `http://localhost:8082/spring-thymeleaf`: + +- `/dates` +- `/saveStudent` +- `/objects` +- `/fragments` +- `/markup` +- `/params` +- `/other` +- `/function-call` +- `/html` +- `/js` +- `/plain` +- `/layout` \ No newline at end of file diff --git a/spring-websockets/pom.xml b/spring-websockets/pom.xml index c13d1cff33..a28ef8749a 100644 --- a/spring-websockets/pom.xml +++ b/spring-websockets/pom.xml @@ -44,8 +44,4 @@ - - 3.3.2 - - \ No newline at end of file diff --git a/testing-modules/cucumber/pom.xml b/testing-modules/cucumber/pom.xml index ffa5c0d250..6d178b86a3 100644 --- a/testing-modules/cucumber/pom.xml +++ b/testing-modules/cucumber/pom.xml @@ -124,7 +124,6 @@ 14 6.10.3 5.4.0 - 2.22.2 3.141.59 4.3.1 0.40 diff --git a/testing-modules/junit-5-advanced/README.md b/testing-modules/junit-5-advanced/README.md index a89bcd2de2..873ab0835b 100644 --- a/testing-modules/junit-5-advanced/README.md +++ b/testing-modules/junit-5-advanced/README.md @@ -9,3 +9,4 @@ - [JUnit – Testing Methods That Call System.exit()](https://www.baeldung.com/junit-system-exit) - [Single Assert Call for Multiple Properties in Java Unit Testing](https://www.baeldung.com/java-testing-single-assert-multiple-properties) - [Creating a Test Suite With JUnit](https://www.baeldung.com/java-junit-test-suite) +- [Testing Interface Contract in Java](https://www.baeldung.com/java-junit-verify-interface-contract) diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java new file mode 100644 index 0000000000..b0e63155f4 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java @@ -0,0 +1,19 @@ +package com.baeldung.interfaces.unittest; + +public class Circle implements Shape { + + private double radius; + + Circle(double radius) { + this.radius = radius; + } + + @Override + public double area() { + return 3.14 * radius * radius; + } + + public double circumference() { + return 2 * 3.14 * radius; + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java new file mode 100644 index 0000000000..a88233e83b --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +public class Rectangle implements Shape { + + private double length; + private double breadth; + + public Rectangle(double length, double breadth) { + this.length = length; + this.breadth = breadth; + } + + @Override + public double area() { + return length * breadth; + } + + public double perimeter() { + return 2 * (length + breadth); + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java new file mode 100644 index 0000000000..bac42fb246 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java @@ -0,0 +1,6 @@ +package com.baeldung.interfaces.unittest; + +public interface Shape { + + double area(); +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..08ce2bc779 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class CircleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Circle(5)); + shapeAreaMap.put("area", 78.5); + return shapeAreaMap; + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java new file mode 100644 index 0000000000..c0b4eecedc --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class CircleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape circle = new Circle(5); + double area = circle.area(); + assertEquals(78.5, area); + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java new file mode 100644 index 0000000000..6b5cd6b6ab --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class ParameterizedUnitTest { + + @ParameterizedTest + @MethodSource("data") + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful(Shape shapeInstance, double expectedArea) { + double area = shapeInstance.area(); + assertEquals(expectedArea, area); + + } + + private static Collection data() { + return Arrays.asList(new Object[][] { + { new Circle(5), 78.5 }, + { new Rectangle(4, 5), 20 } + }); + } +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..b6771ad648 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class RectangleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Rectangle(5, 4)); + shapeAreaMap.put("area", 20.0); + return shapeAreaMap; + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java new file mode 100644 index 0000000000..1983353667 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class RectangleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape rectangle = new Rectangle(5, 4); + double area = rectangle.area(); + assertEquals(20, area); + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java new file mode 100644 index 0000000000..a9d318f698 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public abstract class ShapeUnitTest { + + public abstract Map instantiateShapeWithExpectedArea(); + + @Test + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful() { + Map shapeAreaMap = instantiateShapeWithExpectedArea(); + Shape shape = (Shape) shapeAreaMap.get("shape"); + double expectedArea = (double) shapeAreaMap.get("area"); + double area = shape.area(); + assertEquals(expectedArea, area); + } +} diff --git a/testing-modules/junit-5-basics-2/README.md b/testing-modules/junit-5-basics-2/README.md new file mode 100644 index 0000000000..0e0faedb4b --- /dev/null +++ b/testing-modules/junit-5-basics-2/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Test Main Method with JUnit](https://www.baeldung.com/junit-test-main-method) diff --git a/testing-modules/junit-5-basics-2/pom.xml b/testing-modules/junit-5-basics-2/pom.xml new file mode 100644 index 0000000000..85b6c707fb --- /dev/null +++ b/testing-modules/junit-5-basics-2/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + junit-5-basics-2 + + + + commons-cli + commons-cli + ${commons-cli.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter-api.version} + test + + + org.mockito + mockito-core + ${mockito-core.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + + + 11 + 11 + UTF-8 + 1.5.0 + 5.10.0 + 5.5.0 + + + \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Bootstrapper.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Bootstrapper.java new file mode 100644 index 0000000000..3dcdb93bd5 --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Bootstrapper.java @@ -0,0 +1,62 @@ +package com.baeldung.junit.main.test; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +public class Bootstrapper { + private final InputReader inputReader; + private final Calculator calculator; + + public Bootstrapper(InputReader inputReader, Calculator calculator) { + this.inputReader = inputReader; + this.calculator = calculator; + } + + public void processRequest(String[] args) { + try { + Options options = getOptions(); + CommandLineParser parser = new DefaultParser(); + CommandLine commandLine = parser.parse(options, args); + + if (commandLine.hasOption("i")) { + System.out.print("Option i is present. The value is: " + commandLine.getOptionValue("i") + " \n"); + String optionValue = commandLine.getOptionValue("i"); + InputType inputType = InputType.valueOf(optionValue); + + String fileName = null; + if (commandLine.hasOption("f")) { + fileName = commandLine.getOptionValue("f"); + } + String inputString = inputReader.read(inputType, fileName); + int calculatedSum = calculator.calculateSum(inputString); + } + + } catch (ParseException exception) { + System.out.print("Parse error: " + exception.getMessage()); + } + } + + public static Options getOptions() { + Option fileNameOption = Option.builder("f") + .required(false) + .desc("The file name option") + .type(String.class) + .build(); + Option inputTypeOption = Option.builder("i") + .longOpt("input") + .required(true) + .desc("The input type") + .type(InputType.class) + .hasArg() + .build(); + + Options options = new Options(); + options.addOption(inputTypeOption); + options.addOption(fileNameOption); + return options; + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Calculator.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Calculator.java new file mode 100644 index 0000000000..a741a0b03a --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/Calculator.java @@ -0,0 +1,17 @@ +package com.baeldung.junit.main.test; + +import java.util.Arrays; + +public class Calculator { + + public int calculateSum(String input) { + String[] array = input.split(" "); + int sum = Arrays.stream(array) + .map(Integer::valueOf) + .mapToInt(Integer::intValue) + .sum(); + System.out.println("Calculated sum: " + sum); + return sum; + } + +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputReader.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputReader.java new file mode 100644 index 0000000000..86f558df92 --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputReader.java @@ -0,0 +1,38 @@ +package com.baeldung.junit.main.test; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Scanner; + +public class InputReader { + + public String read(InputType inputType, String fileName) { + switch (inputType) { + case FILE: + return readFromFile(fileName); + case CONSOLE: + return readFromConsole(); + default: + return null; + } + } + + private String readFromConsole() { + System.out.println("Enter values for calculation: \n"); + return new Scanner(System.in).nextLine(); + } + + private String readFromFile(String fileName) { + String readString = null; + try { + readString = Files.readString(Path.of(URI.create(fileName))); + System.out.println(readString); + } catch (IOException e) { + throw new RuntimeException(e); + } + return null; + } + +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputType.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputType.java new file mode 100644 index 0000000000..fbf26b7df3 --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/InputType.java @@ -0,0 +1,5 @@ +package com.baeldung.junit.main.test; + +public enum InputType { + FILE, CONSOLE +} diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/SimpleMain.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/SimpleMain.java new file mode 100644 index 0000000000..346162bbae --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/SimpleMain.java @@ -0,0 +1,16 @@ +package com.baeldung.junit.main.test; + +import java.util.Arrays; + +public class SimpleMain { + + public static void main(String[] args) { + + System.out.println("Received input parameters: " + Arrays.asList(args)); + + Bootstrapper bootstrapper = new Bootstrapper(new InputReader(), new Calculator()); + + bootstrapper.processRequest(args); + } + +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/StaticMain.java b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/StaticMain.java new file mode 100644 index 0000000000..8c610f57ad --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/main/java/com/baeldung/junit/main/test/StaticMain.java @@ -0,0 +1,115 @@ +package com.baeldung.junit.main.test; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Scanner; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +public class StaticMain { + + public static void main(String[] args) { + System.out.println("Received input parameters: " + Arrays.asList(args)); + + processRequest(args); + } + + public static void processRequest(String[] args) { + try { + Options options = getOptions(); + CommandLineParser parser = new DefaultParser(); + CommandLine commandLine = parser.parse(options, args); + + if (commandLine.hasOption("V")) { + System.out.print("Option V is present. The value is: "); + System.out.println(commandLine.getOptionValue("V")); + } + + if (commandLine.hasOption("i")) { + System.out.print("Option i is present. The value is: " + commandLine.getOptionValue("i") + " \n"); + String optionValue = commandLine.getOptionValue("i"); + InputType inputType = InputType.valueOf(optionValue); + + String fileName = null; + if (commandLine.hasOption("f")) { + fileName = commandLine.getOptionValue("f"); + } + String inputString = read(inputType, fileName); + int calculatedSum = calculateSum(inputString); + } + + } catch (ParseException exception) { + System.out.print("Parse error: "); + System.out.println(exception.getMessage()); + } + } + + public static Options getOptions() { + Option inputTypeOption = Option.builder("i") + .longOpt("input") + .required(true) + .desc("The input type") + .type(InputType.class) + .hasArg() + .build(); + Option fileNameOption = Option.builder("f") + .required(false) + .desc("The file name option") + .type(String.class) + .hasArg() + .build(); + + Options options = new Options(); + options.addOption(inputTypeOption); + options.addOption(fileNameOption); + return options; + } + + public static int calculateSum(String input) { + if (input == null) { + return 0; + } + String[] array = input.split(" "); + int sum = Arrays.stream(array) + .map(Integer::valueOf) + .mapToInt(Integer::intValue) + .sum(); + System.out.println("Calculated sum: " + sum); + return sum; + } + + private static String readFromConsole() { + System.out.println("Enter values for calculation: \n"); + return new Scanner(System.in).nextLine(); + } + + private static String readFromFile(String fileName) { + String readString = null; + try { + readString = Files.readString(Path.of(URI.create(fileName))); + System.out.println(readString); + } catch (IOException e) { + throw new RuntimeException(e); + } + return null; + } + + public static String read(InputType inputType, String fileName) { + switch (inputType) { + case FILE: + return readFromFile(fileName); + case CONSOLE: + return readFromConsole(); + default: + return null; + } + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestSimpleMain.java b/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestSimpleMain.java new file mode 100644 index 0000000000..37ef516bff --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestSimpleMain.java @@ -0,0 +1,94 @@ +package com.baeldung.junit.main.test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.charset.Charset; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TestSimpleMain { + private InputStream defaultIn; + private PrintStream defaultOut; + + @BeforeEach + public void setUp() { + defaultIn = System.in; + defaultOut = System.out; + } + + @AfterEach + public void tearDown() { + System.setIn(defaultIn); + System.setOut(defaultOut); + } + + @Test + public void givenArgumentAsConsoleInput_WhenReadFromSubstitutedByteStream_ThenSuccessfullyCalculate() throws IOException { + String[] arguments = new String[] { "-i", "CONSOLE" }; + + final InputStream fips = new ByteArrayInputStream("1 2 3".getBytes()); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(byteArrayOutputStream); + + System.setIn(fips); + System.setOut(out); + + SimpleMain.main(arguments); + + String consoleOutput = byteArrayOutputStream.toString(Charset.defaultCharset()); + assertTrue(consoleOutput.contains("Calculated sum: 6")); + + fips.close(); + out.close(); + } + + @Test + public void givenArgumentAsConsoleInput_WhenReadFromSubstitutedFileStream_ThenSuccessfullyCalculate() throws IOException { + String[] arguments = new String[] { "-i", "CONSOLE" }; + + final InputStream fips = getClass().getClassLoader() + .getResourceAsStream("test-input.txt"); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(byteArrayOutputStream); + + System.setIn(fips); + System.setOut(out); + + SimpleMain.main(arguments); + + String consoleOutput = byteArrayOutputStream.toString(Charset.defaultCharset()); + assertTrue(consoleOutput.contains("Calculated sum: 10")); + + fips.close(); + out.close(); + } + + @Test + public void givenLongArgumentAsConsoleInput_WhenReadFromSubstitutedFileStream_ThenSuccessfullyCalculate() throws IOException { + String[] arguments = new String[] { "--input", "CONSOLE" }; + + final InputStream fips = getClass().getClassLoader() + .getResourceAsStream("test-input.txt"); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(byteArrayOutputStream); + + System.setIn(fips); + System.setOut(out); + + SimpleMain.main(arguments); + + String consoleOutput = byteArrayOutputStream.toString(Charset.defaultCharset()); + assertTrue(consoleOutput.contains("Calculated sum: 10")); + + fips.close(); + out.close(); + } + +} diff --git a/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestStaticMain.java b/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestStaticMain.java new file mode 100644 index 0000000000..267b101f94 --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/test/java/com/baeldung/junit/main/test/TestStaticMain.java @@ -0,0 +1,35 @@ +package com.baeldung.junit.main.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public class TestStaticMain { + + @Test + public void givenArgumentAsConsoleInput_WhenReadFromSubstitutedByteArrayInputStream_ThenSuccessfullyCalculate() throws IOException { + String[] arguments = new String[] { "-i", "CONSOLE" }; + try (MockedStatic mockedStatic = Mockito.mockStatic(StaticMain.class, Mockito.CALLS_REAL_METHODS); + InputStream fips = new ByteArrayInputStream("1 2 3".getBytes())) { + + final InputStream original = System.in; + + //Reassigns the "standard" input stream + System.setIn(fips); + + ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); + + StaticMain.main(arguments); + + mockedStatic.verify(() -> StaticMain.calculateSum(stringArgumentCaptor.capture())); + + System.setIn(original); + } + } + +} diff --git a/testing-modules/junit-5-basics-2/src/test/resources/test-input.txt b/testing-modules/junit-5-basics-2/src/test/resources/test-input.txt new file mode 100644 index 0000000000..6163c9426b --- /dev/null +++ b/testing-modules/junit-5-basics-2/src/test/resources/test-input.txt @@ -0,0 +1 @@ +4 5 1 \ No newline at end of file diff --git a/testing-modules/junit5-annotations/pom.xml b/testing-modules/junit5-annotations/pom.xml index 847baa827c..3a7ab1aa87 100644 --- a/testing-modules/junit5-annotations/pom.xml +++ b/testing-modules/junit5-annotations/pom.xml @@ -45,6 +45,8 @@ + 1.10.0 + 5.10.0 2.19.0 diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md index ac931a108f..da8f339e56 100644 --- a/testing-modules/mockito-2/README.md +++ b/testing-modules/mockito-2/README.md @@ -6,3 +6,6 @@ This module contains articles about Mockito - [Mocking a Singleton With Mockito](https://www.baeldung.com/java-mockito-singleton) - [Resolving Mockito Exception: Wanted But Not Invoked](https://www.baeldung.com/mockito-exception-wanted-but-not-invoked) - [Matching Null With Mockito](https://www.baeldung.com/mockito-match-null) +- [Mock Same Method with Different Parameters](https://www.baeldung.com/java-mock-same-method-other-parameters) +- [How to Mock Constructors for Unit Testing using Mockito](https://www.baeldung.com/java-mockito-constructors-unit-testing) +- [Overview of Mockito MockedConstruction](https://www.baeldung.com/java-mockito-mockedconstruction) diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/construction/CoffeeMachine.java b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/CoffeeMachine.java new file mode 100644 index 0000000000..5cf1d4eecb --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/CoffeeMachine.java @@ -0,0 +1,23 @@ +package com.baeldung.construction; + +public class CoffeeMachine { + + private Grinder grinder; + private WaterTank tank; + + public CoffeeMachine() { + this.grinder = new Grinder(); + this.tank = new WaterTank(); + } + + public CoffeeMachine(int mils) { + this.grinder = new Grinder(); + this.tank = new WaterTank(mils); + } + + public String makeCoffee() { + String type = this.tank.isEspresso() ? "Espresso" : "Americano"; + return String.format("Finished making a delicious %s made with %s beans", type, this.grinder.getBeans()); + } + +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Fruit.java b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Fruit.java new file mode 100644 index 0000000000..c63f28d25f --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Fruit.java @@ -0,0 +1,12 @@ +package com.baeldung.construction; + +public class Fruit { + + public String getName() { + return "Apple"; + } + + public String getColour() { + return "Red"; + } +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Grinder.java b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Grinder.java new file mode 100644 index 0000000000..e62b690bb2 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/Grinder.java @@ -0,0 +1,19 @@ +package com.baeldung.construction; + +public class Grinder { + + private String beans; + + public Grinder() { + this.beans = "Guatemalan"; + } + + public String getBeans() { + return beans; + } + + public void setBeans(String beans) { + this.beans = beans; + } + +} \ No newline at end of file diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/construction/WaterTank.java b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/WaterTank.java new file mode 100644 index 0000000000..bf744930a0 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/construction/WaterTank.java @@ -0,0 +1,27 @@ +package com.baeldung.construction; + +public class WaterTank { + + private int mils; + + public WaterTank() { + this.mils = 25; + } + + public WaterTank(int mils) { + this.mils = mils; + } + + public int getMils() { + return mils; + } + + public void setMils(int mils) { + this.mils = mils; + } + + public boolean isEspresso() { + return getMils() < 50; + } + +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentProcessor.java b/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentProcessor.java new file mode 100644 index 0000000000..39b2b74bd0 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentProcessor.java @@ -0,0 +1,22 @@ +package com.baeldung.constructor; + +public class PaymentProcessor { + + private final PaymentService paymentService; + + public PaymentProcessor(PaymentService paymentService) { + this.paymentService = paymentService; + } + + public PaymentProcessor() { + this.paymentService = new PaymentService(); + } + + public PaymentProcessor(String paymentMode) { + this.paymentService = new PaymentService(paymentMode); + } + + public String processPayment(){ + return paymentService.processPayment(); + } +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentService.java b/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentService.java new file mode 100644 index 0000000000..5194ed7e21 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/constructor/PaymentService.java @@ -0,0 +1,19 @@ +package com.baeldung.constructor; + +public class PaymentService { + + private final String paymentMode; + + public PaymentService(String paymentMode) { + this.paymentMode = paymentMode; + } + + public PaymentService() { + this.paymentMode = "Cash"; + } + + public String processPayment(){ + // simulate processing payment and returns the payment mode + return this.paymentMode; + } +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/onemethodmultipleparams/ExampleService.java b/testing-modules/mockito-2/src/main/java/com/baeldung/onemethodmultipleparams/ExampleService.java new file mode 100644 index 0000000000..7177013721 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/onemethodmultipleparams/ExampleService.java @@ -0,0 +1,7 @@ +package com.baeldung.onemethodmultipleparams; + +public class ExampleService { + public int getValue(int arg) { + return 1; + } +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/construction/CoffeeMachineUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/construction/CoffeeMachineUnitTest.java new file mode 100644 index 0000000000..7b93ad9db6 --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/construction/CoffeeMachineUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.construction; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; + +class CoffeeMachineUnitTest { + + @Test + void givenNoMockedContructor_whenCoffeeMade_thenRealDependencyReturned() { + CoffeeMachine machine = new CoffeeMachine(); + assertEquals("Finished making a delicious Espresso made with Guatemalan beans", machine.makeCoffee()); + } + + @Test + void givenMockedContructor_whenCoffeeMade_thenMockDependencyReturned() { + try (MockedConstruction mockTank = mockConstruction(WaterTank.class); MockedConstruction mockGrinder = mockConstruction(Grinder.class)) { + + CoffeeMachine machine = new CoffeeMachine(); + + WaterTank tank = mockTank.constructed() + .get(0); + Grinder grinder = mockGrinder.constructed() + .get(0); + + when(tank.isEspresso()).thenReturn(false); + when(grinder.getBeans()).thenReturn("Peruvian"); + + assertEquals("Finished making a delicious Americano made with Peruvian beans", machine.makeCoffee()); + } + + } + + @Test + void givenMockedContructorWithArgument_whenCoffeeMade_thenMockDependencyReturned() { + try (MockedConstruction mockTank = mockConstruction(WaterTank.class, (mock, context) -> { + int mils = (int) context.arguments().get(0); + when(mock.getMils()).thenReturn(mils); + }); + MockedConstruction mockGrinder = mockConstruction(Grinder.class)) { + + CoffeeMachine machine = new CoffeeMachine(100); + + Grinder grinder = mockGrinder.constructed() + .get(0); + + when(grinder.getBeans()).thenReturn("Kenyan"); + assertEquals("Finished making a delicious Americano made with Kenyan beans", machine.makeCoffee()); + } + + } + +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/construction/FruitUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/construction/FruitUnitTest.java new file mode 100644 index 0000000000..c7baa1cc7d --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/construction/FruitUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.construction; + +import org.junit.jupiter.api.Test; +import org.mockito.Answers; +import org.mockito.MockedConstruction; + +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import static org.mockito.Mockito.mockConstruction; + +class FruitUnitTest { + + @Test + void givenMockedContructor_whenFruitCreated_thenMockIsReturned() { + assertEquals("Apple", new Fruit().getName()); + assertEquals("Red", new Fruit().getColour()); + + try (MockedConstruction mock = mockConstruction(Fruit.class)) { + + Fruit fruit = new Fruit(); + when(fruit.getName()).thenReturn("Banana"); + when(fruit.getColour()).thenReturn("Yellow"); + + assertEquals("Banana", fruit.getName()); + assertEquals("Yellow", fruit.getColour()); + + List constructed = mock.constructed(); + assertEquals(1, constructed.size()); + } + } + + @Test + void givenMockedContructorWithNewDefaultAnswer_whenFruitCreated_thenRealMethodInvoked() { + try (MockedConstruction mock = mockConstruction(Fruit.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS))) { + + Fruit fruit = new Fruit(); + + assertEquals("Apple", fruit.getName()); + assertEquals("Red", fruit.getColour()); + + List constructed = mock.constructed(); + assertEquals(1, constructed.size()); + } + } + +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/constructor/PaymentServiceUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/constructor/PaymentServiceUnitTest.java new file mode 100644 index 0000000000..16be4a728b --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/constructor/PaymentServiceUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.constructor; + +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; + +class PaymentServiceUnitTest { + + @Test + void whenConstructorInvokedWithInitializer_ThenMockObjectShouldBeCreated(){ + try(MockedConstruction mockPaymentService = Mockito.mockConstruction(PaymentService.class,(mock,context)-> when(mock.processPayment()).thenReturn("Credit"))){ + PaymentProcessor paymentProcessor = new PaymentProcessor(); + Assertions.assertEquals(1,mockPaymentService.constructed().size()); + Assertions.assertEquals("Credit", paymentProcessor.processPayment()); + } + } + + @Test + void whenConstructorInvokedWithoutInitializer_ThenMockObjectShouldBeCreatedWithNullFields(){ + try(MockedConstruction mockPaymentService = Mockito.mockConstruction(PaymentService.class)){ + PaymentProcessor paymentProcessor = new PaymentProcessor(); + Assertions.assertEquals(1,mockPaymentService.constructed().size()); + Assertions.assertNull(paymentProcessor.processPayment()); + } + } + + @Test + void whenConstructorInvokedWithParameters_ThenMockObjectShouldBeCreated(){ + try(MockedConstruction mockPaymentService = Mockito.mockConstruction(PaymentService.class,(mock, context) -> when(mock.processPayment()).thenReturn("Credit"))){ + PaymentProcessor paymentProcessor = new PaymentProcessor("Debit"); + Assertions.assertEquals(1,mockPaymentService.constructed().size()); + Assertions.assertEquals("Credit", paymentProcessor.processPayment()); + } + } + + @Test + void whenMultipleConstructorsInvoked_ThenMultipleMockObjectsShouldBeCreated(){ + try(MockedConstruction mockPaymentService = Mockito.mockConstruction(PaymentService.class)){ + PaymentProcessor paymentProcessor = new PaymentProcessor(); + PaymentProcessor secondPaymentProcessor = new PaymentProcessor(); + PaymentProcessor thirdPaymentProcessor = new PaymentProcessor("Debit"); + + when(mockPaymentService.constructed().get(0).processPayment()).thenReturn("Credit"); + when(mockPaymentService.constructed().get(1).processPayment()).thenReturn("Online Banking"); + + Assertions.assertEquals(3,mockPaymentService.constructed().size()); + Assertions.assertEquals("Credit", paymentProcessor.processPayment()); + Assertions.assertEquals("Online Banking", secondPaymentProcessor.processPayment()); + Assertions.assertNull(thirdPaymentProcessor.processPayment()); + } + } + + @Test + void whenDependencyInjectionIsUsed_ThenMockObjectShouldBeCreated(){ + PaymentService mockPaymentService = Mockito.mock(PaymentService.class); + PaymentProcessor paymentProcessor = new PaymentProcessor(mockPaymentService); + when(mockPaymentService.processPayment()).thenReturn("Online Banking"); + Assertions.assertEquals("Online Banking", paymentProcessor.processPayment()); + } +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/onemethodmultipleparams/OneMethodMultipleParamsUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/onemethodmultipleparams/OneMethodMultipleParamsUnitTest.java new file mode 100644 index 0000000000..0633a5a2f0 --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/onemethodmultipleparams/OneMethodMultipleParamsUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.onemethodmultipleparams; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class OneMethodMultipleParamsUnitTest { + + @Mock + ExampleService exampleService; + + @Test + public void givenAMethod_whenStubbingForMultipleArguments_thenExpectDifferentResults() { + when(exampleService.getValue(10)).thenReturn(100); + when(exampleService.getValue(20)).thenReturn(200); + when(exampleService.getValue(30)).thenReturn(300); + + assertEquals(100, exampleService.getValue(10)); + assertEquals(200, exampleService.getValue(20)); + assertEquals(300, exampleService.getValue(30)); + } + + @Test + public void givenAMethod_whenUsingThenAnswer_thenExpectDifferentReults() { + when(exampleService.getValue(anyInt())).thenAnswer(invocation -> { + int argument = (int) invocation.getArguments()[0]; + int result; + switch (argument) { + case 25: + result = 125; + break; + case 50: + result = 150; + break; + case 75: + result = 175; + break; + default: + result = 0; + } + return result; + }); + assertEquals(125, exampleService.getValue(25)); + assertEquals(150, exampleService.getValue(50)); + assertEquals(175, exampleService.getValue(75)); + } + + @Test + public void givenAMethod_whenUsingConsecutiveStubbing_thenExpectResultsInOrder() { + when(exampleService.getValue(anyInt())).thenReturn(9, 18, 27); + assertEquals(9, exampleService.getValue(1)); + assertEquals(18, exampleService.getValue(1)); + assertEquals(27, exampleService.getValue(1)); + assertEquals(27, exampleService.getValue(1)); + } + +} diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index 108ce29b86..fa72b1e696 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -27,6 +27,7 @@ junit-4 junit-5-advanced junit-5-basics + junit-5-basics-2 junit-5 junit5-annotations junit5-migration diff --git a/testing-modules/testing-assertions/README.md b/testing-modules/testing-assertions/README.md index 37de3d4929..8f94277791 100644 --- a/testing-modules/testing-assertions/README.md +++ b/testing-modules/testing-assertions/README.md @@ -5,3 +5,4 @@ - [Assert That a Java Optional Has a Certain Value](https://www.baeldung.com/java-optional-assert-value) - [Assert That an Object Is From a Specific Type](https://www.baeldung.com/java-assert-object-of-type) - [Asserting Equality on Two Classes Without an equals() Method](https://www.baeldung.com/java-assert-equality-no-equals) +- [Assert Regex Matches in JUnit](https://www.baeldung.com/junit-assert-regex-matches) diff --git a/testing-modules/testing-assertions/src/test/java/com/baeldung/assertregexmatch/AssetRegexMatchUnitTest.java b/testing-modules/testing-assertions/src/test/java/com/baeldung/assertregexmatch/AssetRegexMatchUnitTest.java new file mode 100644 index 0000000000..e5456130e9 --- /dev/null +++ b/testing-modules/testing-assertions/src/test/java/com/baeldung/assertregexmatch/AssetRegexMatchUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.assertregexmatch; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.*; + +public class AssetRegexMatchUnitTest { + + @Test + void whenUsingJunit5assertTrue_thenGetExpectedResult() { + assertTrue("Java at Baeldung".matches(".* at Baeldung$")); + assertFalse("something else".matches(".* at Baeldung$")); + } + + @Test + void whenUsingJunit5assertLinesMatch_thenGetExpectedResult() { + assertLinesMatch(List.of(".* at Baeldung$"), List.of("Kotlin at Baeldung")); + } + + @Test + void whenUsingJunit5assertLinesMatch_thenEqualsIsCheckedFirst() { + assertFalse(".* at Baeldung$".matches(".* at Baeldung$")); + assertLinesMatch(List.of(".* at Baeldung$"), List.of(".* at Baeldung$")); + } + + @Test + void whenUsingAssertJMatches_thenGetExpectedResult() { + org.assertj.core.api.Assertions.assertThat("Linux at Baeldung").matches(".* at Baeldung$"); + org.assertj.core.api.Assertions.assertThat("something unrelated").doesNotMatch(".* at Baeldung$"); + } + + @Test + void whenUsingHamcrestMatches_thenGetExpectedResult() { + org.hamcrest.MatcherAssert.assertThat("Computer science at Baeldung", matchesPattern(".* at Baeldung$")); + org.hamcrest.MatcherAssert.assertThat("something unrelated", not(matchesPattern(".* at Baeldung$"))); + } + +} \ No newline at end of file diff --git a/testing-modules/testing-libraries-2/README.md b/testing-modules/testing-libraries-2/README.md index 9e17da96a7..a37612e207 100644 --- a/testing-modules/testing-libraries-2/README.md +++ b/testing-modules/testing-libraries-2/README.md @@ -7,3 +7,4 @@ - [Gray Box Testing Using the OAT Technique](https://www.baeldung.com/java-gray-box-orthogonal-array-testing) - [Unit Testing of System.in With JUnit](https://www.baeldung.com/java-junit-testing-system-in) - [Fail Maven Build if JUnit Coverage Falls Below Certain Threshold](https://www.baeldung.com/maven-junit-fail-build-coverage-threshold) +- [How to Mock Environment Variables in Unit Tests](https://www.baeldung.com/java-unit-testing-environment-variables) diff --git a/testing-modules/testing-libraries-2/pom.xml b/testing-modules/testing-libraries-2/pom.xml index d74ede07db..717ccac2b2 100644 --- a/testing-modules/testing-libraries-2/pom.xml +++ b/testing-modules/testing-libraries-2/pom.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 testing-libraries-2 testing-libraries-2 @@ -53,6 +53,30 @@ ${system-stubs.version} test + + uk.org.webcompere + system-stubs-testng + ${system-stubs.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.junit-pioneer + junit-pioneer + ${junit.pioneer.version} + test + + + org.testng + testng + ${testng.version} + test + @@ -127,6 +151,9 @@ --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED + + YES + @@ -142,7 +169,10 @@ 0.8.6 1.19.0 1.0.0 - 1.1.0 + 2.1.3 + 7.8.0 + 3.24.2 + 2.1.0 \ No newline at end of file diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesByAbstractionUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesByAbstractionUnitTest.java new file mode 100644 index 0000000000..0ac0603c64 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesByAbstractionUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class EnvironmentVariablesByAbstractionUnitTest { + + @FunctionalInterface + interface GetEnv { + String get(String name); + } + + static class ReadsEnvironment { + private GetEnv getEnv; + + public ReadsEnvironment(GetEnv getEnv) { + this.getEnv = getEnv; + } + + public String whatOs() { + return getEnv.get("OS"); + } + } + + @Test + void givenFakeOs_thenCanReadIt() { + Map fakeEnv = new HashMap<>(); + fakeEnv.put("OS", "MacDowsNix"); + + ReadsEnvironment reader = new ReadsEnvironment(fakeEnv::get); + assertThat(reader.whatOs()).isEqualTo("MacDowsNix"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetByJUnitPioneerUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetByJUnitPioneerUnitTest.java new file mode 100644 index 0000000000..02081a6598 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetByJUnitPioneerUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearEnvironmentVariable; +import org.junitpioneer.jupiter.SetEnvironmentVariable; + +import static org.assertj.core.api.Assertions.assertThat; + +@SetEnvironmentVariable(key = "pioneer", value = "is pioneering") +class EnvironmentVariablesSetByJUnitPioneerUnitTest { + + @Test + void givenEnvironmentVariableIsSetForClass_thenVariableCanBeRead() { + assertThat(System.getenv("pioneer")).isEqualTo("is pioneering"); + } + + @ClearEnvironmentVariable(key = "pioneer") + @Test + void givenEnvironmentVariableIsClear_thenItIsNotSet() { + assertThat(System.getenv("pioneer")).isNull(); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetDirectlyUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetDirectlyUnitTest.java new file mode 100644 index 0000000000..61a3ca3c2e --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSetDirectlyUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +import java.lang.reflect.Field; +import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; + +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_16) +class EnvironmentVariablesSetDirectlyUnitTest { + @BeforeAll + static void beforeAll() throws Exception { + Class classOfMap = System.getenv().getClass(); + Field field = classOfMap.getDeclaredField("m"); + field.setAccessible(true); + Map writeableEnvironmentVariables = (Map)field.get(System.getenv()); + + writeableEnvironmentVariables.put("baeldung", "has set an environment variable"); + } + + @Test + void givenEnvironmentVariableWasSet_thenCanReadIt() { + assertThat(System.getenv("baeldung")).isEqualTo("has set an environment variable"); + } + + @Test + void givenEnvironmentVariableSetBySurefire_thenCanReadIt() { + assertThat(System.getenv("SET_BY_SUREFIRE")).isEqualTo("YES"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemLambdaUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemLambdaUnitTest.java new file mode 100644 index 0000000000..050bebddfd --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemLambdaUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.Test; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; + +import static org.assertj.core.api.Assertions.assertThat; + +class EnvironmentVariablesSystemLambdaUnitTest { + + @Test + void givenSetEnvironmentVariablesInTest_thenCanBeRead() throws Exception { + withEnvironmentVariable("system lambda", "in test") + .execute(() -> { + assertThat(System.getenv("system lambda")).isEqualTo("in test"); + }); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemRulesUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemRulesUnitTest.java new file mode 100644 index 0000000000..44ebb1be71 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemRulesUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EnvironmentVariablesSystemRulesUnitTest { + @Rule + public EnvironmentVariables environmentVariablesRule = new EnvironmentVariables(); + + @Before + public void before() { + environmentVariablesRule.set("system rules", "works"); + } + + @Test + public void givenEnvironmentVariable_thenCanReadIt() { + assertThat(System.getenv("system rules")).isEqualTo("works"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit4UnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit4UnitTest.java new file mode 100644 index 0000000000..efb0ba5598 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit4UnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.Rule; +import org.junit.Test; +import uk.org.webcompere.systemstubs.rules.EnvironmentVariablesRule; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EnvironmentVariablesSystemStubsJUnit4UnitTest { + @Rule + public EnvironmentVariablesRule environmentVariablesRule = + new EnvironmentVariablesRule("system stubs", "initializes variable"); + + @Test + public void givenEnvironmentSetUpInObject_thenCanReadIt() { + assertThat(System.getenv("system stubs")).isEqualTo("initializes variable"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit5UnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit5UnitTest.java new file mode 100644 index 0000000000..1304e4921a --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsJUnit5UnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.environmentvariablesfortest; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(SystemStubsExtension.class) +class EnvironmentVariablesSystemStubsJUnit5UnitTest { + + @SystemStub + private EnvironmentVariables environmentVariables; + + @BeforeEach + void beforeEach() { + environmentVariables.set("systemstubs", "creates stub objects"); + } + + @Test + void givenEnvironmentVariableHasBeenSet_thenCanReadIt() { + assertThat(System.getenv("systemstubs")).isEqualTo("creates stub objects"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkClassScopeEnvironmentUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkClassScopeEnvironmentUnitTest.java new file mode 100644 index 0000000000..9e9421c3f1 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkClassScopeEnvironmentUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; + +import static org.assertj.core.api.Assertions.assertThat; + +class EnvironmentVariablesSystemStubsNoFrameworkClassScopeEnvironmentUnitTest { + private static EnvironmentVariables environmentVariables = new EnvironmentVariables(); + + @BeforeAll + static void beforeAll() throws Exception { + environmentVariables.set("system stubs", "in test"); + environmentVariables.setup(); + } + + @AfterAll + static void afterAll() throws Exception { + environmentVariables.teardown(); + } + + @Test + void givenSetEnvironmentVariablesBeforeAll_thenCanBeRead() throws Exception { + assertThat(System.getenv("system stubs")).isEqualTo("in test"); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkUnitTest.java new file mode 100644 index 0000000000..2e7a92b85f --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsNoFrameworkUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentvariablesfortest; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static uk.org.webcompere.systemstubs.SystemStubs.withEnvironmentVariables; + +class EnvironmentVariablesSystemStubsNoFrameworkUnitTest { + + @Test + void givenSetEnvironmentVariablesInTest_thenCanBeRead() throws Exception { + withEnvironmentVariables("system stubs", "in test") + .execute(() -> { + assertThat(System.getenv("system stubs")).isEqualTo("in test"); + }); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsTestNGUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsTestNGUnitTest.java new file mode 100644 index 0000000000..61ca76a8b0 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/environmentvariablesfortest/EnvironmentVariablesSystemStubsTestNGUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.environmentvariablesfortest; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.testng.SystemStub; +import uk.org.webcompere.systemstubs.testng.SystemStubsListener; +import static org.assertj.core.api.Assertions.assertThat; + +@Listeners(SystemStubsListener.class) +public class EnvironmentVariablesSystemStubsTestNGUnitTest { + @SystemStub + private EnvironmentVariables setEnvironment; + + @BeforeClass + public void beforeAll() { + setEnvironment.set("testng", "has environment variables"); + } + + @Test + public void givenEnvironmentVariableWasSet_thenItCanBeRead() { + assertThat(System.getenv("testng")).isEqualTo("has environment variables"); + } + +} diff --git a/testing-modules/testng/pom.xml b/testing-modules/testng/pom.xml index 62e2b2e578..b0a10b131c 100644 --- a/testing-modules/testng/pom.xml +++ b/testing-modules/testng/pom.xml @@ -25,15 +25,9 @@ testng - - - src/main/resources - true - - - src/main/resources + src/test/resources true diff --git a/testing-modules/zerocode/pom.xml b/testing-modules/zerocode/pom.xml index 15ef45be63..c0aa370096 100644 --- a/testing-modules/zerocode/pom.xml +++ b/testing-modules/zerocode/pom.xml @@ -91,7 +91,6 @@ - 3.0.0-M5 3.0.0-M5 8 8 diff --git a/vaadin/pom.xml b/vaadin/pom.xml index 777ab2551c..aa37a2392a 100644 --- a/vaadin/pom.xml +++ b/vaadin/pom.xml @@ -187,7 +187,6 @@ local mytheme 3.0.0 - 3.3.2 \ No newline at end of file diff --git a/web-modules/blade/pom.xml b/web-modules/blade/pom.xml index 0733556c20..2748c05663 100644 --- a/web-modules/blade/pom.xml +++ b/web-modules/blade/pom.xml @@ -112,7 +112,6 @@ 4.5.6 4.5.6 4.4.10 - 3.0.0-M3 0.7 3.1.0 diff --git a/grails/.gitignore b/web-modules/grails/.gitignore similarity index 100% rename from grails/.gitignore rename to web-modules/grails/.gitignore diff --git a/grails/README.md b/web-modules/grails/README.md similarity index 100% rename from grails/README.md rename to web-modules/grails/README.md diff --git a/grails/build.gradle b/web-modules/grails/build.gradle similarity index 100% rename from grails/build.gradle rename to web-modules/grails/build.gradle diff --git a/grails/gradle.properties b/web-modules/grails/gradle.properties similarity index 100% rename from grails/gradle.properties rename to web-modules/grails/gradle.properties diff --git a/grails/gradle/wrapper/gradle-wrapper.properties b/web-modules/grails/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from grails/gradle/wrapper/gradle-wrapper.properties rename to web-modules/grails/gradle/wrapper/gradle-wrapper.properties diff --git a/grails/gradlew b/web-modules/grails/gradlew similarity index 100% rename from grails/gradlew rename to web-modules/grails/gradlew diff --git a/grails/gradlew.bat b/web-modules/grails/gradlew.bat similarity index 100% rename from grails/gradlew.bat rename to web-modules/grails/gradlew.bat diff --git a/grails/grails-app/assets/images/apple-touch-icon-retina.png b/web-modules/grails/grails-app/assets/images/apple-touch-icon-retina.png similarity index 100% rename from grails/grails-app/assets/images/apple-touch-icon-retina.png rename to web-modules/grails/grails-app/assets/images/apple-touch-icon-retina.png diff --git a/grails/grails-app/assets/images/apple-touch-icon.png b/web-modules/grails/grails-app/assets/images/apple-touch-icon.png similarity index 100% rename from grails/grails-app/assets/images/apple-touch-icon.png rename to web-modules/grails/grails-app/assets/images/apple-touch-icon.png diff --git a/grails/grails-app/assets/images/favicon.ico b/web-modules/grails/grails-app/assets/images/favicon.ico similarity index 100% rename from grails/grails-app/assets/images/favicon.ico rename to web-modules/grails/grails-app/assets/images/favicon.ico diff --git a/grails/grails-app/assets/images/grails-cupsonly-logo-white.svg b/web-modules/grails/grails-app/assets/images/grails-cupsonly-logo-white.svg similarity index 100% rename from grails/grails-app/assets/images/grails-cupsonly-logo-white.svg rename to web-modules/grails/grails-app/assets/images/grails-cupsonly-logo-white.svg diff --git a/grails/grails-app/assets/images/grails.svg b/web-modules/grails/grails-app/assets/images/grails.svg similarity index 100% rename from grails/grails-app/assets/images/grails.svg rename to web-modules/grails/grails-app/assets/images/grails.svg diff --git a/grails/grails-app/assets/images/skin/database_add.png b/web-modules/grails/grails-app/assets/images/skin/database_add.png similarity index 100% rename from grails/grails-app/assets/images/skin/database_add.png rename to web-modules/grails/grails-app/assets/images/skin/database_add.png diff --git a/grails/grails-app/assets/images/skin/database_delete.png b/web-modules/grails/grails-app/assets/images/skin/database_delete.png similarity index 100% rename from grails/grails-app/assets/images/skin/database_delete.png rename to web-modules/grails/grails-app/assets/images/skin/database_delete.png diff --git a/grails/grails-app/assets/images/skin/database_edit.png b/web-modules/grails/grails-app/assets/images/skin/database_edit.png similarity index 100% rename from grails/grails-app/assets/images/skin/database_edit.png rename to web-modules/grails/grails-app/assets/images/skin/database_edit.png diff --git a/grails/grails-app/assets/images/skin/database_save.png b/web-modules/grails/grails-app/assets/images/skin/database_save.png similarity index 100% rename from grails/grails-app/assets/images/skin/database_save.png rename to web-modules/grails/grails-app/assets/images/skin/database_save.png diff --git a/grails/grails-app/assets/images/skin/database_table.png b/web-modules/grails/grails-app/assets/images/skin/database_table.png similarity index 100% rename from grails/grails-app/assets/images/skin/database_table.png rename to web-modules/grails/grails-app/assets/images/skin/database_table.png diff --git a/grails/grails-app/assets/images/skin/exclamation.png b/web-modules/grails/grails-app/assets/images/skin/exclamation.png similarity index 100% rename from grails/grails-app/assets/images/skin/exclamation.png rename to web-modules/grails/grails-app/assets/images/skin/exclamation.png diff --git a/grails/grails-app/assets/images/skin/house.png b/web-modules/grails/grails-app/assets/images/skin/house.png similarity index 100% rename from grails/grails-app/assets/images/skin/house.png rename to web-modules/grails/grails-app/assets/images/skin/house.png diff --git a/grails/grails-app/assets/images/skin/information.png b/web-modules/grails/grails-app/assets/images/skin/information.png similarity index 100% rename from grails/grails-app/assets/images/skin/information.png rename to web-modules/grails/grails-app/assets/images/skin/information.png diff --git a/grails/grails-app/assets/images/skin/shadow.jpg b/web-modules/grails/grails-app/assets/images/skin/shadow.jpg similarity index 100% rename from grails/grails-app/assets/images/skin/shadow.jpg rename to web-modules/grails/grails-app/assets/images/skin/shadow.jpg diff --git a/grails/grails-app/assets/images/skin/sorted_asc.gif b/web-modules/grails/grails-app/assets/images/skin/sorted_asc.gif similarity index 100% rename from grails/grails-app/assets/images/skin/sorted_asc.gif rename to web-modules/grails/grails-app/assets/images/skin/sorted_asc.gif diff --git a/grails/grails-app/assets/images/skin/sorted_desc.gif b/web-modules/grails/grails-app/assets/images/skin/sorted_desc.gif similarity index 100% rename from grails/grails-app/assets/images/skin/sorted_desc.gif rename to web-modules/grails/grails-app/assets/images/skin/sorted_desc.gif diff --git a/grails/grails-app/assets/images/spinner.gif b/web-modules/grails/grails-app/assets/images/spinner.gif similarity index 100% rename from grails/grails-app/assets/images/spinner.gif rename to web-modules/grails/grails-app/assets/images/spinner.gif diff --git a/grails/grails-app/assets/javascripts/application.js b/web-modules/grails/grails-app/assets/javascripts/application.js similarity index 100% rename from grails/grails-app/assets/javascripts/application.js rename to web-modules/grails/grails-app/assets/javascripts/application.js diff --git a/grails/grails-app/assets/javascripts/bootstrap.js b/web-modules/grails/grails-app/assets/javascripts/bootstrap.js similarity index 100% rename from grails/grails-app/assets/javascripts/bootstrap.js rename to web-modules/grails/grails-app/assets/javascripts/bootstrap.js diff --git a/grails/grails-app/assets/javascripts/jquery-2.2.0.min.js b/web-modules/grails/grails-app/assets/javascripts/jquery-2.2.0.min.js similarity index 100% rename from grails/grails-app/assets/javascripts/jquery-2.2.0.min.js rename to web-modules/grails/grails-app/assets/javascripts/jquery-2.2.0.min.js diff --git a/grails/grails-app/assets/stylesheets/application.css b/web-modules/grails/grails-app/assets/stylesheets/application.css similarity index 100% rename from grails/grails-app/assets/stylesheets/application.css rename to web-modules/grails/grails-app/assets/stylesheets/application.css diff --git a/grails/grails-app/assets/stylesheets/bootstrap.css b/web-modules/grails/grails-app/assets/stylesheets/bootstrap.css similarity index 100% rename from grails/grails-app/assets/stylesheets/bootstrap.css rename to web-modules/grails/grails-app/assets/stylesheets/bootstrap.css diff --git a/grails/grails-app/assets/stylesheets/errors.css b/web-modules/grails/grails-app/assets/stylesheets/errors.css similarity index 100% rename from grails/grails-app/assets/stylesheets/errors.css rename to web-modules/grails/grails-app/assets/stylesheets/errors.css diff --git a/grails/grails-app/assets/stylesheets/grails.css b/web-modules/grails/grails-app/assets/stylesheets/grails.css similarity index 100% rename from grails/grails-app/assets/stylesheets/grails.css rename to web-modules/grails/grails-app/assets/stylesheets/grails.css diff --git a/grails/grails-app/assets/stylesheets/main.css b/web-modules/grails/grails-app/assets/stylesheets/main.css similarity index 100% rename from grails/grails-app/assets/stylesheets/main.css rename to web-modules/grails/grails-app/assets/stylesheets/main.css diff --git a/grails/grails-app/assets/stylesheets/mobile.css b/web-modules/grails/grails-app/assets/stylesheets/mobile.css similarity index 100% rename from grails/grails-app/assets/stylesheets/mobile.css rename to web-modules/grails/grails-app/assets/stylesheets/mobile.css diff --git a/grails/grails-app/conf/application.yml b/web-modules/grails/grails-app/conf/application.yml similarity index 100% rename from grails/grails-app/conf/application.yml rename to web-modules/grails/grails-app/conf/application.yml diff --git a/grails/grails-app/conf/logback.groovy b/web-modules/grails/grails-app/conf/logback.groovy similarity index 100% rename from grails/grails-app/conf/logback.groovy rename to web-modules/grails/grails-app/conf/logback.groovy diff --git a/grails/grails-app/conf/spring/resources.groovy b/web-modules/grails/grails-app/conf/spring/resources.groovy similarity index 100% rename from grails/grails-app/conf/spring/resources.groovy rename to web-modules/grails/grails-app/conf/spring/resources.groovy diff --git a/grails/grails-app/controllers/com/baeldung/grails/StudentController.groovy b/web-modules/grails/grails-app/controllers/com/baeldung/grails/StudentController.groovy similarity index 100% rename from grails/grails-app/controllers/com/baeldung/grails/StudentController.groovy rename to web-modules/grails/grails-app/controllers/com/baeldung/grails/StudentController.groovy diff --git a/grails/grails-app/controllers/grails/UrlMappings.groovy b/web-modules/grails/grails-app/controllers/grails/UrlMappings.groovy similarity index 100% rename from grails/grails-app/controllers/grails/UrlMappings.groovy rename to web-modules/grails/grails-app/controllers/grails/UrlMappings.groovy diff --git a/grails/grails-app/domain/com/baeldung/grails/Student.groovy b/web-modules/grails/grails-app/domain/com/baeldung/grails/Student.groovy similarity index 100% rename from grails/grails-app/domain/com/baeldung/grails/Student.groovy rename to web-modules/grails/grails-app/domain/com/baeldung/grails/Student.groovy diff --git a/grails/grails-app/i18n/messages.properties b/web-modules/grails/grails-app/i18n/messages.properties similarity index 100% rename from grails/grails-app/i18n/messages.properties rename to web-modules/grails/grails-app/i18n/messages.properties diff --git a/grails/grails-app/i18n/messages_cs.properties b/web-modules/grails/grails-app/i18n/messages_cs.properties similarity index 100% rename from grails/grails-app/i18n/messages_cs.properties rename to web-modules/grails/grails-app/i18n/messages_cs.properties diff --git a/grails/grails-app/i18n/messages_da.properties b/web-modules/grails/grails-app/i18n/messages_da.properties similarity index 100% rename from grails/grails-app/i18n/messages_da.properties rename to web-modules/grails/grails-app/i18n/messages_da.properties diff --git a/grails/grails-app/i18n/messages_de.properties b/web-modules/grails/grails-app/i18n/messages_de.properties similarity index 100% rename from grails/grails-app/i18n/messages_de.properties rename to web-modules/grails/grails-app/i18n/messages_de.properties diff --git a/grails/grails-app/i18n/messages_es.properties b/web-modules/grails/grails-app/i18n/messages_es.properties similarity index 100% rename from grails/grails-app/i18n/messages_es.properties rename to web-modules/grails/grails-app/i18n/messages_es.properties diff --git a/grails/grails-app/i18n/messages_fr.properties b/web-modules/grails/grails-app/i18n/messages_fr.properties similarity index 100% rename from grails/grails-app/i18n/messages_fr.properties rename to web-modules/grails/grails-app/i18n/messages_fr.properties diff --git a/grails/grails-app/i18n/messages_it.properties b/web-modules/grails/grails-app/i18n/messages_it.properties similarity index 100% rename from grails/grails-app/i18n/messages_it.properties rename to web-modules/grails/grails-app/i18n/messages_it.properties diff --git a/grails/grails-app/i18n/messages_ja.properties b/web-modules/grails/grails-app/i18n/messages_ja.properties similarity index 100% rename from grails/grails-app/i18n/messages_ja.properties rename to web-modules/grails/grails-app/i18n/messages_ja.properties diff --git a/grails/grails-app/i18n/messages_nb.properties b/web-modules/grails/grails-app/i18n/messages_nb.properties similarity index 100% rename from grails/grails-app/i18n/messages_nb.properties rename to web-modules/grails/grails-app/i18n/messages_nb.properties diff --git a/grails/grails-app/i18n/messages_nl.properties b/web-modules/grails/grails-app/i18n/messages_nl.properties similarity index 100% rename from grails/grails-app/i18n/messages_nl.properties rename to web-modules/grails/grails-app/i18n/messages_nl.properties diff --git a/grails/grails-app/i18n/messages_pl.properties b/web-modules/grails/grails-app/i18n/messages_pl.properties similarity index 100% rename from grails/grails-app/i18n/messages_pl.properties rename to web-modules/grails/grails-app/i18n/messages_pl.properties diff --git a/grails/grails-app/i18n/messages_pt_BR.properties b/web-modules/grails/grails-app/i18n/messages_pt_BR.properties similarity index 100% rename from grails/grails-app/i18n/messages_pt_BR.properties rename to web-modules/grails/grails-app/i18n/messages_pt_BR.properties diff --git a/grails/grails-app/i18n/messages_pt_PT.properties b/web-modules/grails/grails-app/i18n/messages_pt_PT.properties similarity index 100% rename from grails/grails-app/i18n/messages_pt_PT.properties rename to web-modules/grails/grails-app/i18n/messages_pt_PT.properties diff --git a/grails/grails-app/i18n/messages_ru.properties b/web-modules/grails/grails-app/i18n/messages_ru.properties similarity index 100% rename from grails/grails-app/i18n/messages_ru.properties rename to web-modules/grails/grails-app/i18n/messages_ru.properties diff --git a/grails/grails-app/i18n/messages_sk.properties b/web-modules/grails/grails-app/i18n/messages_sk.properties similarity index 100% rename from grails/grails-app/i18n/messages_sk.properties rename to web-modules/grails/grails-app/i18n/messages_sk.properties diff --git a/grails/grails-app/i18n/messages_sv.properties b/web-modules/grails/grails-app/i18n/messages_sv.properties similarity index 100% rename from grails/grails-app/i18n/messages_sv.properties rename to web-modules/grails/grails-app/i18n/messages_sv.properties diff --git a/grails/grails-app/i18n/messages_th.properties b/web-modules/grails/grails-app/i18n/messages_th.properties similarity index 100% rename from grails/grails-app/i18n/messages_th.properties rename to web-modules/grails/grails-app/i18n/messages_th.properties diff --git a/grails/grails-app/i18n/messages_zh_CN.properties b/web-modules/grails/grails-app/i18n/messages_zh_CN.properties similarity index 100% rename from grails/grails-app/i18n/messages_zh_CN.properties rename to web-modules/grails/grails-app/i18n/messages_zh_CN.properties diff --git a/grails/grails-app/init/grails/Application.groovy b/web-modules/grails/grails-app/init/grails/Application.groovy similarity index 100% rename from grails/grails-app/init/grails/Application.groovy rename to web-modules/grails/grails-app/init/grails/Application.groovy diff --git a/grails/grails-app/init/grails/BootStrap.groovy b/web-modules/grails/grails-app/init/grails/BootStrap.groovy similarity index 100% rename from grails/grails-app/init/grails/BootStrap.groovy rename to web-modules/grails/grails-app/init/grails/BootStrap.groovy diff --git a/grails/grails-app/services/com/baeldung/grails/StudentService.groovy b/web-modules/grails/grails-app/services/com/baeldung/grails/StudentService.groovy similarity index 100% rename from grails/grails-app/services/com/baeldung/grails/StudentService.groovy rename to web-modules/grails/grails-app/services/com/baeldung/grails/StudentService.groovy diff --git a/grails/grails-app/views/error.gsp b/web-modules/grails/grails-app/views/error.gsp similarity index 100% rename from grails/grails-app/views/error.gsp rename to web-modules/grails/grails-app/views/error.gsp diff --git a/grails/grails-app/views/index.gsp b/web-modules/grails/grails-app/views/index.gsp similarity index 100% rename from grails/grails-app/views/index.gsp rename to web-modules/grails/grails-app/views/index.gsp diff --git a/grails/grails-app/views/layouts/main.gsp b/web-modules/grails/grails-app/views/layouts/main.gsp similarity index 100% rename from grails/grails-app/views/layouts/main.gsp rename to web-modules/grails/grails-app/views/layouts/main.gsp diff --git a/grails/grails-app/views/notFound.gsp b/web-modules/grails/grails-app/views/notFound.gsp similarity index 100% rename from grails/grails-app/views/notFound.gsp rename to web-modules/grails/grails-app/views/notFound.gsp diff --git a/grails/grails-app/views/student/create.gsp b/web-modules/grails/grails-app/views/student/create.gsp similarity index 100% rename from grails/grails-app/views/student/create.gsp rename to web-modules/grails/grails-app/views/student/create.gsp diff --git a/grails/grails-app/views/student/index.gsp b/web-modules/grails/grails-app/views/student/index.gsp similarity index 100% rename from grails/grails-app/views/student/index.gsp rename to web-modules/grails/grails-app/views/student/index.gsp diff --git a/grails/grails-app/views/student/show.gsp b/web-modules/grails/grails-app/views/student/show.gsp similarity index 100% rename from grails/grails-app/views/student/show.gsp rename to web-modules/grails/grails-app/views/student/show.gsp diff --git a/grails/grailsw b/web-modules/grails/grailsw similarity index 100% rename from grails/grailsw rename to web-modules/grails/grailsw diff --git a/grails/grailsw.bat b/web-modules/grails/grailsw.bat similarity index 100% rename from grails/grailsw.bat rename to web-modules/grails/grailsw.bat diff --git a/grails/src/integration-test/groovy/com/baeldung/grails/StudentIntegrationSpec.groovy b/web-modules/grails/src/integration-test/groovy/com/baeldung/grails/StudentIntegrationSpec.groovy similarity index 100% rename from grails/src/integration-test/groovy/com/baeldung/grails/StudentIntegrationSpec.groovy rename to web-modules/grails/src/integration-test/groovy/com/baeldung/grails/StudentIntegrationSpec.groovy diff --git a/grails/src/integration-test/resources/GebConfig.groovy b/web-modules/grails/src/integration-test/resources/GebConfig.groovy similarity index 100% rename from grails/src/integration-test/resources/GebConfig.groovy rename to web-modules/grails/src/integration-test/resources/GebConfig.groovy diff --git a/grails/src/test/groovy/com/baeldung/grails/StudentControllerSpec.groovy b/web-modules/grails/src/test/groovy/com/baeldung/grails/StudentControllerSpec.groovy similarity index 100% rename from grails/src/test/groovy/com/baeldung/grails/StudentControllerSpec.groovy rename to web-modules/grails/src/test/groovy/com/baeldung/grails/StudentControllerSpec.groovy diff --git a/web-modules/javax-servlets-2/README.md b/web-modules/javax-servlets-2/README.md index cd599890ad..179264f90a 100644 --- a/web-modules/javax-servlets-2/README.md +++ b/web-modules/javax-servlets-2/README.md @@ -5,3 +5,4 @@ This module contains articles about Servlets. ### Relevant Articles: - [Check if a User Is Logged-in With Servlets and JSP](https://www.baeldung.com/servlets-jsp-check-user-login) - [How to Mock HttpServletRequest](https://www.baeldung.com/java-httpservletrequest-mock) +- [Set a Parameter in an HttpServletRequest in Java](https://www.baeldung.com/java-servlet-request-set-parameter) diff --git a/web-modules/javax-servlets-2/pom.xml b/web-modules/javax-servlets-2/pom.xml index 81616e0055..9ba12352fd 100644 --- a/web-modules/javax-servlets-2/pom.xml +++ b/web-modules/javax-servlets-2/pom.xml @@ -22,6 +22,11 @@ commons-fileupload ${commons-fileupload.version} + + org.apache.commons + commons-text + ${commons-text.version} + javax.servlet @@ -76,6 +81,16 @@ + + org.eclipse.jetty + jetty-maven-plugin + ${jetty-maven-plugin.version} + + + / + + + @@ -84,6 +99,8 @@ 1.49 5.3.20 2.22.2 + 10.0.4 + 1.10.0 \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java new file mode 100644 index 0000000000..983066ec51 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java @@ -0,0 +1,21 @@ +package com.baeldung.setparam; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.*; + +@WebServlet(name = "LanguageServlet", urlPatterns = "/setparam/lang") +public class LanguageServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + + SetParameterRequestWrapper requestWrapper = new SetParameterRequestWrapper(request); + requestWrapper.setParameter("locale", Locale.getDefault().getLanguage()); + request.getRequestDispatcher("/setparam/3rd_party_module.jsp").forward(requestWrapper, response); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java new file mode 100644 index 0000000000..3f93591bd9 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java @@ -0,0 +1,17 @@ +package com.baeldung.setparam; + +import java.io.IOException; +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; + +@WebFilter(urlPatterns = { "/setparam/with-sanitize.jsp" }) +public class SanitizeParametersFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpReq = (HttpServletRequest) request; + chain.doFilter(new SanitizeParametersRequestWrapper(httpReq), response); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java new file mode 100644 index 0000000000..e4c2870ca6 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java @@ -0,0 +1,46 @@ +package com.baeldung.setparam; + +import java.util.*; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.text.StringEscapeUtils; + +public class SanitizeParametersRequestWrapper extends HttpServletRequestWrapper { + + private final Map sanitizedMap; + + public SanitizeParametersRequestWrapper(HttpServletRequest request) { + super(request); + sanitizedMap = Collections.unmodifiableMap( + request.getParameterMap().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> Arrays.stream(entry.getValue()) + .map(StringEscapeUtils::escapeHtml4) + .toArray(String[]::new) + ))); + } + + @Override + public Map getParameterMap() { + return sanitizedMap; + } + + @Override + public String[] getParameterValues(String name) { + return Optional.ofNullable(getParameterMap().get(name)) + .map(values -> Arrays.copyOf(values, values.length)) + .orElse(null); + } + + @Override + public String getParameter(String name) { + return Optional.ofNullable(getParameterValues(name)) + .map(values -> values[0]) + .orElse(null); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java new file mode 100644 index 0000000000..7b2ab4597c --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java @@ -0,0 +1,40 @@ +package com.baeldung.setparam; + +import java.util.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +public class SetParameterRequestWrapper extends HttpServletRequestWrapper { + + private final Map paramMap; + + public SetParameterRequestWrapper(HttpServletRequest request) { + super(request); + paramMap = new HashMap<>(request.getParameterMap()); + } + + @Override + public Map getParameterMap() { + return Collections.unmodifiableMap(paramMap); + } + + @Override + public String[] getParameterValues(String name) { + return Optional.ofNullable(getParameterMap().get(name)) + .map(values -> Arrays.copyOf(values, values.length)) + .orElse(null); + } + + @Override + public String getParameter(String name) { + return Optional.ofNullable(getParameterValues(name)) + .map(values -> values[0]) + .orElse(null); + } + + public void setParameter(String name, String value) { + paramMap.put(name, new String[] {value}); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp new file mode 100644 index 0000000000..9ab4fd2c00 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp @@ -0,0 +1,13 @@ +<%@ page import="java.util.*"%> + + + 3rd party Module + + + <% + String localeStr = request.getParameter("locale"); + Locale currentLocale = (localeStr != null ? new Locale(localeStr) : null); + %> + The language you have selected: <%=currentLocale != null ? currentLocale.getDisplayLanguage(currentLocale) : " None"%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp new file mode 100644 index 0000000000..68704d6133 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp @@ -0,0 +1,10 @@ + + + Sanitized request parameter + + + The text below comes from request parameter "input": +
+ <%=request.getParameter("input")%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp new file mode 100644 index 0000000000..f5437164ef --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp @@ -0,0 +1,10 @@ + + + Non sanitized request parameter + + + The text below comes from request parameter "input": +
+ <%=request.getParameter("input")%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java new file mode 100644 index 0000000000..c539ce63b9 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java @@ -0,0 +1,34 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.util.Locale; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class LanguageServletLiveTest { + + @Test + public void whenGetRequestUsingHttpClient_thenResponseBodyContainsDefaultLanguage() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet("http://localhost:8080/setparam/lang"); + HttpResponse httpResponse = client.execute(method); + + // Then + Locale defaultLocale = Locale.getDefault(); + String expectedLanguage = defaultLocale.getDisplayLanguage(defaultLocale); + + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains("The language you have selected: " + expectedLanguage)); + } + +} diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java new file mode 100644 index 0000000000..5fffea1824 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java @@ -0,0 +1,40 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.BeforeClass; +import org.junit.Test; + +public class SanitizeParametersRequestLiveTest { + + private static String PARAM_INPUT; + + @BeforeClass + public static void init() throws UnsupportedEncodingException { + PARAM_INPUT = URLEncoder.encode("", "UTF-8"); + } + + @Test + public void whenInputParameterContainsXss_thenResponseBodyContainsSanitizedValue() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/with-sanitize.jsp?input=%s", PARAM_INPUT)); + HttpResponse httpResponse = client.execute(method); + + // Then + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains("<script>alert('Hello');</script>")); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java new file mode 100644 index 0000000000..029cf41d1c --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SanitizeParametersRequestWrapperUnitTest { + + private static final String NEW_VALUE = "NEW VALUE"; + + private Map parameterMap; + + @Mock + private HttpServletRequest request; + + @Before + public void initBeforeEachTest() { + parameterMap = new HashMap<>(); + parameterMap.put("input", new String[] {""}); + when(request.getParameterMap()).thenReturn(parameterMap); + } + + @Test + public void whenGetParameterViaWrapper_thenParameterReturnedIsSanitized() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + String actualValue = wrapper.getParameter("input"); + + assertEquals("<script>alert('Hello');</script>", actualValue); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + Map wrapperParamMap = wrapper.getParameterMap(); + wrapperParamMap.put("input", new String[] {NEW_VALUE}); + } + + @Test + public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + String[] firstCallValues = wrapper.getParameterValues("input"); + + firstCallValues[0] = NEW_VALUE; + String[] secondCallValues = wrapper.getParameterValues("input"); + assertThat(secondCallValues).doesNotContain(NEW_VALUE); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java new file mode 100644 index 0000000000..8ef5307d44 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.setparam; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SetParameterRequestWrapperUnitTest { + + private static final String NEW_VALUE = "NEW VALUE"; + + private Map parameterMap; + + @Mock + private HttpServletRequest request; + + @Before + public void initBeforeEachTest() { + parameterMap = new HashMap<>(); + parameterMap.put("input", new String[] {"inputValue"}); + when(request.getParameterMap()).thenReturn(parameterMap); + } + + @Test + public void whenSetParameterViaWrapper_thenGetParameterShouldReturnTheSameValue() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + wrapper.setParameter("newInput", "newInputValue"); + String actualValue = wrapper.getParameter("newInput"); + + assertEquals("newInputValue", actualValue); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + Map wrapperParamMap = wrapper.getParameterMap(); + wrapperParamMap.put("input", new String[] {NEW_VALUE}); + } + + @Test + public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + String[] firstCallValues = wrapper.getParameterValues("input"); + + firstCallValues[0] = NEW_VALUE; + String[] secondCallValues = wrapper.getParameterValues("input"); + assertThat(secondCallValues).doesNotContain(NEW_VALUE); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java new file mode 100644 index 0000000000..f6cc566bfc --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java @@ -0,0 +1,42 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UnsanitizedParametersRequestLiveTest { + + private static final String TAG_SCRIPT = ""; + + private static String PARAM_INPUT; + + @BeforeClass + public static void init() throws UnsupportedEncodingException { + PARAM_INPUT = URLEncoder.encode(TAG_SCRIPT, "UTF-8"); + } + + @Test + public void whenInputParameterContainsXss_thenResponseBodyContainsUnsanitizedValue() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/without-sanitize.jsp?input=%s", PARAM_INPUT)); + HttpResponse httpResponse = client.execute(method); + + // Then + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains(TAG_SCRIPT)); + } + +} \ No newline at end of file diff --git a/web-modules/pom.xml b/web-modules/pom.xml index c009837186..57810f90de 100644 --- a/web-modules/pom.xml +++ b/web-modules/pom.xml @@ -19,6 +19,7 @@ bootique dropwizard google-web-toolkit + jakarta-ee javax-servlets @@ -26,12 +27,12 @@ jee-7 jooby linkrest - + ratpack resteasy - + restx spark-java struts-2 vraptor diff --git a/web-modules/restx/md.restx.json b/web-modules/restx/md.restx.json index c87244001c..54a1b4e9f8 100644 --- a/web-modules/restx/md.restx.json +++ b/web-modules/restx/md.restx.json @@ -3,8 +3,8 @@ "packaging": "war", "properties": { - "java.version": "1.8", - "restx.version": "0.35-rc4" + "java.version": "17", + "restx.version": "1.0.0-rc3" }, "fragments": { "maven": [ @@ -24,7 +24,7 @@ "io.restx:restx-i18n-admin:${restx.version}", "io.restx:restx-stats-admin:${restx.version}", "io.restx:restx-servlet:${restx.version}", - "io.restx:restx-server-jetty8:${restx.version}!optional", + "io.restx:restx-server-jetty11:${restx.version}!optional", "io.restx:restx-apidocs:${restx.version}", "io.restx:restx-specs-admin:${restx.version}", "io.restx:restx-admin:${restx.version}", diff --git a/web-modules/restx/pom.xml b/web-modules/restx/pom.xml index 0e6cb3fa78..f75292a4a4 100644 --- a/web-modules/restx/pom.xml +++ b/web-modules/restx/pom.xml @@ -77,7 +77,7 @@
io.restx - restx-server-jetty8 + restx-server-jetty11 ${restx.version} true @@ -137,8 +137,7 @@ - 0.35-rc4 - 1.6.0 + 1.0.0-rc3 \ No newline at end of file diff --git a/web-modules/restx/src/main/java/restx/demo/AppModule.java b/web-modules/restx/src/main/java/restx/demo/AppModule.java index 26bc681481..b47f8b9aa8 100644 --- a/web-modules/restx/src/main/java/restx/demo/AppModule.java +++ b/web-modules/restx/src/main/java/restx/demo/AppModule.java @@ -3,13 +3,13 @@ package restx.demo; import restx.config.ConfigLoader; import restx.config.ConfigSupplier; import restx.factory.Provides; +import restx.security.*; +import restx.factory.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableSet; -import restx.security.*; -import restx.factory.Module; -import restx.factory.Provides; + import javax.inject.Named; import java.nio.file.Paths; @@ -30,7 +30,7 @@ public class AppModule { @Provides public ConfigSupplier appConfigSupplier(ConfigLoader configLoader) { // Load settings.properties in restx.demo package as a set of config entries - return configLoader.fromResource("restx/demo/settings"); + return configLoader.fromResource("web-modules/restx/demo/settings"); } @Provides diff --git a/web-modules/restx/src/main/java/restx/demo/AppServer.java b/web-modules/restx/src/main/java/restx/demo/AppServer.java index d66aadac68..089a22c9ae 100644 --- a/web-modules/restx/src/main/java/restx/demo/AppServer.java +++ b/web-modules/restx/src/main/java/restx/demo/AppServer.java @@ -2,7 +2,7 @@ package restx.demo; import com.google.common.base.Optional; import restx.server.WebServer; -import restx.server.Jetty8WebServer; +import restx.server.Jetty11WebServer; /** * This class can be used to run the app. @@ -17,7 +17,7 @@ public class AppServer { public static void main(String[] args) throws Exception { int port = Integer.valueOf(Optional.fromNullable(System.getenv("PORT")).or("8080")); - WebServer server = new Jetty8WebServer(WEB_INF_LOCATION, WEB_APP_LOCATION, port, "0.0.0.0"); + WebServer server = new Jetty11WebServer(WEB_INF_LOCATION, WEB_APP_LOCATION, port, "0.0.0.0"); /* * load mode from system property if defined, or default to dev diff --git a/web-modules/wicket/pom.xml b/web-modules/wicket/pom.xml index 9348e15cdb..244d176e25 100644 --- a/web-modules/wicket/pom.xml +++ b/web-modules/wicket/pom.xml @@ -84,7 +84,6 @@ 7.5.0 9.2.13.v20150730 - 3.3.1 \ No newline at end of file diff --git a/xml-2/pom.xml b/xml-2/pom.xml index d56fdd7165..0f94588ba0 100644 --- a/xml-2/pom.xml +++ b/xml-2/pom.xml @@ -46,6 +46,16 @@ underscore ${underscore.version} + + org.apache.xmlbeans + xmlbeans + 5.0.2 + + + org.apache.logging.log4j + log4j-core + 2.12.4 + @@ -70,9 +80,8 @@ 2.1.3 - 2.14.1 20230227 1.89 - \ No newline at end of file + diff --git a/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java b/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java index 7d8f531bfa..57eccab193 100644 --- a/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java +++ b/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java @@ -44,7 +44,7 @@ public class XmlValidator { try { validator.validate(new StreamSource(getFile(xmlPath))); } catch (SAXParseException e) {} - xsdErrorHandler.getExceptions().forEach(e -> LOGGER.info(e.getMessage())); + xsdErrorHandler.getExceptions().forEach(e -> LOGGER.info(String.format("Line number: %s, Column number: %s. %s", e.getLineNumber(), e.getColumnNumber(), e.getMessage()))); return xsdErrorHandler.getExceptions(); } diff --git a/xml-2/src/main/resources/log4j2.xml b/xml-2/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..f022ab633b --- /dev/null +++ b/xml-2/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/xml-2/src/test/java/com/baeldung/xml/xml2document/XMLStringToDocumentObjectUnitTest.java b/xml-2/src/test/java/com/baeldung/xml/xml2document/XMLStringToDocumentObjectUnitTest.java new file mode 100644 index 0000000000..f573e1c96d --- /dev/null +++ b/xml-2/src/test/java/com/baeldung/xml/xml2document/XMLStringToDocumentObjectUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.xml2document; + +import org.junit.Test; +import org.w3c.dom.*; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import java.io.IOException; +import java.io.StringReader; + +import static org.junit.Assert.assertEquals; + +public class XMLStringToDocumentObjectUnitTest { + @Test + public void givenValidXMLString_whenParsing_thenDocumentIsCorrect() throws ParserConfigurationException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + String xmlString = "XML Parsing Example"; + InputSource is = new InputSource(new StringReader(xmlString)); + Document xmlDoc = null; + try { + xmlDoc = builder.parse(is); + } catch (SAXException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + + assertEquals("root", xmlDoc.getDocumentElement().getNodeName()); + assertEquals("element", xmlDoc.getDocumentElement().getElementsByTagName("element").item(0).getNodeName()); + assertEquals("XML Parsing Example", xmlDoc.getDocumentElement().getElementsByTagName("element").item(0).getTextContent()); + } +} diff --git a/xml-2/src/test/java/com/baeldung/xml/xml2string/XMLObjectToStringUnitTest.java b/xml-2/src/test/java/com/baeldung/xml/xml2string/XMLObjectToStringUnitTest.java new file mode 100644 index 0000000000..0afa3424f3 --- /dev/null +++ b/xml-2/src/test/java/com/baeldung/xml/xml2string/XMLObjectToStringUnitTest.java @@ -0,0 +1,87 @@ +package com.baeldung.xml2string; + +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlObject; +import org.apache.xmlbeans.XmlOptions; +import org.junit.Test; +import org.junit.Before; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.StringWriter; + +import static org.junit.Assert.assertTrue; + +public class XMLObjectToStringUnitTest { + private Document document; + + @Before + public void setup() throws ParserConfigurationException { +// Create a DocumentBuilder + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + +// Create a new Document + document = builder.newDocument(); + +// Create the root element + Element rootElement = document.createElement("root"); + document.appendChild(rootElement); + +// Create child elements + Element childElement1 = document.createElement("child1"); + Element childElement2 = document.createElement("child2"); + +// Add text content to the child elements + childElement1.appendChild(document.createTextNode("This is child element 1")); + childElement2.appendChild(document.createTextNode("This is child element 2")); + +// Append child elements to the root element + rootElement.appendChild(childElement1); + rootElement.appendChild(childElement2); + } + + @Test + public void givenXMLDocument_whenUsingTransformer_thenConvertXMLToString() throws TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + StringWriter stringWriter = new StringWriter(); + transformer.transform(new DOMSource(document), new StreamResult(stringWriter)); + String result = stringWriter.toString(); + + assertTrue(result.contains("")); + assertTrue(result.contains("This is child element 1")); + assertTrue(result.contains("This is child element 2")); + } + + @Test + public void givenXMLDocument_whenUsingXmlBeans_thenConvertXMLToString() { + try { + + XmlObject xmlObject = XmlObject.Factory.parse(document); + + XmlOptions options = new XmlOptions(); + options.setSavePrettyPrint(); + options.setUseDefaultNamespace(); + options.setSaveAggressiveNamespaces(); + + String xmlString = xmlObject.xmlText(options); + + xmlString = "" + xmlString; + + assertTrue(xmlString.contains("")); + assertTrue(xmlString.contains("This is child element 1")); + assertTrue(xmlString.contains("This is child element 2")); + } catch (XmlException e) { + e.printStackTrace(); + } + } +}