diff --git a/.gitignore b/.gitignore index 7b448f6cb0..7f1bab3751 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,8 @@ ethereum/logs/ jmeter/src/main/resources/*-JMeter.csv jmeter/src/main/resources/*-Basic*.csv jmeter/src/main/resources/*-JMeter*.csv +jmeter/src/main/resources/*ReportsDashboard*.csv +jmeter/src/main/resources/dashboard/*ReportsDashboard*.csv ninja/devDb.mv.db @@ -105,4 +107,11 @@ spring-boot-modules/spring-boot-properties-3/*.log .sdkmanrc # Localstack -**/.localstack \ No newline at end of file +**/.localstack + +#libraries-2 +libraries-2/employee* +libraries-2/src/test/resources/crawler4j/** + +#web-modules/ninja +devDb*.db \ No newline at end of file diff --git a/README.md b/README.md index 1ae225b1f3..b354a8f819 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,11 @@ The projects are broadly divided into 3 lists: first, second and heavy. Next, they are segregated further on the basis of the tests that we want to execute. -Additionally, there are 2 profiles dedicated for JDK9 and above builds. +Additionally, there are 2 profiles dedicated for JDK9 and above builds - **which require JDK 17**. -Therefore, we have a total of 8 profiles: +We also have a parents profile to build only parent modules. + +Therefore, we have a total of 9 profiles: | Profile | Includes | Type of test enabled | | -------------------------- | --------------------------- | -------------------- | @@ -45,6 +47,7 @@ Therefore, we have a total of 8 profiles: | integration-heavy | Heavy/long running projects | *IntegrationTest | | default-jdk9-and-above | JDK9 and above projects | *UnitTest | | integration-jdk9-and-above | JDK9 and above projects | *IntegrationTest | +| parents | Set of parent modules | None | Building the project ==================== @@ -71,6 +74,17 @@ Building a single module ==================== To build a specific module, run the command: `mvn clean install` in the module directory. +It can happen that your module is part of a parent module e.g. `parent-boot-1`,`parent-spring-5` etc, then you will need to build the parent module first so that you can build your module. +We have created a `parents` profile that you can use to build just the parent modules, just run the profile as: +`mvn clean install -Pparents` + + +Building modules from the root of the repository +==================== +To build specific modules from the root of the repository, run the command: `mvn clean install --pl asm,atomikos -Pdefault-first` in the root directory. + +Here `asm` and `atomikos` are the modules that we want to build and `default-first` is the maven profile in which these modules are present. + Running a Spring Boot module ==================== diff --git a/akka-modules/akka-http/pom.xml b/akka-modules/akka-http/pom.xml index 9372107fc9..3af7c492ca 100644 --- a/akka-modules/akka-http/pom.xml +++ b/akka-modules/akka-http/pom.xml @@ -36,6 +36,7 @@ + 10.0.11 2.5.11 diff --git a/akka-modules/spring-akka/pom.xml b/akka-modules/spring-akka/pom.xml index 7451a40b86..2201181435 100644 --- a/akka-modules/spring-akka/pom.xml +++ b/akka-modules/spring-akka/pom.xml @@ -43,7 +43,7 @@ - 4.3.4.RELEASE + 5.3.25 2.4.14 diff --git a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/AntColonyOptimizationLongRunningUnitTest.java b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/AntColonyOptimizationLongRunningUnitTest.java index 2ac7adc3aa..f828d148ba 100644 --- a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/AntColonyOptimizationLongRunningUnitTest.java +++ b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/AntColonyOptimizationLongRunningUnitTest.java @@ -1,22 +1,24 @@ package com.baeldung.algorithms; -import org.junit.Assert; -import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization; -public class AntColonyOptimizationLongRunningUnitTest { +class AntColonyOptimizationLongRunningUnitTest { @Test - public void testGenerateRandomMatrix() { + void testGenerateRandomMatrix() { AntColonyOptimization antTSP = new AntColonyOptimization(5); - Assert.assertNotNull(antTSP.generateRandomMatrix(5)); + assertNotNull(antTSP.generateRandomMatrix(5)); } @Test - public void testStartAntOptimization() { + void testStartAntOptimization() { AntColonyOptimization antTSP = new AntColonyOptimization(5); - Assert.assertNotNull(antTSP.solve()); + assertNotNull(antTSP.solve()); } } diff --git a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmLongRunningUnitTest.java b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmLongRunningUnitTest.java index e819da4b36..a2f869e171 100644 --- a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmLongRunningUnitTest.java +++ b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmLongRunningUnitTest.java @@ -1,16 +1,19 @@ package com.baeldung.algorithms; -import org.junit.Assert; -import org.junit.Test; + + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm; -public class BinaryGeneticAlgorithmLongRunningUnitTest { +class BinaryGeneticAlgorithmLongRunningUnitTest { @Test - public void testGA() { + void testGA() { SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm(); - Assert.assertTrue(ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111")); + assertTrue(ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111")); } } diff --git a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/SimulatedAnnealingLongRunningUnitTest.java b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/SimulatedAnnealingLongRunningUnitTest.java index 2ce7d75e43..461e3e9128 100644 --- a/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/SimulatedAnnealingLongRunningUnitTest.java +++ b/algorithms-modules/algorithms-genetic/src/test/java/com/baeldung/algorithms/SimulatedAnnealingLongRunningUnitTest.java @@ -1,15 +1,17 @@ package com.baeldung.algorithms; -import org.junit.Assert; -import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing; -public class SimulatedAnnealingLongRunningUnitTest { +class SimulatedAnnealingLongRunningUnitTest { @Test - public void testSimulateAnnealing() { - Assert.assertTrue(SimulatedAnnealing.simulateAnnealing(10, 1000, 0.9) > 0); + void testSimulateAnnealing() { + assertTrue(SimulatedAnnealing.simulateAnnealing(10, 1000, 0.9) > 0); } } diff --git a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/HillClimbingAlgorithmUnitTest.java b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/HillClimbingAlgorithmUnitTest.java index e817d195b3..4e8f927750 100644 --- a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/HillClimbingAlgorithmUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/HillClimbingAlgorithmUnitTest.java @@ -1,23 +1,25 @@ package com.baeldung.algorithms; +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 org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import com.baeldung.algorithms.hillclimbing.HillClimbing; import com.baeldung.algorithms.hillclimbing.State; -import org.junit.Before; -import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Stack; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -public class HillClimbingAlgorithmUnitTest { +class HillClimbingAlgorithmUnitTest { private Stack initStack; private Stack goalStack; - @Before + @BeforeEach public void initStacks() { String blockArr[] = { "B", "C", "D", "A" }; String goalBlockArr[] = { "A", "B", "C", "D" }; @@ -30,7 +32,7 @@ public class HillClimbingAlgorithmUnitTest { } @Test - public void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() { + void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() { HillClimbing hillClimbing = new HillClimbing(); List path; @@ -46,7 +48,7 @@ public class HillClimbingAlgorithmUnitTest { } @Test - public void givenCurrentState_whenFindNextState_thenBetterHeuristics() { + void givenCurrentState_whenFindNextState_thenBetterHeuristics() { HillClimbing hillClimbing = new HillClimbing(); List> initList = new ArrayList<>(); initList.add(initStack); diff --git a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/RtFiniteStateMachineLongRunningUnitTest.java b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/RtFiniteStateMachineLongRunningUnitTest.java index fddccfcd9f..f3e896541d 100644 --- a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/RtFiniteStateMachineLongRunningUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/RtFiniteStateMachineLongRunningUnitTest.java @@ -1,14 +1,16 @@ package com.baeldung.algorithms; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + import com.baeldung.algorithms.automata.*; -import org.junit.Test; -import static org.junit.Assert.assertTrue; - -public final class RtFiniteStateMachineLongRunningUnitTest { +class RtFiniteStateMachineLongRunningUnitTest { @Test - public void acceptsSimplePair() { + void acceptsSimplePair() { String json = "{\"key\":\"value\"}"; FiniteStateMachine machine = this.buildJsonStateMachine(); for (int i = 0; i < json.length(); i++) { @@ -18,7 +20,7 @@ public final class RtFiniteStateMachineLongRunningUnitTest { } @Test - public void acceptsMorePairs() { + void acceptsMorePairs() { String json = "{\"key1\":\"value1\",\"key2\":\"value2\"}"; FiniteStateMachine machine = this.buildJsonStateMachine(); for (int i = 0; i < json.length(); i++) { @@ -27,13 +29,15 @@ public final class RtFiniteStateMachineLongRunningUnitTest { assertTrue(machine.canStop()); } - @Test(expected = IllegalArgumentException.class) - public void missingColon() { + @Test + void missingColon() { String json = "{\"key\"\"value\"}"; - FiniteStateMachine machine = this.buildJsonStateMachine(); - for (int i = 0; i < json.length(); i++) { - machine = machine.switchState(String.valueOf(json.charAt(i))); - } + assertThrows(IllegalArgumentException.class, () -> { + FiniteStateMachine machine = this.buildJsonStateMachine(); + for (int i = 0; i < json.length(); i++) { + machine = machine.switchState(String.valueOf(json.charAt(i))); + } + }); } /** diff --git a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/kthlargest/FindKthLargestUnitTest.java b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/kthlargest/FindKthLargestUnitTest.java index 6fbb7c163a..e877d9945a 100644 --- a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/kthlargest/FindKthLargestUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/kthlargest/FindKthLargestUnitTest.java @@ -1,54 +1,54 @@ package com.baeldung.algorithms.kthlargest; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class FindKthLargestUnitTest { +class FindKthLargestUnitTest { private FindKthLargest findKthLargest; private Integer[] arr = { 3, 7, 1, 2, 8, 10, 4, 5, 6, 9 }; - @Before + @BeforeEach public void setup() { findKthLargest = new FindKthLargest(); } @Test - public void givenIntArray_whenFindKthLargestBySorting_thenGetResult() { + void givenIntArray_whenFindKthLargestBySorting_thenGetResult() { int k = 3; assertThat(findKthLargest.findKthLargestBySorting(arr, k)).isEqualTo(8); } @Test - public void givenIntArray_whenFindKthLargestBySortingDesc_thenGetResult() { + void givenIntArray_whenFindKthLargestBySortingDesc_thenGetResult() { int k = 3; assertThat(findKthLargest.findKthLargestBySortingDesc(arr, k)).isEqualTo(8); } @Test - public void givenIntArray_whenFindKthLargestByQuickSelect_thenGetResult() { + void givenIntArray_whenFindKthLargestByQuickSelect_thenGetResult() { int k = 3; int kthLargest = arr.length - k; assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8); } @Test - public void givenIntArray_whenFindKthElementByQuickSelectIterative_thenGetResult() { + void givenIntArray_whenFindKthElementByQuickSelectIterative_thenGetResult() { int k = 3; int kthLargest = arr.length - k; assertThat(findKthLargest.findKthElementByQuickSelectWithIterativePartition(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8); } @Test - public void givenIntArray_whenFindKthSmallestByQuickSelect_thenGetResult() { + void givenIntArray_whenFindKthSmallestByQuickSelect_thenGetResult() { int k = 3; assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, k - 1)).isEqualTo(3); } @Test - public void givenIntArray_whenFindKthLargestByRandomizedQuickSelect_thenGetResult() { + void givenIntArray_whenFindKthLargestByRandomizedQuickSelect_thenGetResult() { int k = 3; int kthLargest = arr.length - k; assertThat(findKthLargest.findKthElementByRandomizedQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8); diff --git a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/minimax/MinimaxUnitTest.java b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/minimax/MinimaxUnitTest.java index 59f0fcf053..e36e3651de 100644 --- a/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/minimax/MinimaxUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/minimax/MinimaxUnitTest.java @@ -1,23 +1,24 @@ package com.baeldung.algorithms.minimax; -import org.junit.Before; -import org.junit.Test; +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 static org.junit.Assert.*; -import com.baeldung.algorithms.minimax.MiniMax; -import com.baeldung.algorithms.minimax.Tree; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class MinimaxUnitTest { +class MinimaxUnitTest { private Tree gameTree; private MiniMax miniMax; - @Before + @BeforeEach public void initMiniMaxUtility() { miniMax = new MiniMax(); } @Test - public void givenMiniMax_whenConstructTree_thenNotNullTree() { + void givenMiniMax_whenConstructTree_thenNotNullTree() { assertNull(gameTree); miniMax.constructTree(6); gameTree = miniMax.getTree(); @@ -25,7 +26,7 @@ public class MinimaxUnitTest { } @Test - public void givenMiniMax_whenCheckWin_thenComputeOptimal() { + void givenMiniMax_whenCheckWin_thenComputeOptimal() { miniMax.constructTree(6); boolean result = miniMax.checkWin(); assertTrue(result); diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/DijkstraAlgorithmLongRunningUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/DijkstraAlgorithmLongRunningUnitTest.java index bbc4d4f398..7e80d335be 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/DijkstraAlgorithmLongRunningUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/DijkstraAlgorithmLongRunningUnitTest.java @@ -1,6 +1,6 @@ package com.baeldung.algorithms; -import org.junit.Test; + import com.baeldung.algorithms.ga.dijkstra.Dijkstra; import com.baeldung.algorithms.ga.dijkstra.Graph; @@ -11,7 +11,9 @@ import java.util.List; import static org.junit.Assert.assertTrue; -public class DijkstraAlgorithmLongRunningUnitTest { +import org.junit.jupiter.api.Test; + +class DijkstraAlgorithmLongRunningUnitTest { @Test public void whenSPPSolved_thenCorrect() { diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java index aba7f149da..ba492b33cf 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/astar/underground/RouteFinderIntegrationTest.java @@ -1,5 +1,6 @@ package com.baeldung.algorithms.astar.underground; + import static org.assertj.core.api.Assertions.assertThat; import java.util.HashMap; @@ -10,22 +11,22 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import com.baeldung.algorithms.astar.Graph; import com.baeldung.algorithms.astar.RouteFinder; import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Test; - @Slf4j -public class RouteFinderIntegrationTest { +class RouteFinderIntegrationTest { private Graph underground; private RouteFinder routeFinder; - @Before + @BeforeEach public void setUp() throws Exception { Set stations = new HashSet<>(); Map> connections = new HashMap<>(); @@ -641,7 +642,7 @@ public class RouteFinderIntegrationTest { } @Test - public void findRoute() { + void findRoute() { List route = routeFinder.findRoute(underground.getNode("74"), underground.getNode("7")); assertThat(route).size().isPositive(); diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceDataProvider.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceDataProvider.java deleted file mode 100644 index d11da61191..0000000000 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceDataProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.baeldung.algorithms.editdistance; - -import org.junit.runners.Parameterized.Parameters; - -import java.util.Arrays; -import java.util.Collection; - -public class EditDistanceDataProvider { - - @Parameters - public static Collection getLists() { - return Arrays.asList(new Object[][] { - { "", "", 0 }, - { "ago", "", 3 }, - { "", "do", 2 }, - { "abc", "adc", 1 }, - { "peek", "pesek", 1 }, - { "sunday", "saturday", 3 } - }); - } -} diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceUnitTest.java index 3dd63e86ab..044c8fc268 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/editdistance/EditDistanceUnitTest.java @@ -1,32 +1,39 @@ package com.baeldung.algorithms.editdistance; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -@RunWith(Parameterized.class) -public class EditDistanceUnitTest extends EditDistanceDataProvider { +import java.util.stream.Stream; - private String x; - private String y; - private int result; - public EditDistanceUnitTest(String a, String b, int res) { - super(); - x = a; - y = b; - result = res; - } +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; - @Test - public void testEditDistance_RecursiveImplementation() { +import org.junit.jupiter.params.provider.MethodSource; + +class EditDistanceUnitTest { + + @ParameterizedTest + @MethodSource("provideArguments") + void testEditDistance_RecursiveImplementation(String x, String y, int result) { assertEquals(result, EditDistanceRecursive.calculate(x, y)); } - @Test - public void testEditDistance_givenDynamicProgrammingImplementation() { + @ParameterizedTest + @MethodSource("provideArguments") + void testEditDistance_givenDynamicProgrammingImplementation(String x, String y, int result) { assertEquals(result, EditDistanceDynamicProgramming.calculate(x, y)); } + + + static Stream provideArguments() { + return Stream.of(new Object[][] { + { "", "", 0 }, + { "ago", "", 3 }, + { "", "do", 2 }, + { "abc", "adc", 1 }, + { "peek", "pesek", 1 }, + { "sunday", "saturday", 3 } + }).map(Arguments::of); + } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceUnitTest.java index 33889fbec6..a2bcb07ce3 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceUnitTest.java @@ -1,23 +1,16 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import static org.junit.jupiter.api.Assertions.assertEquals; -@RunWith(value = Parameterized.class) -public class CycleDetectionBruteForceUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - public CycleDetectionBruteForceUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +class CycleDetectionBruteForceUnitTest extends CycleDetectionTestBase { - @Test - public void givenList_detectLoop() { - Assert.assertEquals(cycleExists, CycleDetectionBruteForce.detectCycle(head).cycleExists); + + @ParameterizedTest + @MethodSource("getLists") + void givenList_detectLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleDetectionBruteForce.detectCycle(head).cycleExists); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsUnitTest.java index 1496840771..6acd8a2bef 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsUnitTest.java @@ -1,23 +1,16 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(value = Parameterized.class) -public class CycleDetectionByFastAndSlowIteratorsUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import static org.junit.jupiter.api.Assertions.assertEquals; - public CycleDetectionByFastAndSlowIteratorsUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - @Test - public void givenList_detectLoop() { - Assert.assertEquals(cycleExists, CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); +class CycleDetectionByFastAndSlowIteratorsUnitTest extends CycleDetectionTestBase { + + @ParameterizedTest + @MethodSource("getLists") + void givenList_detectLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingUnitTest.java index 136f55f834..905423e337 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingUnitTest.java @@ -1,23 +1,17 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(value = Parameterized.class) -public class CycleDetectionByHashingUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import static org.junit.jupiter.api.Assertions.assertEquals; - public CycleDetectionByHashingUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - @Test - public void givenList_detectLoop() { - Assert.assertEquals(cycleExists, CycleDetectionByHashing.detectCycle(head).cycleExists); + +class CycleDetectionByHashingUnitTest extends CycleDetectionTestBase { + + @ParameterizedTest + @MethodSource("getLists") + void givenList_detectLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleDetectionByHashing.detectCycle(head).cycleExists); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java index 1c6f56b20d..b4d0bf5459 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java @@ -7,7 +7,7 @@ import org.junit.runners.Parameterized.Parameters; public class CycleDetectionTestBase { - @Parameters + public static Collection getLists() { return Arrays.asList(new Object[][] { { createList(), false }, diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForceUnitTest.java index 36f08d2b76..6dc6ff9f58 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForceUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForceUnitTest.java @@ -1,24 +1,19 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(value = Parameterized.class) -public class CycleRemovalBruteForceUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; - public CycleRemovalBruteForceUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - @Test - public void givenList_ifLoopExists_thenDetectAndRemoveLoop() { - Assert.assertEquals(cycleExists, CycleRemovalBruteForce.detectAndRemoveCycle(head)); - Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); + +class CycleRemovalBruteForceUnitTest extends CycleDetectionTestBase { + + @ParameterizedTest + @MethodSource("getLists") + void givenList_ifLoopExists_thenDetectAndRemoveLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleRemovalBruteForce.detectAndRemoveCycle(head)); + assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodesUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodesUnitTest.java index cc7589c53d..c82f175488 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodesUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodesUnitTest.java @@ -1,24 +1,17 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; -@RunWith(value = Parameterized.class) -public class CycleRemovalByCountingLoopNodesUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - public CycleRemovalByCountingLoopNodesUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +class CycleRemovalByCountingLoopNodesUnitTest extends CycleDetectionTestBase { - @Test - public void givenList_ifLoopExists_thenDetectAndRemoveLoop() { - Assert.assertEquals(cycleExists, CycleRemovalByCountingLoopNodes.detectAndRemoveCycle(head)); - Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); + @ParameterizedTest + @MethodSource("getLists") + void givenList_ifLoopExists_thenDetectAndRemoveLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleRemovalByCountingLoopNodes.detectAndRemoveCycle(head)); + assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodesUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodesUnitTest.java index 350e63dcc3..3ffb9ac639 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodesUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodesUnitTest.java @@ -1,24 +1,19 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(value = Parameterized.class) -public class CycleRemovalWithoutCountingLoopNodesUnitTest extends CycleDetectionTestBase { - boolean cycleExists; - Node head; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; - public CycleRemovalWithoutCountingLoopNodesUnitTest(Node head, boolean cycleExists) { - super(); - this.cycleExists = cycleExists; - this.head = head; - } +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; - @Test - public void givenList_ifLoopExists_thenDetectAndRemoveLoop() { - Assert.assertEquals(cycleExists, CycleRemovalWithoutCountingLoopNodes.detectAndRemoveCycle(head)); - Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); + +class CycleRemovalWithoutCountingLoopNodesUnitTest extends CycleDetectionTestBase { + + @ParameterizedTest + @MethodSource("getLists") + void givenList_ifLoopExists_thenDetectAndRemoveLoop(Node head, boolean cycleExists) { + assertEquals(cycleExists, CycleRemovalWithoutCountingLoopNodes.detectAndRemoveCycle(head)); + assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists); } } \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/moneywords/NumberWordConverterUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/moneywords/NumberWordConverterUnitTest.java index 26643e9c1e..1b94643e8a 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/moneywords/NumberWordConverterUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/moneywords/NumberWordConverterUnitTest.java @@ -1,84 +1,84 @@ package com.baeldung.algorithms.moneywords; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.numberwordconverter.NumberWordConverter; -public class NumberWordConverterUnitTest { +class NumberWordConverterUnitTest { @Test - public void whenMoneyNegative_thenReturnInvalidInput() { + void whenMoneyNegative_thenReturnInvalidInput() { assertEquals(NumberWordConverter.INVALID_INPUT_GIVEN, NumberWordConverter.getMoneyIntoWords(-13)); } @Test - public void whenZeroDollarsGiven_thenReturnEmptyString() { + void whenZeroDollarsGiven_thenReturnEmptyString() { assertEquals("", NumberWordConverter.getMoneyIntoWords(0)); } @Test - public void whenOnlyDollarsGiven_thenReturnWords() { + void whenOnlyDollarsGiven_thenReturnWords() { assertEquals("one dollar", NumberWordConverter.getMoneyIntoWords(1)); } @Test - public void whenOnlyCentsGiven_thenReturnWords() { + void whenOnlyCentsGiven_thenReturnWords() { assertEquals("sixty cents", NumberWordConverter.getMoneyIntoWords(0.6)); } @Test - public void whenAlmostAMillioDollarsGiven_thenReturnWords() { + void whenAlmostAMillioDollarsGiven_thenReturnWords() { String expectedResult = "nine hundred ninety nine thousand nine hundred ninety nine dollars"; assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(999_999)); } @Test - public void whenThirtyMillionDollarsGiven_thenReturnWords() { + void whenThirtyMillionDollarsGiven_thenReturnWords() { String expectedResult = "thirty three million three hundred forty eight thousand nine hundred seventy eight dollars"; assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(33_348_978)); } @Test - public void whenTwoBillionDollarsGiven_thenReturnWords() { + void whenTwoBillionDollarsGiven_thenReturnWords() { String expectedResult = "two billion one hundred thirty three million two hundred forty seven thousand eight hundred ten dollars"; assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(2_133_247_810)); } @Test - public void whenGivenDollarsAndCents_thenReturnWords() { + void whenGivenDollarsAndCents_thenReturnWords() { String expectedResult = "nine hundred twenty four dollars and sixty cents"; assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(924.6)); } @Test - public void whenOneDollarAndNoCents_thenReturnDollarSingular() { + void whenOneDollarAndNoCents_thenReturnDollarSingular() { assertEquals("one dollar", NumberWordConverter.getMoneyIntoWords(1)); } @Test - public void whenNoDollarsAndOneCent_thenReturnCentSingular() { + void whenNoDollarsAndOneCent_thenReturnCentSingular() { assertEquals("one cent", NumberWordConverter.getMoneyIntoWords(0.01)); } @Test - public void whenNoDollarsAndTwoCents_thenReturnCentsPlural() { + void whenNoDollarsAndTwoCents_thenReturnCentsPlural() { assertEquals("two cents", NumberWordConverter.getMoneyIntoWords(0.02)); } @Test - public void whenNoDollarsAndNinetyNineCents_thenReturnWords() { + void whenNoDollarsAndNinetyNineCents_thenReturnWords() { assertEquals("ninety nine cents", NumberWordConverter.getMoneyIntoWords(0.99)); } @Test - public void whenNoDollarsAndNineFiveNineCents_thenCorrectRounding() { + void whenNoDollarsAndNineFiveNineCents_thenCorrectRounding() { assertEquals("ninety six cents", NumberWordConverter.getMoneyIntoWords(0.959)); } @Test - public void whenGivenDollarsAndCents_thenReturnWordsVersionTwo() { + void whenGivenDollarsAndCents_thenReturnWordsVersionTwo() { assertEquals("three hundred ten £ 00/100", NumberWordConverter.getMoneyIntoWords("310")); } } diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/CompleteGraphUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/CompleteGraphUnitTest.java index 0b0d6ae822..c95f1bc6e8 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/CompleteGraphUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/CompleteGraphUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.jgrapht; -import static org.junit.Assert.assertEquals; + + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; @@ -9,15 +11,15 @@ import org.jgrapht.alg.HamiltonianCycle; import org.jgrapht.generate.CompleteGraphGenerator; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.SimpleWeightedGraph; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class CompleteGraphUnitTest { +class CompleteGraphUnitTest { static SimpleWeightedGraph completeGraph; static int size = 10; - @Before + @BeforeEach public void createCompleteGraph() { completeGraph = new SimpleWeightedGraph<>(DefaultEdge.class); CompleteGraphGenerator completeGenerator = new CompleteGraphGenerator(size); diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/DirectedGraphUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/DirectedGraphUnitTest.java index 3aebaf49a2..ad3433cc21 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/DirectedGraphUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/DirectedGraphUnitTest.java @@ -1,7 +1,9 @@ package com.baeldung.jgrapht; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; + + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; @@ -21,13 +23,13 @@ import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DirectedSubgraph; import org.jgrapht.traverse.BreadthFirstIterator; import org.jgrapht.traverse.DepthFirstIterator; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class DirectedGraphUnitTest { +class DirectedGraphUnitTest { DirectedGraph directedGraph; - @Before + @BeforeEach public void createDirectedGraph() { directedGraph = new DefaultDirectedGraph(DefaultEdge.class); IntStream.range(1, 10).forEach(i -> { @@ -46,7 +48,7 @@ public class DirectedGraphUnitTest { } @Test - public void givenDirectedGraph_whenGetStronglyConnectedSubgraphs_thenPathExistsBetweenStronglyconnectedVertices() { + void givenDirectedGraph_whenGetStronglyConnectedSubgraphs_thenPathExistsBetweenStronglyconnectedVertices() { StrongConnectivityAlgorithm scAlg = new KosarajuStrongConnectivityInspector<>(directedGraph); List> stronglyConnectedSubgraphs = scAlg.stronglyConnectedSubgraphs(); List stronglyConnectedVertices = new ArrayList<>(stronglyConnectedSubgraphs.get(3).vertexSet()); @@ -60,7 +62,7 @@ public class DirectedGraphUnitTest { } @Test - public void givenDirectedGraphWithCycle_whenCheckCycles_thenDetectCycles() { + void givenDirectedGraphWithCycle_whenCheckCycles_thenDetectCycles() { CycleDetector cycleDetector = new CycleDetector(directedGraph); assertTrue(cycleDetector.detectCycles()); Set cycleVertices = cycleDetector.findCycles(); @@ -68,26 +70,26 @@ public class DirectedGraphUnitTest { } @Test - public void givenDirectedGraph_whenCreateInstanceDepthFirstIterator_thenGetIterator() { + void givenDirectedGraph_whenCreateInstanceDepthFirstIterator_thenGetIterator() { DepthFirstIterator depthFirstIterator = new DepthFirstIterator<>(directedGraph); assertNotNull(depthFirstIterator); } @Test - public void givenDirectedGraph_whenCreateInstanceBreadthFirstIterator_thenGetIterator() { + void givenDirectedGraph_whenCreateInstanceBreadthFirstIterator_thenGetIterator() { BreadthFirstIterator breadthFirstIterator = new BreadthFirstIterator<>(directedGraph); assertNotNull(breadthFirstIterator); } @Test - public void givenDirectedGraph_whenGetDijkstraShortestPath_thenGetNotNullPath() { + void givenDirectedGraph_whenGetDijkstraShortestPath_thenGetNotNullPath() { DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(directedGraph); List shortestPath = dijkstraShortestPath.getPath("v1", "v4").getVertexList(); assertNotNull(shortestPath); } @Test - public void givenDirectedGraph_whenGetBellmanFordShortestPath_thenGetNotNullPath() { + void givenDirectedGraph_whenGetBellmanFordShortestPath_thenGetNotNullPath() { BellmanFordShortestPath bellmanFordShortestPath = new BellmanFordShortestPath(directedGraph); List shortestPath = bellmanFordShortestPath.getPath("v1", "v4").getVertexList(); assertNotNull(shortestPath); diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/EulerianCircuitUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/EulerianCircuitUnitTest.java index 8cf1b70898..e47f53da75 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/EulerianCircuitUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/EulerianCircuitUnitTest.java @@ -1,7 +1,7 @@ package com.baeldung.jgrapht; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.stream.IntStream; @@ -9,13 +9,13 @@ import org.jgrapht.GraphPath; import org.jgrapht.alg.cycle.HierholzerEulerianCycle; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.SimpleWeightedGraph; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class EulerianCircuitUnitTest { +class EulerianCircuitUnitTest { SimpleWeightedGraph simpleGraph; - @Before + @BeforeEach public void createGraphWithEulerianCircuit() { simpleGraph = new SimpleWeightedGraph<>(DefaultEdge.class); IntStream.range(1, 6).forEach(i -> { diff --git a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/GraphImageGenerationUnitTest.java b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/GraphImageGenerationUnitTest.java index a0d7523f48..7fb1b28cca 100644 --- a/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/GraphImageGenerationUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-2/src/test/java/com/baeldung/jgrapht/GraphImageGenerationUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.jgrapht; -import static org.junit.Assert.assertTrue; + + +import static org.junit.jupiter.api.Assertions.assertTrue; import java.awt.Color; import java.awt.image.BufferedImage; @@ -12,18 +14,18 @@ import javax.imageio.ImageIO; import org.jgrapht.ext.JGraphXAdapter; import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.graph.DefaultEdge; -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; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxIGraphLayout; import com.mxgraph.util.mxCellRenderer; -public class GraphImageGenerationUnitTest { +class GraphImageGenerationUnitTest { static DefaultDirectedGraph g; - @Before + @BeforeEach public void createGraph() throws IOException { File imgFile = new File("src/test/resources/graph1.png"); imgFile.createNewFile(); @@ -39,14 +41,14 @@ public class GraphImageGenerationUnitTest { g.addEdge(x3, x1); } - @After + @AfterEach public void cleanup() { File imgFile = new File("src/test/resources/graph1.png"); imgFile.deleteOnExit(); } @Test - public void givenAdaptedGraph_whenWriteBufferedImage_ThenFileShouldExist() throws IOException { + void givenAdaptedGraph_whenWriteBufferedImage_ThenFileShouldExist() throws IOException { JGraphXAdapter graphAdapter = new JGraphXAdapter(g); mxIGraphLayout layout = new mxCircleLayout(graphAdapter); layout.execute(graphAdapter.getDefaultParent()); diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checktargetsum/CheckTargetSum.java b/algorithms-modules/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checktargetsum/CheckTargetSum.java new file mode 100644 index 0000000000..fdbde62301 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/checktargetsum/CheckTargetSum.java @@ -0,0 +1,58 @@ +package com.baeldung.algorithms.checktargetsum; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class CheckTargetSum { + public boolean isTargetSumExistNaive(int[] nums, int target) { + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + return true; + } + } + } + + return false; + } + + public boolean isTargetSumExistSorted(int[] nums, int target) { + Arrays.sort(nums); + + int start = 0; + int end = nums.length - 1; + + while (start < end) { + int sum = nums[start] + nums[end]; + + if (sum == target) { + return true; + } + + if (sum < target) { + start++; + } else { + end--; + } + } + + return false; + } + + public boolean isTargetSumExistHashSet(int[] nums, int target) { + Set hashSet = new HashSet<>(); + + for (int num : nums) { + int diff = target - num; + + if (hashSet.contains(diff)) { + return true; + } + + hashSet.add(num); + } + + return false; + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java index 1e9188f726..f3d9f7161a 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java @@ -1,14 +1,14 @@ package com.baeldung.algorithms.analysis; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class AnalysisRunnerLiveTest { +class AnalysisRunnerLiveTest { int n = 10; int total = 0; @Test - public void whenConstantComplexity_thenConstantRuntime() { + void whenConstantComplexity_thenConstantRuntime() { System.out.println("**** n = " + n + " ****"); System.out.println(); @@ -22,7 +22,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenLogarithmicComplexity_thenLogarithmicRuntime() { + void whenLogarithmicComplexity_thenLogarithmicRuntime() { // Logarithmic Time System.out.println("**** Logarithmic Time ****"); for (int i = 1; i < n; i = i * 2) { @@ -34,7 +34,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenLinearComplexity_thenLinearRuntime() { + void whenLinearComplexity_thenLinearRuntime() { // Linear Time System.out.println("**** Linear Time ****"); for (int i = 0; i < n; i++) { @@ -47,7 +47,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenNLogNComplexity_thenNLogNRuntime() { + void whenNLogNComplexity_thenNLogNRuntime() { // N Log N Time System.out.println("**** nlogn Time ****"); total = 0; @@ -64,7 +64,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenQuadraticComplexity_thenQuadraticRuntime() { + void whenQuadraticComplexity_thenQuadraticRuntime() { // Quadratic Time System.out.println("**** Quadratic Time ****"); total = 0; @@ -81,7 +81,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenCubicComplexity_thenCubicRuntime() { + void whenCubicComplexity_thenCubicRuntime() { // Cubic Time System.out.println("**** Cubic Time ****"); total = 0; @@ -100,7 +100,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenExponentialComplexity_thenExponentialRuntime() { + void whenExponentialComplexity_thenExponentialRuntime() { // Exponential Time System.out.println("**** Exponential Time ****"); total = 0; @@ -115,7 +115,7 @@ public class AnalysisRunnerLiveTest { } @Test - public void whenFactorialComplexity_thenFactorialRuntime() { + void whenFactorialComplexity_thenFactorialRuntime() { // Factorial Time System.out.println("**** Factorial Time ****"); total = 0; diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java index 44c4388e6c..e865aa010a 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checksortedlist/SortedListCheckerUnitTest.java @@ -11,10 +11,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class SortedListCheckerUnitTest { +class SortedListCheckerUnitTest { private List sortedListOfString; private List unsortedListOfString; @@ -23,7 +23,7 @@ public class SortedListCheckerUnitTest { private List employeesSortedByName; private List employeesNotSortedByName; - @Before + @BeforeEach public void setUp() { sortedListOfString = asList("Canada", "HK", "LA", "NJ", "NY"); unsortedListOfString = asList("LA", "HK", "NJ", "NY", "Canada"); @@ -34,72 +34,72 @@ public class SortedListCheckerUnitTest { } @Test - public void givenSortedList_whenUsingIterativeApproach_thenReturnTrue() { + void givenSortedList_whenUsingIterativeApproach_thenReturnTrue() { assertThat(checkIfSortedUsingIterativeApproach(sortedListOfString)).isTrue(); } @Test - public void givenSingleElementList_whenUsingIterativeApproach_thenReturnTrue() { + void givenSingleElementList_whenUsingIterativeApproach_thenReturnTrue() { assertThat(checkIfSortedUsingIterativeApproach(singletonList)).isTrue(); } @Test - public void givenUnsortedList_whenUsingIterativeApproach_thenReturnFalse() { + void givenUnsortedList_whenUsingIterativeApproach_thenReturnFalse() { assertThat(checkIfSortedUsingIterativeApproach(unsortedListOfString)).isFalse(); } @Test - public void givenSortedListOfEmployees_whenUsingIterativeApproach_thenReturnTrue() { + void givenSortedListOfEmployees_whenUsingIterativeApproach_thenReturnTrue() { assertThat(checkIfSortedUsingIterativeApproach(employeesSortedByName, Comparator.comparing(Employee::getName))).isTrue(); } @Test - public void givenUnsortedListOfEmployees_whenUsingIterativeApproach_thenReturnFalse() { + void givenUnsortedListOfEmployees_whenUsingIterativeApproach_thenReturnFalse() { assertThat(checkIfSortedUsingIterativeApproach(employeesNotSortedByName, Comparator.comparing(Employee::getName))).isFalse(); } @Test - public void givenSortedList_whenUsingRecursion_thenReturnTrue() { + void givenSortedList_whenUsingRecursion_thenReturnTrue() { assertThat(checkIfSortedUsingRecursion(sortedListOfString)).isTrue(); } @Test - public void givenSingleElementList_whenUsingRecursion_thenReturnTrue() { + void givenSingleElementList_whenUsingRecursion_thenReturnTrue() { assertThat(checkIfSortedUsingRecursion(singletonList)).isTrue(); } @Test - public void givenUnsortedList_whenUsingRecursion_thenReturnFalse() { + void givenUnsortedList_whenUsingRecursion_thenReturnFalse() { assertThat(checkIfSortedUsingRecursion(unsortedListOfString)).isFalse(); } @Test - public void givenSortedList_whenUsingGuavaOrdering_thenReturnTrue() { + void givenSortedList_whenUsingGuavaOrdering_thenReturnTrue() { assertThat(checkIfSortedUsingOrderingClass(sortedListOfString)).isTrue(); } @Test - public void givenUnsortedList_whenUsingGuavaOrdering_thenReturnFalse() { + void givenUnsortedList_whenUsingGuavaOrdering_thenReturnFalse() { assertThat(checkIfSortedUsingOrderingClass(unsortedListOfString)).isFalse(); } @Test - public void givenSortedListOfEmployees_whenUsingGuavaOrdering_thenReturnTrue() { + void givenSortedListOfEmployees_whenUsingGuavaOrdering_thenReturnTrue() { assertThat(checkIfSortedUsingOrderingClass(employeesSortedByName, Comparator.comparing(Employee::getName))).isTrue(); } @Test - public void givenUnsortedListOfEmployees_whenUsingGuavaOrdering_thenReturnFalse() { + void givenUnsortedListOfEmployees_whenUsingGuavaOrdering_thenReturnFalse() { assertThat(checkIfSortedUsingOrderingClass(employeesNotSortedByName, Comparator.comparing(Employee::getName))).isFalse(); } @Test - public void givenSortedList_whenUsingGuavaComparators_thenReturnTrue() { + void givenSortedList_whenUsingGuavaComparators_thenReturnTrue() { assertThat(checkIfSortedUsingComparators(sortedListOfString)).isTrue(); } @Test - public void givenUnsortedList_whenUsingGuavaComparators_thenReturnFalse() { + void givenUnsortedList_whenUsingGuavaComparators_thenReturnFalse() { assertThat(checkIfSortedUsingComparators(unsortedListOfString)).isFalse(); } diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checktargetsum/CheckTargetSumUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checktargetsum/CheckTargetSumUnitTest.java new file mode 100644 index 0000000000..ff20ce112e --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/checktargetsum/CheckTargetSumUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.algorithms.checktargetsum; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CheckTargetSumUnitTest { + private CheckTargetSum checkTargetSum = new CheckTargetSum(); + + private int[] nums = new int[] { 10, 5, 15, 7, 14, 1, 9 }; + + private int existingTarget = 6; + + private int nonExistingTarget = 27; + + @Test + public void givenArrayOfIntegers_whenTargetSumNaive_thenPairExists() { + assertTrue(checkTargetSum.isTargetSumExistNaive(nums, existingTarget)); + } + + @Test + public void givenArrayOfIntegers_whenTargetSumNaive_thenPairDoesNotExists() { + assertFalse(checkTargetSum.isTargetSumExistNaive(nums, nonExistingTarget)); + } + + @Test + public void givenArrayOfIntegers_whenTargetSumSorted_thenPairExists() { + assertTrue(checkTargetSum.isTargetSumExistNaive(nums, existingTarget)); + } + + @Test + public void givenArrayOfIntegers_whenTargetSumSorted_thenPairDoesNotExists() { + assertFalse(checkTargetSum.isTargetSumExistNaive(nums, nonExistingTarget)); + } + + @Test + public void givenArrayOfIntegers_whenTargetSumHashSet_thenPairExists() { + assertTrue(checkTargetSum.isTargetSumExistNaive(nums, existingTarget)); + } + + @Test + public void givenArrayOfIntegers_whenTargetSumHashSet_thenPairDoesNotExists() { + assertFalse(checkTargetSum.isTargetSumExistNaive(nums, nonExistingTarget)); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java index 61ed6b3aec..5b48c884e4 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java @@ -1,37 +1,37 @@ package com.baeldung.algorithms.enumstatemachine; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class LeaveRequestStateUnitTest { +class LeaveRequestStateUnitTest { @Test - public void givenLeaveRequest_whenStateEscalated_thenResponsibleIsTeamLeader() { + void givenLeaveRequest_whenStateEscalated_thenResponsibleIsTeamLeader() { LeaveRequestState state = LeaveRequestState.Escalated; - assertEquals(state.responsiblePerson(), "Team Leader"); + assertEquals( "Team Leader", state.responsiblePerson()); } @Test - public void givenLeaveRequest_whenStateApproved_thenResponsibleIsDepartmentManager() { + void givenLeaveRequest_whenStateApproved_thenResponsibleIsDepartmentManager() { LeaveRequestState state = LeaveRequestState.Approved; - assertEquals(state.responsiblePerson(), "Department Manager"); + assertEquals( "Department Manager" , state.responsiblePerson()); } @Test - public void givenLeaveRequest_whenNextStateIsCalled_thenStateIsChanged() { + void givenLeaveRequest_whenNextStateIsCalled_thenStateIsChanged() { LeaveRequestState state = LeaveRequestState.Submitted; state = state.nextState(); - assertEquals(state, LeaveRequestState.Escalated); + assertEquals(LeaveRequestState.Escalated, state); state = state.nextState(); - assertEquals(state, LeaveRequestState.Approved); + assertEquals(LeaveRequestState.Approved, state); state = state.nextState(); - assertEquals(state, LeaveRequestState.Approved); + assertEquals(LeaveRequestState.Approved, state); } } diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/graphcycledetection/GraphCycleDetectionUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/graphcycledetection/GraphCycleDetectionUnitTest.java index 8d464d7b97..c54483dbbb 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/graphcycledetection/GraphCycleDetectionUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/graphcycledetection/GraphCycleDetectionUnitTest.java @@ -1,14 +1,14 @@ package com.baeldung.algorithms.graphcycledetection; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.graphcycledetection.domain.Graph; import com.baeldung.algorithms.graphcycledetection.domain.Vertex; -public class GraphCycleDetectionUnitTest { +class GraphCycleDetectionUnitTest { @Test public void givenGraph_whenCycleExists_thenReturnTrue() { @@ -33,7 +33,7 @@ public class GraphCycleDetectionUnitTest { } @Test - public void givenGraph_whenNoCycleExists_thenReturnFalse() { + void givenGraph_whenNoCycleExists_thenReturnFalse() { Vertex vertexA = new Vertex("A"); Vertex vertexB = new Vertex("B"); diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java index 97e99290c9..ad98d63388 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java @@ -1,14 +1,11 @@ package com.baeldung.algorithms.printtriangles; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.junit.Test; -import org.junit.runner.RunWith; +import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(JUnitParamsRunner.class) -public class PrintTriangleExamplesUnitTest { +class PrintTriangleExamplesUnitTest { private static Object[][] rightTriangles() { String expected0 = ""; @@ -38,9 +35,9 @@ public class PrintTriangleExamplesUnitTest { }; } - @Test - @Parameters(method = "rightTriangles") - public void whenPrintARightTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { + @ParameterizedTest + @MethodSource("rightTriangles") + void whenPrintARightTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { String actual = PrintTriangleExamples.printARightTriangle(nrOfRows); assertEquals(expected, actual); @@ -74,24 +71,24 @@ public class PrintTriangleExamplesUnitTest { }; } - @Test - @Parameters(method = "isoscelesTriangles") - public void whenPrintAnIsoscelesTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { + @ParameterizedTest + @MethodSource("isoscelesTriangles") + void whenPrintAnIsoscelesTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { String actual = PrintTriangleExamples.printAnIsoscelesTriangle(nrOfRows); assertEquals(expected, actual); } - @Test - @Parameters(method = "isoscelesTriangles") + @ParameterizedTest + @MethodSource("isoscelesTriangles") public void whenPrintAnIsoscelesTriangleUsingStringUtilsIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { String actual = PrintTriangleExamples.printAnIsoscelesTriangleUsingStringUtils(nrOfRows); assertEquals(expected, actual); } - - @Test - @Parameters(method = "isoscelesTriangles") + + @ParameterizedTest + @MethodSource("isoscelesTriangles") public void whenPrintAnIsoscelesTriangleUsingSubstringIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) { String actual = PrintTriangleExamples.printAnIsoscelesTriangleUsingSubstring(nrOfRows); diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java index 9043cfe9cc..4571a60509 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java @@ -1,13 +1,14 @@ package com.baeldung.algorithms.romannumerals; + import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class RomanArabicConverterUnitTest { +class RomanArabicConverterUnitTest { @Test - public void given2018Roman_WhenConvertingToArabic_ThenReturn2018() { + void given2018Roman_WhenConvertingToArabic_ThenReturn2018() { String roman2018 = "MMXVIII"; @@ -17,7 +18,7 @@ public class RomanArabicConverterUnitTest { } @Test - public void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() { + void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() { int arabic1999 = 1999; diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java index 422a53fa3e..5aaf1711b9 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java @@ -2,14 +2,14 @@ package com.baeldung.algorithms.twopointertechnique; import static org.assertj.core.api.Assertions.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class LinkedListFindMiddleUnitTest { +class LinkedListFindMiddleUnitTest { LinkedListFindMiddle linkedListFindMiddle = new LinkedListFindMiddle(); @Test - public void givenLinkedListOfMyNodes_whenLinkedListFindMiddle_thenCorrect() { + void givenLinkedListOfMyNodes_whenLinkedListFindMiddle_thenCorrect() { MyNode head = createNodesList(8); diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java index da227ae751..defc956a68 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java @@ -1,10 +1,10 @@ package com.baeldung.algorithms.twopointertechnique; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class RotateArrayUnitTest { +class RotateArrayUnitTest { private RotateArray rotateArray = new RotateArray(); @@ -13,7 +13,7 @@ public class RotateArrayUnitTest { private int step; @Test - public void givenAnArrayOfIntegers_whenRotateKsteps_thenCorrect() { + void givenAnArrayOfIntegers_whenRotateKsteps_thenCorrect() { inputArray = new int[] { 1, 2, 3, 4, 5, 6, 7 }; step = 4; diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java index aa76f8e1cf..9b017a9d06 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java @@ -1,11 +1,12 @@ package com.baeldung.algorithms.twopointertechnique; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class TwoSumUnitTest { +class TwoSumUnitTest { private TwoSum twoSum = new TwoSum(); @@ -14,7 +15,7 @@ public class TwoSumUnitTest { private int targetValue; @Test - public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairExists() { + void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairExists() { sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; @@ -24,7 +25,7 @@ public class TwoSumUnitTest { } @Test - public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairDoesNotExists() { + void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairDoesNotExists() { sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; @@ -34,7 +35,7 @@ public class TwoSumUnitTest { } @Test - public void givenASortedArrayOfIntegers_whenTwoSum_thenPairExists() { + void givenASortedArrayOfIntegers_whenTwoSum_thenPairExists() { sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; @@ -44,7 +45,7 @@ public class TwoSumUnitTest { } @Test - public void givenASortedArrayOfIntegers_whenTwoSum_thenPairDoesNotExists() { + void givenASortedArrayOfIntegers_whenTwoSum_thenPairDoesNotExists() { sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/counter/CounterUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/counter/CounterUnitTest.java index 4f914bd289..4a60bcb213 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/counter/CounterUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/counter/CounterUnitTest.java @@ -1,18 +1,18 @@ package com.baeldung.counter; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.*; - -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.baeldung.counter.CounterUtil.MutableInteger; -public class CounterUnitTest { +class CounterUnitTest { @Test - public void whenMapWithWrapperAsCounter_runsSuccessfully() { + void whenMapWithWrapperAsCounter_runsSuccessfully() { Map counterMap = new HashMap<>(); CounterUtil.counterWithWrapperObject(counterMap); @@ -23,7 +23,7 @@ public class CounterUnitTest { } @Test - public void whenMapWithLambdaAndWrapperCounter_runsSuccessfully() { + void whenMapWithLambdaAndWrapperCounter_runsSuccessfully() { Map counterMap = new HashMap<>(); CounterUtil.counterWithLambdaAndWrapper(counterMap); @@ -34,7 +34,7 @@ public class CounterUnitTest { } @Test - public void whenMapWithMutableIntegerCounter_runsSuccessfully() { + void whenMapWithMutableIntegerCounter_runsSuccessfully() { Map counterMap = new HashMap<>(); CounterUtil.counterWithMutableInteger(counterMap); assertEquals(3, counterMap.get("China") @@ -44,7 +44,7 @@ public class CounterUnitTest { } @Test - public void whenMapWithPrimitiveArray_runsSuccessfully() { + void whenMapWithPrimitiveArray_runsSuccessfully() { Map counterMap = new HashMap<>(); CounterUtil.counterWithPrimitiveArray(counterMap); assertEquals(3, counterMap.get("China")[0]); diff --git a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java index 43e33d8378..4db4ebd337 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-3/src/test/java/com/baeldung/folding/FoldingHashUnitTest.java @@ -1,22 +1,22 @@ package com.baeldung.folding; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class FoldingHashUnitTest { +class FoldingHashUnitTest { @Test - public void givenStringJavaLanguage_whenSize2Capacity100000_then48933() throws Exception { + void givenStringJavaLanguage_whenSize2Capacity100000_then48933() throws Exception { final FoldingHash hasher = new FoldingHash(); final int value = hasher.hash("Java language", 2, 100_000); assertEquals(value, 48933); } @Test - public void givenStringVaJaLanguage_whenSize2Capacity100000_thenSameAsJavaLanguage() throws Exception { + void givenStringVaJaLanguage_whenSize2Capacity100000_thenSameAsJavaLanguage() throws Exception { final FoldingHash hasher = new FoldingHash(); final int java = hasher.hash("Java language", 2, 100_000); final int vaja = hasher.hash("vaJa language", 2, 100_000); @@ -24,28 +24,28 @@ public class FoldingHashUnitTest { } @Test - public void givenSingleElementArray_whenOffset0Size2_thenSingleElement() throws Exception { + void givenSingleElementArray_whenOffset0Size2_thenSingleElement() throws Exception { final FoldingHash hasher = new FoldingHash(); final int[] value = hasher.extract(new int[] { 5 }, 0, 2); assertArrayEquals(new int[] { 5 }, value); } @Test - public void givenFiveElementArray_whenOffset0Size3_thenFirstThreeElements() throws Exception { + void givenFiveElementArray_whenOffset0Size3_thenFirstThreeElements() throws Exception { final FoldingHash hasher = new FoldingHash(); final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 0, 3); assertArrayEquals(new int[] { 1, 2, 3 }, value); } @Test - public void givenFiveElementArray_whenOffset1Size2_thenTwoElements() throws Exception { + void givenFiveElementArray_whenOffset1Size2_thenTwoElements() throws Exception { final FoldingHash hasher = new FoldingHash(); final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 1, 2); assertArrayEquals(new int[] { 2, 3 }, value); } @Test - public void givenFiveElementArray_whenOffset2SizeTooBig_thenElementsToTheEnd() throws Exception { + void givenFiveElementArray_whenOffset2SizeTooBig_thenElementsToTheEnd() throws Exception { final FoldingHash hasher = new FoldingHash(); final int[] value = hasher.extract(new int[] { 1, 2, 3, 4, 5 }, 2, 2000); assertArrayEquals(new int[] { 3, 4, 5 }, value); diff --git a/algorithms-modules/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/MiddleElementLookupUnitTest.java b/algorithms-modules/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/MiddleElementLookupUnitTest.java index 2cda0ccb36..0759f2c020 100644 --- a/algorithms-modules/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/MiddleElementLookupUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-4/src/test/java/com/baeldung/algorithms/MiddleElementLookupUnitTest.java @@ -1,18 +1,19 @@ package com.baeldung.algorithms; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + import com.baeldung.algorithms.middleelementlookup.MiddleElementLookup; import com.baeldung.algorithms.middleelementlookup.Node; -import org.junit.Test; import java.util.LinkedList; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import org.junit.jupiter.api.Test; -public class MiddleElementLookupUnitTest { +class MiddleElementLookupUnitTest { @Test - public void whenFindingMiddleLinkedList_thenMiddleFound() { + void whenFindingMiddleLinkedList_thenMiddleFound() { assertEquals("3", MiddleElementLookup .findMiddleElementLinkedList(createLinkedList(5)) .get()); @@ -22,7 +23,7 @@ public class MiddleElementLookupUnitTest { } @Test - public void whenFindingMiddleFromHead_thenMiddleFound() { + void whenFindingMiddleFromHead_thenMiddleFound() { assertEquals("3", MiddleElementLookup .findMiddleElementFromHead(createNodesList(5)) .get()); @@ -32,7 +33,7 @@ public class MiddleElementLookupUnitTest { } @Test - public void whenFindingMiddleFromHead1PassRecursively_thenMiddleFound() { + void whenFindingMiddleFromHead1PassRecursively_thenMiddleFound() { assertEquals("3", MiddleElementLookup .findMiddleElementFromHead1PassRecursively(createNodesList(5)) .get()); @@ -42,7 +43,7 @@ public class MiddleElementLookupUnitTest { } @Test - public void whenFindingMiddleFromHead1PassIteratively_thenMiddleFound() { + void whenFindingMiddleFromHead1PassIteratively_thenMiddleFound() { assertEquals("3", MiddleElementLookup .findMiddleElementFromHead1PassIteratively(createNodesList(5)) .get()); @@ -52,7 +53,7 @@ public class MiddleElementLookupUnitTest { } @Test - public void whenListEmptyOrNull_thenMiddleNotFound() { + void whenListEmptyOrNull_thenMiddleNotFound() { // null list assertFalse(MiddleElementLookup .findMiddleElementLinkedList(null) diff --git a/algorithms-modules/algorithms-miscellaneous-5/pom.xml b/algorithms-modules/algorithms-miscellaneous-5/pom.xml index 97c61cb88f..92b8e7d1f5 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/pom.xml +++ b/algorithms-modules/algorithms-miscellaneous-5/pom.xml @@ -34,6 +34,23 @@ guava ${guava.version} + + + jakarta.xml.bind + jakarta.xml.bind-api + ${xml-bind-api.version} + + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb-runtime.version} + + + 4.0.0 + 4.0.0 + + \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java index d3e251d3fd..ae434d88ad 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/conversion/HexStringConverter.java @@ -2,13 +2,15 @@ package com.baeldung.algorithms.conversion; import java.math.BigInteger; -import javax.xml.bind.DatatypeConverter; + import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import com.google.common.io.BaseEncoding; +import jakarta.xml.bind.DatatypeConverter; + public class HexStringConverter { /** @@ -90,7 +92,7 @@ public class HexStringConverter { return DatatypeConverter.parseHexBinary(hexString); } - public String encodeUsingApacheCommons(byte[] bytes) throws DecoderException { + public String encodeUsingApacheCommons(byte[] bytes) { return Hex.encodeHexString(bytes); } diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java index 25f313f991..154bc80932 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/balancedbinarytree/BalancedBinaryTreeUnitTest.java @@ -1,22 +1,23 @@ package com.baeldung.algorithms.balancedbinarytree; -import org.junit.Test; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class BalancedBinaryTreeUnitTest extends BinaryTreeDataProvider { +import org.junit.jupiter.api.Test; + +class BalancedBinaryTreeUnitTest extends BinaryTreeDataProvider { @Test - public void givenBalancedTrees_whenCallingIsBalanced_ShouldReturnTrue() { + void givenBalancedTrees_whenCallingIsBalanced_ShouldReturnTrue() { for (Tree tree : balancedTrees()) { - assertTrue(toString(tree) + " should be balanced", BalancedBinaryTree.isBalanced(tree)); + assertTrue(BalancedBinaryTree.isBalanced(tree), toString(tree) + " should be balanced"); } } @Test - public void givenUnbalancedTrees_whenCallingIsBalanced_ShouldReturnFalse() { + void givenUnbalancedTrees_whenCallingIsBalanced_ShouldReturnFalse() { for (Tree tree : unbalancedTrees()) { - assertFalse(toString(tree) + " should not be balanced", BalancedBinaryTree.isBalanced(tree)); + assertFalse(BalancedBinaryTree.isBalanced(tree), toString(tree) + " should not be balanced"); } } diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java index 304d36e2bb..7404c9b5bd 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/binarygap/BinaryGapUnitTest.java @@ -5,27 +5,31 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class BinaryGapUnitTest { +class BinaryGapUnitTest { - @Test public void givenNoOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + @Test + void givenNoOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { int result = calculateBinaryGap(63); assertEquals(0, result); } - @Test public void givenTrailingZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + @Test + void givenTrailingZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { int result = calculateBinaryGap(40); assertEquals(1, result); } - @Test public void givenSingleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + @Test + void givenSingleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { int result = calculateBinaryGap(9); assertEquals(2, result); } - @Test public void givenMultipleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { + @Test + void givenMultipleOccurrenceOfBoundedZeros_whenCalculateBinaryGap_thenOutputCorrectResult() { int result = calculateBinaryGap(145); assertEquals(3, result); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java index 95ffdec239..9f82c444cb 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java @@ -1,17 +1,18 @@ package com.baeldung.algorithms.combinatorics; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + import java.util.Arrays; import java.util.HashSet; import java.util.List; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; +import org.junit.jupiter.api.Test; -public class CombinatoricsUnitTest { +class CombinatoricsUnitTest { @Test - public void givenEmptySequence_whenCallingPermutations_ShouldReturnEmptyList() { + void givenEmptySequence_whenCallingPermutations_ShouldReturnEmptyList() { List sequence = Arrays.asList(); List> permutations = Combinatorics.permutations(sequence); @@ -20,7 +21,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenOneElementSequence_whenCallingPermutations_ShouldReturnPermutations() { + void givenOneElementSequence_whenCallingPermutations_ShouldReturnPermutations() { List sequence = Arrays.asList(1); List> permutations = Combinatorics.permutations(sequence); @@ -31,7 +32,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenFourElementsSequence_whenCallingPermutations_ShouldReturnPermutations() { + void givenFourElementsSequence_whenCallingPermutations_ShouldReturnPermutations() { List sequence = Arrays.asList(1, 2, 3, 4); List> permutations = Combinatorics.permutations(sequence); @@ -41,7 +42,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenTwoElements_whenCalling3Combinations_ShouldReturnEmptyList() { + void givenTwoElements_whenCalling3Combinations_ShouldReturnEmptyList() { List set = Arrays.asList(1, 2); List> combinations = Combinatorics.combinations(set, 3); @@ -50,7 +51,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenThreeElements_whenCalling3Combinations_ShouldReturnOneCombination() { + void givenThreeElements_whenCalling3Combinations_ShouldReturnOneCombination() { List set = Arrays.asList(1, 2, 3); List> combinations = Combinatorics.combinations(set, 3); @@ -60,7 +61,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenFourElements_whenCalling2Combinations_ShouldReturnCombinations() { + void givenFourElements_whenCalling2Combinations_ShouldReturnCombinations() { List set = Arrays.asList(1, 2, 3, 4); List> combinations = Combinatorics.combinations(set, 2); @@ -70,7 +71,7 @@ public class CombinatoricsUnitTest { } @Test - public void givenFourElements_whenCallingPowerSet_ShouldReturn15Sets() { + void givenFourElements_whenCallingPowerSet_ShouldReturn15Sets() { List sequence = Arrays.asList('a', 'b', 'c', 'd'); List> combinations = Combinatorics.powerSet(sequence); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java index be61802705..bb344e8b30 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/conversion/ByteArrayConverterUnitTest.java @@ -1,27 +1,27 @@ package com.baeldung.algorithms.conversion; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.apache.commons.codec.DecoderException; import org.hamcrest.text.IsEqualIgnoringCase; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.conversion.HexStringConverter; -public class ByteArrayConverterUnitTest { +class ByteArrayConverterUnitTest { private HexStringConverter hexStringConverter; - @Before + @BeforeEach public void setup() { hexStringConverter = new HexStringConverter(); } @Test - public void shouldEncodeByteArrayToHexStringUsingBigIntegerToString() { + void shouldEncodeByteArrayToHexStringUsingBigIntegerToString() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); if(hexString.charAt(0) == '0') { @@ -32,7 +32,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldEncodeByteArrayToHexStringUsingBigIntegerStringFormat() { + void shouldEncodeByteArrayToHexStringUsingBigIntegerStringFormat() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); String output = hexStringConverter.encodeUsingBigIntegerStringFormat(bytes); @@ -40,7 +40,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldDecodeHexStringToByteArrayUsingBigInteger() { + void shouldDecodeHexStringToByteArrayUsingBigInteger() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); byte[] output = hexStringConverter.decodeUsingBigInteger(hexString); @@ -48,7 +48,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldEncodeByteArrayToHexStringUsingCharacterConversion() { + void shouldEncodeByteArrayToHexStringUsingCharacterConversion() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); String output = hexStringConverter.encodeHexString(bytes); @@ -56,20 +56,22 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldDecodeHexStringToByteArrayUsingCharacterConversion() { + void shouldDecodeHexStringToByteArrayUsingCharacterConversion() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); byte[] output = hexStringConverter.decodeHexString(hexString); assertArrayEquals(bytes, output); } - @Test(expected=IllegalArgumentException.class) - public void shouldDecodeHexToByteWithInvalidHexCharacter() { - hexStringConverter.hexToByte("fg"); + @Test + void shouldDecodeHexToByteWithInvalidHexCharacter() { + assertThrows(IllegalArgumentException.class, () -> { + hexStringConverter.hexToByte("fg"); + }); } @Test - public void shouldEncodeByteArrayToHexStringDataTypeConverter() { + void shouldEncodeByteArrayToHexStringDataTypeConverter() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); String output = hexStringConverter.encodeUsingDataTypeConverter(bytes); @@ -77,7 +79,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldDecodeHexStringToByteArrayUsingDataTypeConverter() { + void shouldDecodeHexStringToByteArrayUsingDataTypeConverter() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); byte[] output = hexStringConverter.decodeUsingDataTypeConverter(hexString); @@ -85,7 +87,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldEncodeByteArrayToHexStringUsingGuava() { + void shouldEncodeByteArrayToHexStringUsingGuava() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); String output = hexStringConverter.encodeUsingGuava(bytes); @@ -93,7 +95,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldDecodeHexStringToByteArrayUsingGuava() { + void shouldDecodeHexStringToByteArrayUsingGuava() { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); byte[] output = hexStringConverter.decodeUsingGuava(hexString); @@ -101,7 +103,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldEncodeByteArrayToHexStringUsingApacheCommons() throws DecoderException { + void shouldEncodeByteArrayToHexStringUsingApacheCommons() throws DecoderException { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); String output = hexStringConverter.encodeUsingApacheCommons(bytes); @@ -109,7 +111,7 @@ public class ByteArrayConverterUnitTest { } @Test - public void shouldDecodeHexStringToByteArrayUsingApacheCommons() throws DecoderException { + void shouldDecodeHexStringToByteArrayUsingApacheCommons() throws DecoderException { byte[] bytes = getSampleBytes(); String hexString = getSampleHexString(); byte[] output = hexStringConverter.decodeUsingApacheCommons(hexString); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/integerstreammedian/MedianOfIntegerStreamUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/integerstreammedian/MedianOfIntegerStreamUnitTest.java index bcea4ebba8..b37ef5af7d 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/integerstreammedian/MedianOfIntegerStreamUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/integerstreammedian/MedianOfIntegerStreamUnitTest.java @@ -1,16 +1,18 @@ package com.baeldung.algorithms.integerstreammedian; -import org.junit.Test; + + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.LinkedHashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.Test; -public class MedianOfIntegerStreamUnitTest { +class MedianOfIntegerStreamUnitTest { @Test - public void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach1() { + void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach1() { MedianOfIntegerStream mis = new MedianOfIntegerStream(); for (Map.Entry e : testcaseFixture().entrySet()) { mis.add(e.getKey()); @@ -19,7 +21,7 @@ public class MedianOfIntegerStreamUnitTest { } @Test - public void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach2() { + void givenStreamOfIntegers_whenAnElementIsRead_thenMedianChangesWithApproach2() { MedianOfIntegerStream2 mis = new MedianOfIntegerStream2(); for (Map.Entry e : testcaseFixture().entrySet()) { mis.add(e.getKey()); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java index b168e6b1eb..f6d802f50b 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/knapsack/KnapsackUnitTest.java @@ -4,10 +4,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class KnapsackUnitTest { +class KnapsackUnitTest { @Test - public void givenWeightsandValues_whenCalculateMax_thenOutputCorrectResult() { + void givenWeightsandValues_whenCalculateMax_thenOutputCorrectResult() { final int[] w = new int[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }; final int[] v = new int[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; final int n = 10; @@ -19,7 +19,7 @@ public class KnapsackUnitTest { } @Test - public void givenZeroItems_whenCalculateMax_thenOutputZero() { + void givenZeroItems_whenCalculateMax_thenOutputZero() { final int[] w = new int[] {}; final int[] v = new int[] {}; final int n = 0; @@ -31,7 +31,7 @@ public class KnapsackUnitTest { } @Test - public void givenZeroWeightLimit_whenCalculateMax_thenOutputZero() { + void givenZeroWeightLimit_whenCalculateMax_thenOutputZero() { final int[] w = new int[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }; final int[] v = new int[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }; final int n = 10; diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/mergesortedarrays/SortedArraysUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/mergesortedarrays/SortedArraysUnitTest.java index 76eeb7b116..ca6824fd15 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/mergesortedarrays/SortedArraysUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/mergesortedarrays/SortedArraysUnitTest.java @@ -5,10 +5,10 @@ import org.junit.jupiter.api.Test; import com.baeldung.algorithms.mergesortedarrays.SortedArrays; -public class SortedArraysUnitTest { +class SortedArraysUnitTest { @Test - public void givenTwoSortedArrays_whenMerged_thenReturnMergedSortedArray() { + void givenTwoSortedArrays_whenMerged_thenReturnMergedSortedArray() { int[] foo = { 3, 7 }; int[] bar = { 4, 8, 11 }; @@ -18,7 +18,7 @@ public class SortedArraysUnitTest { } @Test - public void givenTwoSortedArraysWithDuplicates_whenMerged_thenReturnMergedSortedArray() { + void givenTwoSortedArraysWithDuplicates_whenMerged_thenReturnMergedSortedArray() { int[] foo = { 3, 3, 7 }; int[] bar = { 4, 8, 8, 11 }; diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java index fac3b3a81f..a5eb6f4d89 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java @@ -1,14 +1,15 @@ package com.baeldung.algorithms.prim; -import org.junit.Test; import java.util.ArrayList; import java.util.List; -public class PrimUnitTest { +import org.junit.jupiter.api.Test; + +class PrimUnitTest { @Test - public void givenAGraph_whenPrimRuns_thenPrintMST() { + void givenAGraph_whenPrimRuns_thenPrintMST() { Prim prim = new Prim(createGraph()); System.out.println(prim.originalGraphToString()); System.out.println("----------------"); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java index 84bb2620af..8218649e98 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java @@ -1,49 +1,49 @@ package com.baeldung.algorithms.relativelyprime; -import org.junit.Test; - import static com.baeldung.algorithms.relativelyprime.RelativelyPrime.*; import static org.assertj.core.api.Assertions.assertThat; -public class RelativelyPrimeUnitTest { +import org.junit.jupiter.api.Test; + +class RelativelyPrimeUnitTest { @Test - public void givenNonRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnFalse() { + void givenNonRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnFalse() { boolean result = iterativeRelativelyPrime(45, 35); assertThat(result).isFalse(); } @Test - public void givenRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnTrue() { + void givenRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnTrue() { boolean result = iterativeRelativelyPrime(500, 501); assertThat(result).isTrue(); } @Test - public void givenNonRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnFalse() { + void givenNonRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnFalse() { boolean result = recursiveRelativelyPrime(45, 35); assertThat(result).isFalse(); } @Test - public void givenRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnTrue() { + void givenRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnTrue() { boolean result = recursiveRelativelyPrime(500, 501); assertThat(result).isTrue(); } @Test - public void givenNonRelativelyPrimeNumbers_whenCheckingUsingBigIntegers_shouldReturnFalse() { + void givenNonRelativelyPrimeNumbers_whenCheckingUsingBigIntegers_shouldReturnFalse() { boolean result = bigIntegerRelativelyPrime(45, 35); assertThat(result).isFalse(); } @Test - public void givenRelativelyPrimeNumbers_whenCheckingBigIntegers_shouldReturnTrue() { + void givenRelativelyPrimeNumbers_whenCheckingBigIntegers_shouldReturnTrue() { boolean result = bigIntegerRelativelyPrime(500, 501); assertThat(result).isTrue(); diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java index 44fac57361..2366a897c6 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java @@ -4,10 +4,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class TreeReverserUnitTest { +class TreeReverserUnitTest { @Test - public void givenTreeWhenReversingRecursivelyThenReversed() { + void givenTreeWhenReversingRecursivelyThenReversed() { TreeReverser reverser = new TreeReverser(); TreeNode treeNode = createBinaryTree(); @@ -19,7 +19,7 @@ public class TreeReverserUnitTest { } @Test - public void givenTreeWhenReversingIterativelyThenReversed() { + void givenTreeWhenReversingIterativelyThenReversed() { TreeReverser reverser = new TreeReverser(); TreeNode treeNode = createBinaryTree(); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingDequeUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingDequeUnitTest.java index 4c0a56dabc..b7a6a6470e 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingDequeUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingDequeUnitTest.java @@ -1,80 +1,81 @@ package com.baeldung.algorithms.balancedbrackets; -import org.junit.Before; -import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; -public class BalancedBracketsUsingDequeUnitTest { +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BalancedBracketsUsingDequeUnitTest { private BalancedBracketsUsingDeque balancedBracketsUsingDeque; - @Before + @BeforeEach public void setup() { balancedBracketsUsingDeque = new BalancedBracketsUsingDeque(); } @Test - public void givenNullInput_whenCheckingForBalance_shouldReturnFalse() { + void givenNullInput_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced(null); assertThat(result).isFalse(); } @Test - public void givenEmptyString_whenCheckingForBalance_shouldReturnTrue() { + void givenEmptyString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingDeque.isBalanced(""); assertThat(result).isTrue(); } @Test - public void givenInvalidCharacterString_whenCheckingForBalance_shouldReturnFalse() { + void givenInvalidCharacterString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("abc[](){}"); assertThat(result).isFalse(); } @Test - public void givenOddLengthString_whenCheckingForBalance_shouldReturnFalse() { + void givenOddLengthString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("{{[]()}}}"); assertThat(result).isFalse(); } @Test - public void givenEvenLengthString_whenCheckingForBalance_shouldReturnFalse() { + void givenEvenLengthString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("{{[]()}}}}"); assertThat(result).isFalse(); } @Test - public void givenEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("{[(])}"); assertThat(result).isFalse(); } @Test - public void givenAnotherEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenAnotherEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("{{}("); assertThat(result).isFalse(); } @Test - public void givenEvenLengthBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenEvenLengthBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingDeque.isBalanced("{[()]}"); assertThat(result).isTrue(); } @Test - public void givenBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingDeque.isBalanced("{{[[(())]]}}"); assertThat(result).isTrue(); } @Test - public void givenAnotherBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenAnotherBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingDeque.isBalanced("{{([])}}"); assertThat(result).isTrue(); } @Test - public void givenUnBalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenUnBalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingDeque.isBalanced("{{)[](}}"); assertThat(result).isFalse(); } diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingStringUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingStringUnitTest.java index bda85a75ce..71bd91c39a 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingStringUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/balancedbrackets/BalancedBracketsUsingStringUnitTest.java @@ -1,80 +1,81 @@ package com.baeldung.algorithms.balancedbrackets; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -public class BalancedBracketsUsingStringUnitTest { +class BalancedBracketsUsingStringUnitTest { private BalancedBracketsUsingString balancedBracketsUsingString; - @Before + @BeforeEach public void setup() { balancedBracketsUsingString = new BalancedBracketsUsingString(); } @Test - public void givenNullInput_whenCheckingForBalance_shouldReturnFalse() { + void givenNullInput_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced(null); assertThat(result).isFalse(); } @Test - public void givenEmptyString_whenCheckingForBalance_shouldReturnTrue() { + void givenEmptyString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingString.isBalanced(""); assertThat(result).isTrue(); } @Test - public void givenInvalidCharacterString_whenCheckingForBalance_shouldReturnFalse() { + void givenInvalidCharacterString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("abc[](){}"); assertThat(result).isFalse(); } @Test - public void givenOddLengthString_whenCheckingForBalance_shouldReturnFalse() { + void givenOddLengthString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("{{[]()}}}"); assertThat(result).isFalse(); } @Test - public void givenEvenLengthString_whenCheckingForBalance_shouldReturnFalse() { + void givenEvenLengthString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("{{[]()}}}}"); assertThat(result).isFalse(); } @Test - public void givenEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("{[(])}"); assertThat(result).isFalse(); } @Test - public void givenAnotherEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenAnotherEvenLengthUnbalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("{{}("); assertThat(result).isFalse(); } @Test - public void givenEvenLengthBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenEvenLengthBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingString.isBalanced("{[()]}"); assertThat(result).isTrue(); } @Test - public void givenBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingString.isBalanced("{{[[(())]]}}"); assertThat(result).isTrue(); } @Test - public void givenAnotherBalancedString_whenCheckingForBalance_shouldReturnTrue() { + void givenAnotherBalancedString_whenCheckingForBalance_shouldReturnTrue() { boolean result = balancedBracketsUsingString.isBalanced("{{([])}}"); assertThat(result).isTrue(); } @Test - public void givenUnBalancedString_whenCheckingForBalance_shouldReturnFalse() { + void givenUnBalancedString_whenCheckingForBalance_shouldReturnFalse() { boolean result = balancedBracketsUsingString.isBalanced("{{)[](}}"); assertThat(result).isFalse(); } diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/boruvka/BoruvkaUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/boruvka/BoruvkaUnitTest.java index e61e1e668d..7261dfffc6 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/boruvka/BoruvkaUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/boruvka/BoruvkaUnitTest.java @@ -2,17 +2,17 @@ package com.baeldung.algorithms.boruvka; import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.google.common.graph.MutableValueGraph; import com.google.common.graph.ValueGraphBuilder; -public class BoruvkaUnitTest { +class BoruvkaUnitTest { private MutableValueGraph graph; - @Before + @BeforeEach public void setup() { graph = ValueGraphBuilder.undirected() .build(); @@ -26,7 +26,7 @@ public class BoruvkaUnitTest { } @Test - public void givenInputGraph_whenBoruvkaPerformed_thenMinimumSpanningTree() { + void givenInputGraph_whenBoruvkaPerformed_thenMinimumSpanningTree() { BoruvkaMST boruvkaMST = new BoruvkaMST(graph); MutableValueGraph mst = boruvkaMST.getMST(); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/gradientdescent/GradientDescentUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/gradientdescent/GradientDescentUnitTest.java index 34d3e188f2..d7aa952037 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/gradientdescent/GradientDescentUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/gradientdescent/GradientDescentUnitTest.java @@ -1,15 +1,15 @@ package com.baeldung.algorithms.gradientdescent; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.function.Function; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class GradientDescentUnitTest { +class GradientDescentUnitTest { @Test - public void givenFunction_whenStartingPointIsOne_thenLocalMinimumIsFound() { + void givenFunction_whenStartingPointIsOne_thenLocalMinimumIsFound() { Function df = x -> StrictMath.abs(StrictMath.pow(x, 3)) - (3 * StrictMath.pow(x, 2)) + x; GradientDescent gd = new GradientDescent(); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/greedy/GreedyAlgorithmUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/greedy/GreedyAlgorithmUnitTest.java index a503b006de..ea90ea14c1 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/greedy/GreedyAlgorithmUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/greedy/GreedyAlgorithmUnitTest.java @@ -1,13 +1,14 @@ package com.baeldung.algorithms.greedy; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; import java.util.Arrays; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -public class GreedyAlgorithmUnitTest { + +class GreedyAlgorithmUnitTest { private SocialConnector prepareNetwork() { SocialConnector sc = new SocialConnector(); @@ -35,21 +36,21 @@ public class GreedyAlgorithmUnitTest { } @Test - public void greedyAlgorithmTest() { + void greedyAlgorithmTest() { GreedyAlgorithm ga = new GreedyAlgorithm(prepareNetwork()); assertEquals(ga.findMostFollowersPath("root"), 5); } @Test - public void nongreedyAlgorithmTest() { + void nongreedyAlgorithmTest() { NonGreedyAlgorithm nga = new NonGreedyAlgorithm(prepareNetwork(), 0); - Assertions.assertThrows(IllegalStateException.class, () -> { + assertThrows(IllegalStateException.class, () -> { nga.findMostFollowersPath("root"); }); } @Test - public void nongreedyAlgorithmUnboundedTest() { + void nongreedyAlgorithmUnboundedTest() { SocialConnector sc = prepareNetwork(); sc.switchCounter(); NonGreedyAlgorithm nga = new NonGreedyAlgorithm(sc, 0); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java index a7206c6cd0..9367942dc6 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java @@ -1,21 +1,23 @@ package com.baeldung.algorithms.kruskal; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; -import org.junit.Before; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import com.google.common.graph.MutableValueGraph; import com.google.common.graph.ValueGraph; import com.google.common.graph.ValueGraphBuilder; import com.baeldung.algorithms.kruskal.Kruskal; -public class KruskalUnitTest { +class KruskalUnitTest { private MutableValueGraph graph; - @Before + @BeforeEach public void setup() { graph = ValueGraphBuilder.undirected().build(); graph.putEdgeValue(0, 1, 8.0); @@ -28,7 +30,7 @@ public class KruskalUnitTest { } @Test - public void givenGraph_whenMinimumSpanningTree_thenOutputCorrectResult() { + void givenGraph_whenMinimumSpanningTree_thenOutputCorrectResult() { final Kruskal kruskal = new Kruskal(); ValueGraph spanningTree = kruskal.minSpanningTree(graph); @@ -47,7 +49,7 @@ public class KruskalUnitTest { } @Test - public void givenGraph_whenMaximumSpanningTree_thenOutputCorrectResult() { + void givenGraph_whenMaximumSpanningTree_thenOutputCorrectResult() { final Kruskal kruskal = new Kruskal(); ValueGraph spanningTree = kruskal.maxSpanningTree(graph); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java index 0940677959..0d222c0841 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java @@ -1,13 +1,13 @@ package com.baeldung.algorithms.linkedlist; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import org.junit.jupiter.api.Test; -public class LinkedListReversalUnitTest { +class LinkedListReversalUnitTest { @Test - public void givenLinkedList_whenIterativeReverse_thenOutputCorrectResult() { + void givenLinkedList_whenIterativeReverse_thenOutputCorrectResult() { ListNode head = constructLinkedList(); ListNode node = head; for (int i = 1; i <= 5; i++) { @@ -25,7 +25,7 @@ public class LinkedListReversalUnitTest { } @Test - public void givenLinkedList_whenRecursiveReverse_thenOutputCorrectResult() { + void givenLinkedList_whenRecursiveReverse_thenOutputCorrectResult() { ListNode head = constructLinkedList(); ListNode node = head; for (int i = 1; i <= 5; i++) { diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/minheapmerge/MinHeapUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/minheapmerge/MinHeapUnitTest.java index f84c860dcc..c5b78bbf48 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/minheapmerge/MinHeapUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/minheapmerge/MinHeapUnitTest.java @@ -2,17 +2,17 @@ package com.baeldung.algorithms.minheapmerge; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class MinHeapUnitTest { +class MinHeapUnitTest { private final int[][] inputArray = { { 0, 6 }, { 1, 5, 10, 100 }, { 2, 4, 200, 650 } }; private final int[] expectedArray = { 0, 1, 2, 4, 5, 6, 10, 100, 200, 650 }; @Test - public void givenSortedArrays_whenMerged_thenShouldReturnASingleSortedarray() { + void givenSortedArrays_whenMerged_thenShouldReturnASingleSortedarray() { int[] resultArray = MinHeap.merge(inputArray); assertThat(resultArray.length, is(equalTo(10))); diff --git a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/topkelements/TopKElementsFinderUnitTest.java b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/topkelements/TopKElementsFinderUnitTest.java index 41fa5e067e..d979d1c856 100644 --- a/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/topkelements/TopKElementsFinderUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/topkelements/TopKElementsFinderUnitTest.java @@ -1,13 +1,13 @@ package com.baeldung.algorithms.topkelements; -import org.junit.Test; - import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Java6Assertions.assertThat; -public class TopKElementsFinderUnitTest { +import org.junit.jupiter.api.Test; + +class TopKElementsFinderUnitTest { private final TopKElementsFinder bruteForceFinder = new BruteForceTopKElementsFinder(); private final TopKElementsFinder maxHeapFinder = new MaxHeapTopKElementsFinder(); private final TopKElementsFinder treeSetFinder = new TreeSetTopKElementsFinder(); @@ -20,27 +20,27 @@ public class TopKElementsFinderUnitTest { @Test - public void givenArrayDistinctIntegers_whenBruteForceFindTopK_thenReturnKLargest() { + void givenArrayDistinctIntegers_whenBruteForceFindTopK_thenReturnKLargest() { assertThat(bruteForceFinder.findTopK(distinctIntegers, k)).containsOnlyElementsOf(distinctIntegersTopK); } @Test - public void givenArrayDistinctIntegers_whenMaxHeapFindTopK_thenReturnKLargest() { + void givenArrayDistinctIntegers_whenMaxHeapFindTopK_thenReturnKLargest() { assertThat(maxHeapFinder.findTopK(distinctIntegers, k)).containsOnlyElementsOf(distinctIntegersTopK); } @Test - public void givenArrayDistinctIntegers_whenTreeSetFindTopK_thenReturnKLargest() { + void givenArrayDistinctIntegers_whenTreeSetFindTopK_thenReturnKLargest() { assertThat(treeSetFinder.findTopK(distinctIntegers, k)).containsOnlyElementsOf(distinctIntegersTopK); } @Test - public void givenArrayNonDistinctIntegers_whenBruteForceFindTopK_thenReturnKLargest() { + void givenArrayNonDistinctIntegers_whenBruteForceFindTopK_thenReturnKLargest() { assertThat(bruteForceFinder.findTopK(nonDistinctIntegers, k)).containsOnlyElementsOf(nonDistinctIntegersTopK); } @Test - public void givenArrayNonDistinctIntegers_whenMaxHeapFindTopK_thenReturnKLargest() { + void givenArrayNonDistinctIntegers_whenMaxHeapFindTopK_thenReturnKLargest() { assertThat(maxHeapFinder.findTopK(nonDistinctIntegers, k)).containsOnlyElementsOf(nonDistinctIntegersTopK); } } diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/luhn/LuhnCheckerUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/luhn/LuhnCheckerUnitTest.java index dd1b184b81..9f7c93c1b3 100644 --- a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/luhn/LuhnCheckerUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/luhn/LuhnCheckerUnitTest.java @@ -1,63 +1,66 @@ package com.baeldung.algorithms.luhn; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class LuhnCheckerUnitTest { +import org.junit.jupiter.api.Test; + +class LuhnCheckerUnitTest { @Test - public void whenCardNumberDoesMeetLuhnCriteria_thenCheckLuhnReturnsTrue() { + void whenCardNumberDoesMeetLuhnCriteria_thenCheckLuhnReturnsTrue() { String cardNumber = "8649"; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertTrue(result); + assertTrue(result); } @Test - public void whenCardNumberDoesNotMeetLuhnCriteria_thenCheckLuhnReturnsFalse() { + void whenCardNumberDoesNotMeetLuhnCriteria_thenCheckLuhnReturnsFalse() { String cardNumber = "8642"; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertFalse(result); + assertFalse(result); } @Test - public void whenCardNumberHasNoSecondDigits_thenCheckLuhnCalculatesCorrectly() { + void whenCardNumberHasNoSecondDigits_thenCheckLuhnCalculatesCorrectly() { String cardNumber = "0505050505050505"; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertTrue(result); + assertTrue(result); } @Test - public void whenCardNumberHasSecondDigits_thenCheckLuhnCalculatesCorrectly() { + void whenCardNumberHasSecondDigits_thenCheckLuhnCalculatesCorrectly() { String cardNumber = "75757575757575"; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertTrue(result); + assertTrue(result); } @Test - public void whenDoubleAndSumDigitsIsCalled_thenOutputIsCorrect() { - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(0), 0); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(1), 2); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(2), 4); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(3), 6); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(4), 8); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(5), 1); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(6), 3); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(7), 5); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(8), 7); - Assert.assertEquals(LuhnChecker.doubleAndSumDigits(9), 9); + void whenDoubleAndSumDigitsIsCalled_thenOutputIsCorrect() { + assertEquals(0,LuhnChecker.doubleAndSumDigits(0)); + assertEquals(2,LuhnChecker.doubleAndSumDigits(1)); + assertEquals(4, LuhnChecker.doubleAndSumDigits(2)); + assertEquals(6, LuhnChecker.doubleAndSumDigits(3)); + assertEquals(8, LuhnChecker.doubleAndSumDigits(4)); + assertEquals(1, LuhnChecker.doubleAndSumDigits(5)); + assertEquals(3, LuhnChecker.doubleAndSumDigits(6)); + assertEquals(5, LuhnChecker.doubleAndSumDigits(7)); + assertEquals(7, LuhnChecker.doubleAndSumDigits(8)); + assertEquals(9, LuhnChecker.doubleAndSumDigits(9)); } @Test - public void whenCardNumberNonNumeric_thenCheckLuhnReturnsFalse() { + void whenCardNumberNonNumeric_thenCheckLuhnReturnsFalse() { String cardNumber = "test"; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertFalse(result); + assertFalse(result); } @Test - public void whenCardNumberIsNull_thenCheckLuhnReturnsFalse() { + void whenCardNumberIsNull_thenCheckLuhnReturnsFalse() { String cardNumber = null; boolean result = LuhnChecker.checkLuhn(cardNumber); - Assert.assertFalse(result); + assertFalse(result); } } diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java index eb3fb4f718..8a4dbb2141 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/binarysearch/BinarySearchUnitTest.java @@ -1,11 +1,13 @@ package com.baeldung.algorithms.binarysearch; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.Arrays; import java.util.List; -import org.junit.Assert; -import org.junit.Test; -public class BinarySearchUnitTest { +import org.junit.jupiter.api.Test; + +class BinarySearchUnitTest { int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; int key = 6; @@ -15,27 +17,27 @@ public class BinarySearchUnitTest { List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9); @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() { + void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() { BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high)); + assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high)); } @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() { + void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() { BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high)); + assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high)); } @Test - public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() { + void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() { BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key)); + assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key)); } @Test - public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() { + void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() { BinarySearch binSearch = new BinarySearch(); - Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key)); + assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key)); } } diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java index f98b4377ed..dc83d8eac8 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/BinaryTreeUnitTest.java @@ -1,15 +1,15 @@ package com.baeldung.algorithms.dfs; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.junit.jupiter.api.Test; -public class BinaryTreeUnitTest { +class BinaryTreeUnitTest { @Test - public void givenABinaryTree_WhenAddingElements_ThenTreeNotEmpty() { + void givenABinaryTree_WhenAddingElements_ThenTreeNotEmpty() { BinaryTree bt = createBinaryTree(); @@ -17,7 +17,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() { + void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() { BinaryTree bt = createBinaryTree(); @@ -28,7 +28,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() { + void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() { BinaryTree bt = createBinaryTree(); @@ -40,7 +40,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() { + void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() { BinaryTree bt = createBinaryTree(); @@ -48,7 +48,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() { + void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() { BinaryTree bt = createBinaryTree(); @@ -58,7 +58,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() { + void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() { BinaryTree bt = createBinaryTree(); @@ -71,7 +71,7 @@ public class BinaryTreeUnitTest { } @Test - public void it_deletes_the_root() { + void it_deletes_the_root() { int value = 12; BinaryTree bt = new BinaryTree(); bt.add(value); @@ -82,7 +82,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() { + void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() { BinaryTree bt = createBinaryTree(); @@ -92,7 +92,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() { + void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() { BinaryTree bt = createBinaryTree(); @@ -102,7 +102,7 @@ public class BinaryTreeUnitTest { } @Test - public void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() { + void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() { BinaryTree bt = createBinaryTree(); diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java index 7af25a85ca..086eb77a82 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java @@ -2,12 +2,12 @@ package com.baeldung.algorithms.dfs; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class GraphUnitTest { +class GraphUnitTest { @Test - public void givenDirectedGraph_whenDFS_thenPrintAllValues() { + void givenDirectedGraph_whenDFS_thenPrintAllValues() { Graph graph = createDirectedGraph(); graph.dfs(0); System.out.println(); @@ -15,7 +15,7 @@ public class GraphUnitTest { } @Test - public void givenDirectedGraph_whenGetTopologicalSort_thenPrintValuesSorted() { + void givenDirectedGraph_whenGetTopologicalSort_thenPrintValuesSorted() { Graph graph = createDirectedGraph(); List list = graph.topologicalSort(0); System.out.println(list); diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java index cabedcefad..c9e95b0cc9 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java @@ -1,27 +1,28 @@ package com.baeldung.algorithms.interpolationsearch; -import org.junit.Before; -import org.junit.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -public class InterpolationSearchUnitTest { +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class InterpolationSearchUnitTest { private int[] myData; - @Before + @BeforeEach public void setUp() { myData = new int[]{13,21,34,55,69,73,84,101}; } @Test - public void givenSortedArray_whenLookingFor84_thenReturn6() { + void givenSortedArray_whenLookingFor84_thenReturn6() { int pos = InterpolationSearch.interpolationSearch(myData, 84); assertEquals(6, pos); } @Test - public void givenSortedArray_whenLookingFor19_thenReturnMinusOne() { + void givenSortedArray_whenLookingFor19_thenReturnMinusOne() { int pos = InterpolationSearch.interpolationSearch(myData, 19); assertEquals(-1, pos); } diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/kthsmallest/KthSmallestUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/kthsmallest/KthSmallestUnitTest.java index 740e89d8e7..1349be59c0 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/kthsmallest/KthSmallestUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/kthsmallest/KthSmallestUnitTest.java @@ -9,13 +9,13 @@ import java.util.*; import static com.baeldung.algorithms.kthsmallest.KthSmallest.*; import static org.junit.jupiter.api.Assertions.*; -public class KthSmallestUnitTest { +class KthSmallestUnitTest { @Nested class Exceptions { @Test - public void when_at_least_one_list_is_null_then_an_exception_is_thrown() { + void when_at_least_one_list_is_null_then_an_exception_is_thrown() { Executable executable1 = () -> findKthSmallestElement(1, null, null); Executable executable2 = () -> findKthSmallestElement(1, new int[]{2}, null); @@ -27,7 +27,7 @@ public class KthSmallestUnitTest { } @Test - public void when_at_least_one_list_is_empty_then_an_exception_is_thrown() { + void when_at_least_one_list_is_empty_then_an_exception_is_thrown() { Executable executable1 = () -> findKthSmallestElement(1, new int[]{}, new int[]{2}); Executable executable2 = () -> findKthSmallestElement(1, new int[]{2}, new int[]{}); @@ -39,19 +39,19 @@ public class KthSmallestUnitTest { } @Test - public void when_k_is_smaller_than_0_then_an_exception_is_thrown() { + void when_k_is_smaller_than_0_then_an_exception_is_thrown() { Executable executable1 = () -> findKthSmallestElement(-1, new int[]{2}, new int[]{2}); assertThrows(IllegalArgumentException.class, executable1); } @Test - public void when_k_is_smaller_than_1_then_an_exception_is_thrown() { + void when_k_is_smaller_than_1_then_an_exception_is_thrown() { Executable executable1 = () -> findKthSmallestElement(0, new int[]{2}, new int[]{2}); assertThrows(IllegalArgumentException.class, executable1); } @Test - public void when_k_bigger_then_the_two_lists_then_an_exception_is_thrown() { + void when_k_bigger_then_the_two_lists_then_an_exception_is_thrown() { Executable executable1 = () -> findKthSmallestElement(6, new int[]{1, 5, 6}, new int[]{2, 5}); assertThrows(NoSuchElementException.class, executable1); } diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java index 59afed65de..3770ca4ddd 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/mcts/MCTSUnitTest.java @@ -1,12 +1,13 @@ package com.baeldung.algorithms.mcts; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch; import com.baeldung.algorithms.mcts.montecarlo.State; @@ -15,31 +16,31 @@ import com.baeldung.algorithms.mcts.tictactoe.Board; import com.baeldung.algorithms.mcts.tictactoe.Position; import com.baeldung.algorithms.mcts.tree.Tree; -public class MCTSUnitTest { +class MCTSUnitTest { private Tree gameTree; private MonteCarloTreeSearch mcts; - @Before + @BeforeEach public void initGameTree() { gameTree = new Tree(); mcts = new MonteCarloTreeSearch(); } @Test - public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() { + void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() { double uctValue = 15.79; assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01); } @Test - public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() { + void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() { State initState = gameTree.getRoot().getState(); List possibleStates = initState.getAllPossibleStates(); assertTrue(possibleStates.size() > 0); } @Test - public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() { + void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() { Board board = new Board(); int initAvailablePositions = board.getEmptyPositions().size(); board.performMove(Board.P1, new Position(1, 1)); @@ -48,7 +49,7 @@ public class MCTSUnitTest { } @Test - public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() { + void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() { Board board = new Board(); int player = Board.P1; @@ -61,11 +62,11 @@ public class MCTSUnitTest { player = 3 - player; } int winStatus = board.checkStatus(); - assertEquals(winStatus, Board.DRAW); + assertEquals(Board.DRAW, winStatus); } @Test - public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() { + void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() { Board board = new Board(); MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch(); mcts1.setLevel(1); diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java index 4389795ffb..6bb8ad3e09 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java @@ -1,21 +1,22 @@ package com.baeldung.algorithms.quadtree; -import org.junit.Assert; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class QuadTreeSearchUnitTest { +class QuadTreeSearchUnitTest { private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchUnitTest.class); private static QuadTree quadTree; - @BeforeClass + @BeforeAll public static void setUp() { Region area = new Region(0, 0, 400, 400); quadTree = new QuadTree(area); @@ -32,30 +33,30 @@ public class QuadTreeSearchUnitTest { } @Test - public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() { + void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() { Region searchArea = new Region(200, 200, 250, 250); List result = quadTree.search(searchArea, null, ""); LOGGER.debug(result.toString()); LOGGER.debug(quadTree.printSearchTraversePath()); - Assert.assertEquals(1, result.size()); - Assert.assertArrayEquals(new float[] { 245, 238 }, + assertEquals(1, result.size()); + assertArrayEquals(new float[] { 245, 238 }, new float[]{result.get(0).getX(), result.get(0).getY() }, 0); } @Test - public void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() { + void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() { Region searchArea = new Region(0, 0, 100, 100); List result = quadTree.search(searchArea, null, ""); LOGGER.debug(result.toString()); LOGGER.debug(quadTree.printSearchTraversePath()); - Assert.assertEquals(2, result.size()); - Assert.assertArrayEquals(new float[] { 21, 25 }, + assertEquals(2, result.size()); + assertArrayEquals(new float[] { 21, 25 }, new float[]{result.get(0).getX(), result.get(0).getY() }, 0); - Assert.assertArrayEquals(new float[] { 55, 53 }, + assertArrayEquals(new float[] { 55, 53 }, new float[]{result.get(1).getX(), result.get(1).getY() }, 0); } diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/suffixtree/SuffixTreeUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/suffixtree/SuffixTreeUnitTest.java index d9a4f2962c..7ae9a6fcc4 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/suffixtree/SuffixTreeUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/suffixtree/SuffixTreeUnitTest.java @@ -1,71 +1,72 @@ package com.baeldung.algorithms.suffixtree; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + import java.util.List; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SuffixTreeUnitTest { +class SuffixTreeUnitTest { private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTreeUnitTest.class); private static SuffixTree suffixTree; - @BeforeClass + @BeforeAll public static void setUp() { suffixTree = new SuffixTree("havanabanana"); printTree(); } @Test - public void givenSuffixTree_whenSearchingForA_thenReturn6Matches() { + void givenSuffixTree_whenSearchingForA_thenReturn6Matches() { List matches = suffixTree.searchText("a"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] { "h[a]vanabanana", "hav[a]nabanana", "havan[a]banana", "havanab[a]nana", "havanaban[a]na", "havanabanan[a]" }, matches.toArray()); + assertArrayEquals(new String[] { "h[a]vanabanana", "hav[a]nabanana", "havan[a]banana", "havanab[a]nana", "havanaban[a]na", "havanabanan[a]" }, matches.toArray()); } @Test - public void givenSuffixTree_whenSearchingForNab_thenReturn1Match() { + void givenSuffixTree_whenSearchingForNab_thenReturn1Match() { List matches = suffixTree.searchText("nab"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] { "hava[nab]anana" }, matches.toArray()); + assertArrayEquals(new String[] { "hava[nab]anana" }, matches.toArray()); } @Test - public void givenSuffixTree_whenSearchingForNag_thenReturnNoMatches() { + void givenSuffixTree_whenSearchingForNag_thenReturnNoMatches() { List matches = suffixTree.searchText("nag"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] {}, matches.toArray()); + assertArrayEquals(new String[] {}, matches.toArray()); } @Test - public void givenSuffixTree_whenSearchingForBanana_thenReturn2Matches() { + void givenSuffixTree_whenSearchingForBanana_thenReturn2Matches() { List matches = suffixTree.searchText("ana"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] { "hav[ana]banana", "havanab[ana]na", "havanaban[ana]" }, matches.toArray()); + assertArrayEquals(new String[] { "hav[ana]banana", "havanab[ana]na", "havanaban[ana]" }, matches.toArray()); } @Test - public void givenSuffixTree_whenSearchingForNa_thenReturn4Matches() { + void givenSuffixTree_whenSearchingForNa_thenReturn4Matches() { List matches = suffixTree.searchText("na"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] { "hava[na]banana", "havanaba[na]na", "havanabana[na]" }, matches.toArray()); + assertArrayEquals(new String[] { "hava[na]banana", "havanaba[na]na", "havanabana[na]" }, matches.toArray()); } @Test - public void givenSuffixTree_whenSearchingForX_thenReturnNoMatches() { + void givenSuffixTree_whenSearchingForX_thenReturnNoMatches() { List matches = suffixTree.searchText("x"); matches.stream() .forEach(m -> LOGGER.debug(m)); - Assert.assertArrayEquals(new String[] {}, matches.toArray()); + assertArrayEquals(new String[] {}, matches.toArray()); } private static void printTree() { diff --git a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java index 543ccb912f..a1a5e9cbbe 100644 --- a/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java +++ b/algorithms-modules/algorithms-searching/src/test/java/com/baeldung/algorithms/textsearch/TextSearchAlgorithmsUnitTest.java @@ -1,23 +1,24 @@ package com.baeldung.algorithms.textsearch; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class TextSearchAlgorithmsUnitTest { +class TextSearchAlgorithmsUnitTest { @Test - public void testStringSearchAlgorithms() { + void testStringSearchAlgorithms() { String text = "This is some nice text."; String pattern = "some"; int realPosition = text.indexOf(pattern); - Assert.assertTrue(realPosition == TextSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == TextSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == TextSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray())); - Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray())); + assertEquals(TextSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray()), realPosition); + assertEquals(TextSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray()), realPosition); + assertEquals(TextSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray()) , realPosition); + assertEquals(TextSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray()), realPosition); + assertEquals(TextSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray()), realPosition); } } diff --git a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/bynumber/NaturalOrderComparatorsUnitTest.java b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/bynumber/NaturalOrderComparatorsUnitTest.java index aaa5de87e1..d8b9887605 100644 --- a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/bynumber/NaturalOrderComparatorsUnitTest.java +++ b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/bynumber/NaturalOrderComparatorsUnitTest.java @@ -1,17 +1,19 @@ package com.baeldung.algorithms.bynumber; -import org.junit.Test; + + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; -public class NaturalOrderComparatorsUnitTest { +class NaturalOrderComparatorsUnitTest { @Test - public void givenSimpleStringsContainingIntsAndDoubles_whenSortedByRegex_checkSortingCorrect() { + void givenSimpleStringsContainingIntsAndDoubles_whenSortedByRegex_checkSortingCorrect() { List testStrings = Arrays.asList("a1", "b3", "c4", "d2.2", "d2.4", "d2.3d"); @@ -25,7 +27,7 @@ public class NaturalOrderComparatorsUnitTest { } @Test - public void givenSimpleStringsContainingIntsAndDoublesWithAnInvalidNumber_whenSortedByRegex_checkSortingCorrect() { + void givenSimpleStringsContainingIntsAndDoublesWithAnInvalidNumber_whenSortedByRegex_checkSortingCorrect() { List testStrings = Arrays.asList("a1", "b3", "c4", "d2.2", "d2.4", "d2.3.3d"); @@ -39,7 +41,7 @@ public class NaturalOrderComparatorsUnitTest { } @Test - public void givenAllForseenProblems_whenSortedByRegex_checkSortingCorrect() { + void givenAllForseenProblems_whenSortedByRegex_checkSortingCorrect() { List testStrings = Arrays.asList("a1", "b3", "c4", "d2.2", "d2.f4", "d2.3.3d"); @@ -53,7 +55,7 @@ public class NaturalOrderComparatorsUnitTest { } @Test - public void givenComplexStringsContainingSeparatedNumbers_whenSortedByRegex_checkNumbersCondensedAndSorted() { + void givenComplexStringsContainingSeparatedNumbers_whenSortedByRegex_checkNumbersCondensedAndSorted() { List testStrings = Arrays.asList("a1b2c5", "b3ght3.2", "something65.thensomething5"); //125, 33.2, 65.5 @@ -66,7 +68,7 @@ public class NaturalOrderComparatorsUnitTest { } @Test - public void givenStringsNotContainingNumbers_whenSortedByRegex_checkOrderNotChanged() { + void givenStringsNotContainingNumbers_whenSortedByRegex_checkOrderNotChanged() { List testStrings = Arrays.asList("a", "c", "d", "e"); List expected = new ArrayList<>(testStrings); diff --git a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/gravitysort/GravitySortUnitTest.java b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/gravitysort/GravitySortUnitTest.java index 89fc1ed687..c1ef611ab6 100644 --- a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/gravitysort/GravitySortUnitTest.java +++ b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/gravitysort/GravitySortUnitTest.java @@ -1,15 +1,16 @@ package com.baeldung.algorithms.gravitysort; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class GravitySortUnitTest { +import org.junit.jupiter.api.Test; + +class GravitySortUnitTest { @Test - public void givenIntegerArray_whenSortedWithGravitySort_thenGetSortedArray() { + void givenIntegerArray_whenSortedWithGravitySort_thenGetSortedArray() { int[] actual = { 9, 9, 100, 3, 57, 12, 3, 78, 0, 2, 2, 40, 21, 9 }; int[] expected = { 0, 2, 2, 3, 3, 9, 9, 9, 12, 21, 40, 57, 78, 100 }; GravitySort.sort(actual); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/inoutsort/InOutSortUnitTest.java b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/inoutsort/InOutSortUnitTest.java index 321b905f68..2d87dfaf1e 100644 --- a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/inoutsort/InOutSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/inoutsort/InOutSortUnitTest.java @@ -1,23 +1,22 @@ package com.baeldung.algorithms.inoutsort; -import static org.junit.Assert.*; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class InOutSortUnitTest { +class InOutSortUnitTest { @Test - public void givenArray_whenInPlaceSort_thenReversed() { + void givenArray_whenInPlaceSort_thenReversed() { int[] input = {1, 2, 3, 4, 5, 6, 7}; int[] expected = {7, 6, 5, 4, 3, 2, 1}; - assertArrayEquals("the two arrays are not equal", expected, InOutSort.reverseInPlace(input)); + assertArrayEquals(expected, InOutSort.reverseInPlace(input), "the two arrays are not equal"); } @Test - public void givenArray_whenOutOfPlaceSort_thenReversed() { + void givenArray_whenOutOfPlaceSort_thenReversed() { int[] input = {1, 2, 3, 4, 5, 6, 7}; int[] expected = {7, 6, 5, 4, 3, 2, 1}; - assertArrayEquals("the two arrays are not equal", expected, InOutSort.reverseOutOfPlace(input)); + assertArrayEquals(expected, InOutSort.reverseOutOfPlace(input), "the two arrays are not equal"); } } diff --git a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/BentleyMcilroyPartitioningUnitTest.java b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/BentleyMcilroyPartitioningUnitTest.java index 847f7f8acb..02cb01ab71 100644 --- a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/BentleyMcilroyPartitioningUnitTest.java +++ b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/BentleyMcilroyPartitioningUnitTest.java @@ -1,16 +1,17 @@ package com.baeldung.algorithms.quicksort; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class BentleyMcilroyPartitioningUnitTest { +import org.junit.jupiter.api.Test; + +class BentleyMcilroyPartitioningUnitTest { @Test - public void given_IntegerArray_whenSortedWithBentleyMcilroyPartitioning_thenGetSortedArray() { + void given_IntegerArray_whenSortedWithBentleyMcilroyPartitioning_thenGetSortedArray() { int[] actual = {3, 2, 2, 2, 3, 7, 7, 3, 2, 2, 7, 3, 3}; int[] expected = {2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 7, 7, 7}; BentleyMcIlroyPartioning.quicksort(actual, 0, actual.length - 1); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/DNFThreeWayQuickSortUnitTest.java b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/DNFThreeWayQuickSortUnitTest.java index a8e27253cc..f8eec55e8f 100644 --- a/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/DNFThreeWayQuickSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting-2/src/test/java/com/baeldung/algorithms/quicksort/DNFThreeWayQuickSortUnitTest.java @@ -1,15 +1,16 @@ package com.baeldung.algorithms.quicksort; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class DNFThreeWayQuickSortUnitTest { +import org.junit.jupiter.api.Test; + +class DNFThreeWayQuickSortUnitTest { @Test - public void givenIntegerArray_whenSortedWithThreeWayQuickSort_thenGetSortedArray() { + void givenIntegerArray_whenSortedWithThreeWayQuickSort_thenGetSortedArray() { int[] actual = {3, 5, 5, 5, 3, 7, 7, 3, 5, 5, 7, 3, 3}; int[] expected = {3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 7, 7, 7}; DutchNationalFlagPartioning.quicksort(actual, 0, actual.length - 1); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bubblesort/BubbleSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bubblesort/BubbleSortUnitTest.java index 210ee2378a..edbd352020 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bubblesort/BubbleSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bubblesort/BubbleSortUnitTest.java @@ -4,10 +4,10 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import org.junit.jupiter.api.Test; -public class BubbleSortUnitTest { +class BubbleSortUnitTest { @Test - public void givenIntegerArray_whenSortedWithBubbleSort_thenGetSortedArray() { + void givenIntegerArray_whenSortedWithBubbleSort_thenGetSortedArray() { Integer[] array = { 2, 1, 4, 6, 3, 5 }; Integer[] sortedArray = { 1, 2, 3, 4, 5, 6 }; BubbleSort bubbleSort = new BubbleSort(); @@ -16,7 +16,7 @@ public class BubbleSortUnitTest { } @Test - public void givenIntegerArray_whenSortedWithOptimizedBubbleSort_thenGetSortedArray() { + void givenIntegerArray_whenSortedWithOptimizedBubbleSort_thenGetSortedArray() { Integer[] array = { 2, 1, 4, 6, 3, 5 }; Integer[] sortedArray = { 1, 2, 3, 4, 5, 6 }; BubbleSort bubbleSort = new BubbleSort(); diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java index 4671819673..3916834c83 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java @@ -1,24 +1,26 @@ package com.baeldung.algorithms.bucketsort; -import static org.junit.Assert.assertEquals; + + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class IntegerBucketSorterUnitTest { +class IntegerBucketSorterUnitTest { private IntegerBucketSorter sorter; - @Before + @BeforeEach public void setUp() throws Exception { sorter = new IntegerBucketSorter(); } @Test - public void givenUnsortedList_whenSortedUsingBucketSorter_checkSortingCorrect() { + void givenUnsortedList_whenSortedUsingBucketSorter_checkSortingCorrect() { List unsorted = Arrays.asList(80,50,60,30,20,10,70,0,40,500,600,602,200,15); List expected = Arrays.asList(0,10,15,20,30,40,50,60,70,80,200,500,600,602); @@ -26,7 +28,5 @@ public class IntegerBucketSorterUnitTest { List actual = sorter.sort(unsorted); assertEquals(expected, actual); - - } } \ No newline at end of file diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java index 96e4936eaf..b4240f0287 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/heapsort/HeapUnitTest.java @@ -1,16 +1,16 @@ package com.baeldung.algorithms.heapsort; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import java.util.Arrays; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class HeapUnitTest { +class HeapUnitTest { @Test - public void givenNotEmptyHeap_whenPopCalled_thenItShouldReturnSmallestElement() { + void givenNotEmptyHeap_whenPopCalled_thenItShouldReturnSmallestElement() { // given Heap heap = Heap.of(3, 5, 1, 4, 2); @@ -22,7 +22,7 @@ public class HeapUnitTest { } @Test - public void givenNotEmptyIterable_whenSortCalled_thenItShouldReturnElementsInSortedList() { + void givenNotEmptyIterable_whenSortCalled_thenItShouldReturnElementsInSortedList() { // given List elements = Arrays.asList(3, 5, 1, 4, 2); diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java index b3d7e8c534..5845df45ae 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/insertionsort/InsertionSortUnitTest.java @@ -1,25 +1,25 @@ package com.baeldung.algorithms.insertionsort; -import com.baeldung.algorithms.insertionsort.InsertionSort; -import org.junit.Test; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class InsertionSortUnitTest { +import org.junit.jupiter.api.Test; + +class InsertionSortUnitTest { @Test - public void givenUnsortedArray_whenInsertionSortImperative_thenSortedAsc() { + void givenUnsortedArray_whenInsertionSortImperative_thenSortedAsc() { int[] input = {6, 2, 3, 4, 5, 1}; InsertionSort.insertionSortImperative(input); int[] expected = {1, 2, 3, 4, 5, 6}; - assertArrayEquals("the two arrays are not equal", expected, input); + assertArrayEquals(expected, input, "the two arrays are not equal"); } @Test - public void givenUnsortedArray_whenInsertionSortRecursive_thenSortedAsc() { + void givenUnsortedArray_whenInsertionSortRecursive_thenSortedAsc() { int[] input = {6, 4, 5, 2, 3, 1}; InsertionSort.insertionSortRecursive(input); int[] expected = {1, 2, 3, 4, 5, 6}; - assertArrayEquals("the two arrays are not equal", expected, input); + assertArrayEquals( expected, input, "the two arrays are not equal"); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/mergesort/MergeSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/mergesort/MergeSortUnitTest.java index 5cd14b7bd0..cc663458bd 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/mergesort/MergeSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/mergesort/MergeSortUnitTest.java @@ -1,17 +1,17 @@ package com.baeldung.algorithms.mergesort; -import org.junit.Assert; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class MergeSortUnitTest { +class MergeSortUnitTest { @Test - public void positiveTest() { + void positiveTest() { int[] actual = { 5, 1, 6, 2, 3, 4 }; int[] expected = { 1, 2, 3, 4, 5, 6 }; MergeSort.mergeSort(actual, actual.length); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/QuickSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/QuickSortUnitTest.java index c9af5b4bf8..c4e53cc50b 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/QuickSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/QuickSortUnitTest.java @@ -1,17 +1,17 @@ package com.baeldung.algorithms.quicksort; -import com.baeldung.algorithms.quicksort.QuickSort; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class QuickSortUnitTest { +import org.junit.jupiter.api.Test; + +class QuickSortUnitTest { @Test - public void givenIntegerArray_whenSortedWithQuickSort_thenGetSortedArray() { + void givenIntegerArray_whenSortedWithQuickSort_thenGetSortedArray() { int[] actual = { 9, 5, 1, 0, 6, 2, 3, 4, 7, 8 }; int[] expected = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; QuickSort.quickSort(actual, 0, actual.length-1); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/ThreeWayQuickSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/ThreeWayQuickSortUnitTest.java index cd8c7c1241..bb0b5c6bd3 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/ThreeWayQuickSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/quicksort/ThreeWayQuickSortUnitTest.java @@ -1,15 +1,16 @@ package com.baeldung.algorithms.quicksort; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class ThreeWayQuickSortUnitTest { +import org.junit.jupiter.api.Test; + +class ThreeWayQuickSortUnitTest { @Test public void givenIntegerArray_whenSortedWithThreeWayQuickSort_thenGetSortedArray() { int[] actual = { 3, 5, 5, 5, 3, 7, 7, 3, 5, 5, 7, 3, 3 }; int[] expected = { 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 7, 7, 7 }; ThreeWayQuickSort.threeWayQuickSort(actual, 0, actual.length-1); - Assert.assertArrayEquals(expected, actual); + assertArrayEquals(expected, actual); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/radixsort/RadixSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/radixsort/RadixSortUnitTest.java index 0f6c751ade..66225344cd 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/radixsort/RadixSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/radixsort/RadixSortUnitTest.java @@ -1,13 +1,13 @@ package com.baeldung.algorithms.radixsort; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class RadixSortUnitTest { +class RadixSortUnitTest { @Test - public void givenUnsortedArray_whenRadixSort_thenArraySorted() { + void givenUnsortedArray_whenRadixSort_thenArraySorted() { int[] numbers = { 387, 468, 134, 123, 68, 221, 769, 37, 7 }; RadixSort.sort(numbers); int[] numbersSorted = { 7, 37, 68, 123, 134, 221, 387, 468, 769 }; diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/selectionsort/SelectionSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/selectionsort/SelectionSortUnitTest.java index 85efd1d3da..3cbc88e128 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/selectionsort/SelectionSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/selectionsort/SelectionSortUnitTest.java @@ -1,25 +1,24 @@ package com.baeldung.algorithms.selectionsort; -import static org.junit.Assert.*; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class SelectionSortUnitTest { +class SelectionSortUnitTest { @Test - public void givenUnsortedArray_whenSelectionSort_SortAscending_thenSortedAsc() { + void givenUnsortedArray_whenSelectionSort_SortAscending_thenSortedAsc() { int[] input = { 5, 4, 1, 6, 2 }; SelectionSort.sortAscending(input); int[] expected = {1, 2, 4, 5, 6}; - assertArrayEquals("the two arrays are not equal", expected, input); + assertArrayEquals(expected, input, "the two arrays are not equal"); } @Test - public void givenUnsortedArray_whenSelectionSort_SortDescending_thenSortedDesc() { + void givenUnsortedArray_whenSelectionSort_SortDescending_thenSortedDesc() { int[] input = { 5, 4, 1, 6, 2 }; SelectionSort.sortDescending(input); int[] expected = {6, 5, 4, 2, 1}; - assertArrayEquals("the two arrays are not equal", expected, input); + assertArrayEquals(expected, input, "the two arrays are not equal"); } } diff --git a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/shellsort/ShellSortUnitTest.java b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/shellsort/ShellSortUnitTest.java index 91a27c41d0..38a861c2c0 100644 --- a/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/shellsort/ShellSortUnitTest.java +++ b/algorithms-modules/algorithms-sorting/src/test/java/com/baeldung/algorithms/shellsort/ShellSortUnitTest.java @@ -1,17 +1,17 @@ package com.baeldung.algorithms.shellsort; -import static org.junit.Assert.*; -import static org.junit.Assert.assertArrayEquals; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; -public class ShellSortUnitTest { +import org.junit.jupiter.api.Test; + +class ShellSortUnitTest { @Test - public void givenUnsortedArray_whenShellSort_thenSortedAsc() { + void givenUnsortedArray_whenShellSort_thenSortedAsc() { int[] input = {41, 15, 82, 5, 65, 19, 32, 43, 8}; ShellSort.sort(input); int[] expected = {5, 8, 15, 19, 32, 41, 43, 65, 82}; - assertArrayEquals("the two arrays are not equal", expected, input); + assertArrayEquals( expected, input, "the two arrays are not equal"); } } diff --git a/annotations/annotation-processing/pom.xml b/annotations/annotation-processing/pom.xml index 14bbc409e5..2a17242ee5 100644 --- a/annotations/annotation-processing/pom.xml +++ b/annotations/annotation-processing/pom.xml @@ -21,6 +21,7 @@ + 1.0-rc2 diff --git a/apache-cxf-modules/cxf-aegis/pom.xml b/apache-cxf-modules/cxf-aegis/pom.xml index d013aabc65..6b9e026cdd 100644 --- a/apache-cxf-modules/cxf-aegis/pom.xml +++ b/apache-cxf-modules/cxf-aegis/pom.xml @@ -20,4 +20,8 @@ + + 4.0.0 + + \ No newline at end of file diff --git a/apache-cxf-modules/cxf-aegis/src/test/java/com/baeldung/cxf/aegis/BaeldungIntegrationTest.java b/apache-cxf-modules/cxf-aegis/src/test/java/com/baeldung/cxf/aegis/BaeldungIntegrationTest.java index b28b987cfa..9c89d769e0 100644 --- a/apache-cxf-modules/cxf-aegis/src/test/java/com/baeldung/cxf/aegis/BaeldungIntegrationTest.java +++ b/apache-cxf-modules/cxf-aegis/src/test/java/com/baeldung/cxf/aegis/BaeldungIntegrationTest.java @@ -80,16 +80,20 @@ public class BaeldungIntegrationTest { private void marshalCourseRepo(CourseRepo courseRepo) throws Exception { AegisWriter writer = context.createXMLStreamWriter(); AegisType aegisType = context.getTypeMapping().getType(CourseRepo.class); - XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileOutputStream(fileName)); + final FileOutputStream stream = new FileOutputStream(fileName); + XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(stream); writer.write(courseRepo, new QName("http://aegis.cxf.baeldung.com", "baeldung"), false, xmlWriter, aegisType); xmlWriter.close(); + stream.close(); } private CourseRepo unmarshalCourseRepo() throws Exception { AegisReader reader = context.createXMLStreamReader(); - XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(fileName)); + final FileInputStream stream = new FileInputStream(fileName); + XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(stream); CourseRepo courseRepo = (CourseRepo) reader.read(xmlReader, context.getTypeMapping().getType(CourseRepo.class)); xmlReader.close(); + stream.close(); return courseRepo; } @@ -97,7 +101,7 @@ public class BaeldungIntegrationTest { public void cleanup(){ File testFile = new File(fileName); if (testFile.exists()) { - testFile.delete(); + testFile.deleteOnExit(); } } } \ No newline at end of file diff --git a/apache-cxf-modules/cxf-introduction/pom.xml b/apache-cxf-modules/cxf-introduction/pom.xml index fe7b917c6f..fdcd100cc5 100644 --- a/apache-cxf-modules/cxf-introduction/pom.xml +++ b/apache-cxf-modules/cxf-introduction/pom.xml @@ -23,6 +23,16 @@ cxf-rt-transports-http-jetty ${cxf.version} + + jakarta.xml.ws + jakarta.xml.ws-api + ${jakarta-xml.version} + + + jakarta.jws + jakarta.jws-api + ${jakarta.jws.version} + @@ -37,4 +47,10 @@ + + 4.0.0 + 4.0.0 + 3.0.0 + + \ No newline at end of file diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Baeldung.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Baeldung.java index 472d38b8e1..cd482af0db 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Baeldung.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Baeldung.java @@ -2,8 +2,8 @@ package com.baeldung.cxf.introduction; import java.util.Map; -import javax.jws.WebService; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import jakarta.jws.WebService; +import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @WebService public interface Baeldung { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/BaeldungImpl.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/BaeldungImpl.java index 240f6bb1da..04a6243cc2 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/BaeldungImpl.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/BaeldungImpl.java @@ -3,7 +3,7 @@ package com.baeldung.cxf.introduction; import java.util.LinkedHashMap; import java.util.Map; -import javax.jws.WebService; +import jakarta.jws.WebService; @WebService(endpointInterface = "com.baeldung.cxf.introduction.Baeldung") public class BaeldungImpl implements Baeldung { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Server.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Server.java index 2ac649f4c5..f00a64a055 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Server.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Server.java @@ -1,6 +1,6 @@ package com.baeldung.cxf.introduction; -import javax.xml.ws.Endpoint; +import jakarta.xml.ws.Endpoint; public class Server { public static void main(String args[]) throws InterruptedException { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Student.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Student.java index cad8f94d97..0605956bbc 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Student.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/Student.java @@ -1,6 +1,6 @@ package com.baeldung.cxf.introduction; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlJavaTypeAdapter(StudentAdapter.class) public interface Student { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentAdapter.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentAdapter.java index 29b829d808..7885c953a5 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentAdapter.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentAdapter.java @@ -1,6 +1,6 @@ package com.baeldung.cxf.introduction; -import javax.xml.bind.annotation.adapters.XmlAdapter; +import jakarta.xml.bind.annotation.adapters.XmlAdapter; public class StudentAdapter extends XmlAdapter { public StudentImpl marshal(Student student) throws Exception { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentImpl.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentImpl.java index bc9dd27afe..041418befb 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentImpl.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentImpl.java @@ -1,6 +1,6 @@ package com.baeldung.cxf.introduction; -import javax.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.XmlType; @XmlType(name = "Student") public class StudentImpl implements Student { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMap.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMap.java index 4c40886c42..aa17b0cf4f 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMap.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMap.java @@ -3,8 +3,8 @@ package com.baeldung.cxf.introduction; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlType; @XmlType(name = "StudentMap") public class StudentMap { diff --git a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMapAdapter.java b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMapAdapter.java index f156676a5f..3bf1bfd2ff 100644 --- a/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMapAdapter.java +++ b/apache-cxf-modules/cxf-introduction/src/main/java/com/baeldung/cxf/introduction/StudentMapAdapter.java @@ -3,7 +3,7 @@ package com.baeldung.cxf.introduction; import java.util.LinkedHashMap; import java.util.Map; -import javax.xml.bind.annotation.adapters.XmlAdapter; +import jakarta.xml.bind.annotation.adapters.XmlAdapter; public class StudentMapAdapter extends XmlAdapter> { public StudentMap marshal(Map boundMap) throws Exception { diff --git a/apache-cxf-modules/cxf-introduction/src/test/java/com/baeldung/cxf/introduction/StudentLiveTest.java b/apache-cxf-modules/cxf-introduction/src/test/java/com/baeldung/cxf/introduction/StudentLiveTest.java index 60fc0a10e7..89b127a742 100644 --- a/apache-cxf-modules/cxf-introduction/src/test/java/com/baeldung/cxf/introduction/StudentLiveTest.java +++ b/apache-cxf-modules/cxf-introduction/src/test/java/com/baeldung/cxf/introduction/StudentLiveTest.java @@ -5,8 +5,8 @@ import static org.junit.Assert.assertEquals; import java.util.Map; import javax.xml.namespace.QName; -import javax.xml.ws.Service; -import javax.xml.ws.soap.SOAPBinding; +import jakarta.xml.ws.Service; +import jakarta.xml.ws.soap.SOAPBinding; import org.junit.Before; import org.junit.Test; diff --git a/apache-cxf-modules/cxf-jaxrs-implementation/pom.xml b/apache-cxf-modules/cxf-jaxrs-implementation/pom.xml index cc5eba4025..8418853b1e 100644 --- a/apache-cxf-modules/cxf-jaxrs-implementation/pom.xml +++ b/apache-cxf-modules/cxf-jaxrs-implementation/pom.xml @@ -16,12 +16,28 @@ org.apache.cxf cxf-rt-frontend-jaxrs - ${cxf.version} + 4.0.0 org.apache.cxf cxf-rt-transports-http-jetty - ${cxf.version} + 4.0.0 + + + jakarta.xml.ws + jakarta.xml.ws-api + ${jakarta-xml.version} + + + jakarta.jws + jakarta.jws-api + ${jakarta-jws.version} + + + jakarta.platform + jakarta.jakartaee-web-api + ${jakarta-platform.version} + compile org.apache.httpcomponents @@ -50,6 +66,9 @@ 4.5.2 + 4.0.0 + 3.0.0 + 9.0.0 \ No newline at end of file diff --git a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Course.java b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Course.java index dba9b9c661..9f2ba2e837 100644 --- a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Course.java +++ b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Course.java @@ -1,8 +1,8 @@ package com.baeldung.cxf.jaxrs.implementation; -import javax.ws.rs.*; -import javax.ws.rs.core.Response; -import javax.xml.bind.annotation.XmlRootElement; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; +import jakarta.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; import java.util.List; diff --git a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/CourseRepository.java b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/CourseRepository.java index a2fd6be435..e527180440 100644 --- a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/CourseRepository.java +++ b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/CourseRepository.java @@ -1,7 +1,7 @@ package com.baeldung.cxf.jaxrs.implementation; -import javax.ws.rs.*; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; import java.util.ArrayList; import java.util.HashMap; import java.util.List; diff --git a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Student.java b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Student.java index bd3dad0f5e..f6c4e32cdd 100644 --- a/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Student.java +++ b/apache-cxf-modules/cxf-jaxrs-implementation/src/main/java/com/baeldung/cxf/jaxrs/implementation/Student.java @@ -1,6 +1,6 @@ package com.baeldung.cxf.jaxrs.implementation; -import javax.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "Student") public class Student { diff --git a/apache-cxf-modules/cxf-jaxrs-implementation/src/test/java/com/baeldung/cxf/jaxrs/implementation/ServiceLiveTest.java b/apache-cxf-modules/cxf-jaxrs-implementation/src/test/java/com/baeldung/cxf/jaxrs/implementation/ServiceLiveTest.java index 29c34ae16b..a9f71930f2 100644 --- a/apache-cxf-modules/cxf-jaxrs-implementation/src/test/java/com/baeldung/cxf/jaxrs/implementation/ServiceLiveTest.java +++ b/apache-cxf-modules/cxf-jaxrs-implementation/src/test/java/com/baeldung/cxf/jaxrs/implementation/ServiceLiveTest.java @@ -7,7 +7,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; -import javax.xml.bind.JAXB; +import jakarta.xml.bind.JAXB; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpDelete; diff --git a/apache-cxf-modules/cxf-spring/pom.xml b/apache-cxf-modules/cxf-spring/pom.xml index ebbebd7f3b..1c87ae4bfb 100644 --- a/apache-cxf-modules/cxf-spring/pom.xml +++ b/apache-cxf-modules/cxf-spring/pom.xml @@ -40,10 +40,22 @@ spring-webmvc ${spring.version} + + com.sun.xml.ws + jaxws-ri + 2.3.3 + pom + javax.servlet javax.servlet-api - ${javax.servlet-api.version} + 4.0.1 + provided + + + javax.servlet + jstl + 1.2 @@ -103,8 +115,9 @@ - 4.3.4.RELEASE + 5.3.25 1.6.1 + 3.3.2 \ No newline at end of file diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/pom.xml b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/pom.xml index 26c8a87c2b..ce2b0059c3 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/pom.xml +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/pom.xml @@ -23,6 +23,11 @@ cxf-rt-rs-sse ${cxf-version} + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta-ws.version} + @@ -55,7 +60,8 @@ - 3.2.0 + 4.0.0 + 3.1.0 \ No newline at end of file diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientApp.java b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientApp.java index 5d42b3a243..af9a9c7691 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientApp.java +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientApp.java @@ -1,10 +1,10 @@ package com.baeldung.sse.jaxrs.client; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.sse.InboundSseEvent; -import javax.ws.rs.sse.SseEventSource; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.sse.InboundSseEvent; +import jakarta.ws.rs.sse.SseEventSource; import java.util.function.Consumer; public class SseClientApp { diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientBroadcastApp.java b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientBroadcastApp.java index 9afc187a6d..4e3c236437 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientBroadcastApp.java +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-client/src/main/java/com/baeldung/sse/jaxrs/client/SseClientBroadcastApp.java @@ -1,10 +1,10 @@ package com.baeldung.sse.jaxrs.client; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.sse.InboundSseEvent; -import javax.ws.rs.sse.SseEventSource; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.sse.InboundSseEvent; +import jakarta.ws.rs.sse.SseEventSource; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/pom.xml b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/pom.xml index 0467fd9e5d..3bd3e5cb27 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/pom.xml +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/pom.xml @@ -15,16 +15,14 @@ - javax.ws.rs - javax.ws.rs-api - ${rs-api.version} - provided + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta-ws.version} - javax.enterprise - cdi-api - ${cdi-api.version} - provided + jakarta.enterprise + jakarta.enterprise.cdi-api + ${jakarta-cdi-api} javax.json.bind @@ -37,6 +35,11 @@ ${project.artifactId} + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + net.wasdev.wlp.maven.plugins liberty-maven-plugin @@ -78,9 +81,10 @@ 2.4.2 false 18.0.0.2 - 2.1 - 2.0 + 3.1.0 + 4.0.1 1.0 + 3.3.2 \ No newline at end of file diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/AppConfig.java b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/AppConfig.java index 058d19f045..fdd1af632c 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/AppConfig.java +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/AppConfig.java @@ -1,7 +1,7 @@ package com.baeldung.sse.jaxrs; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; @ApplicationPath("sse") public class AppConfig extends Application { diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/SseResource.java b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/SseResource.java index 1f60168a1b..3e211f109b 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/SseResource.java +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/SseResource.java @@ -1,15 +1,15 @@ package com.baeldung.sse.jaxrs; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.sse.OutboundSseEvent; -import javax.ws.rs.sse.Sse; -import javax.ws.rs.sse.SseBroadcaster; -import javax.ws.rs.sse.SseEventSink; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.sse.OutboundSseEvent; +import jakarta.ws.rs.sse.Sse; +import jakarta.ws.rs.sse.SseBroadcaster; +import jakarta.ws.rs.sse.SseEventSink; @ApplicationScoped @Path("stock") diff --git a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/StockService.java b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/StockService.java index 15818ead5d..721ef35678 100644 --- a/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/StockService.java +++ b/apache-cxf-modules/sse-jaxrs/sse-jaxrs-server/src/main/java/com/baeldung/sse/jaxrs/StockService.java @@ -1,11 +1,11 @@ package com.baeldung.sse.jaxrs; -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.context.Initialized; -import javax.enterprise.event.Event; -import javax.enterprise.event.Observes; -import javax.inject.Inject; -import javax.inject.Named; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Initialized; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Named; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; diff --git a/apache-httpclient-2/pom.xml b/apache-httpclient-2/pom.xml index c5b8195472..91c4c718c0 100644 --- a/apache-httpclient-2/pom.xml +++ b/apache-httpclient-2/pom.xml @@ -98,7 +98,7 @@ 3.22.0 5.11.2 4.5.8 - 5.1.3 + 5.2 11 11 2.1.7.RELEASE 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 404acb3098..265fa39816 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 @@ -1,46 +1,50 @@ package com.baeldung.httpclient.cookies; -import org.apache.http.client.CookieStore; -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.cookie.ClientCookie; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.cookie.BasicClientCookie; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.Cookie; +import org.apache.hc.client5.http.cookie.CookieStore; + +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; +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.cookie.BasicClientCookie; +import org.apache.hc.client5.http.protocol.HttpClientContext; + import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import static org.junit.Assert.assertEquals; - - -public class HttpClientGettingCookieValueUnitTest { +class HttpClientGettingCookieValueUnitTest { private static Logger log = LoggerFactory.getLogger(HttpClientGettingCookieValueUnitTest.class); private static final String SAMPLE_URL = "http://www.baeldung.com/"; @Test - public final void whenSettingCustomCookieOnTheRequest_thenGettingTheSameCookieFromTheResponse() throws IOException { + void whenSettingCustomCookieOnTheRequest_thenGettingTheSameCookieFromTheResponse() throws IOException { + HttpClientContext context = HttpClientContext.create(); context.setAttribute(HttpClientContext.COOKIE_STORE, createCustomCookieStore()); - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - try (CloseableHttpResponse response = httpClient.execute(new HttpGet(SAMPLE_URL), context)) { - CookieStore cookieStore = context.getCookieStore(); - Cookie customCookie = cookieStore.getCookies() - .stream() - .peek(cookie -> log.info("cookie name:{}", cookie.getName())) - .filter(cookie -> "custom_cookie".equals(cookie.getName())) - .findFirst() - .orElseThrow(IllegalStateException::new); + final HttpGet request = new HttpGet(SAMPLE_URL); - assertEquals("test_value", customCookie.getValue()); - } + try (CloseableHttpClient client = HttpClientBuilder.create() + .build()) { + client.execute(request, context, new BasicHttpClientResponseHandler()); + CookieStore cookieStore = context.getCookieStore(); + Cookie customCookie = cookieStore.getCookies() + .stream() + .peek(cookie -> log.info("cookie name:{}", cookie.getName())) + .filter(cookie -> "custom_cookie".equals(cookie.getName())) + .findFirst() + .orElseThrow(IllegalStateException::new); + + assertEquals("test_value", customCookie.getValue()); } } @@ -48,7 +52,7 @@ public class HttpClientGettingCookieValueUnitTest { BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("custom_cookie", "test_value"); cookie.setDomain("baeldung.com"); - cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "true"); + cookie.setAttribute("domain", "true"); 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 35b21789ef..9a79cbf491 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 @@ -1,29 +1,27 @@ package com.baeldung.httpclient.readresponsebodystring; import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; 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.core5.http.HttpEntity; -import org.apache.hc.core5.http.ParseException; -import org.apache.hc.core5.http.io.entity.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 ApacheHttpClient5UnitTest { 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, ParseException { + public void whenUseApacheHttpClient_thenCorrect() throws IOException { HttpGet request = new HttpGet(DUMMY_URL); - try (CloseableHttpClient client = HttpClients.createDefault(); CloseableHttpResponse response = client.execute(request)) { - HttpEntity entity = response.getEntity(); - logger.debug("Response -> {}", EntityUtils.toString(entity)); + try (CloseableHttpClient client = HttpClients.createDefault()) { + String response = client.execute(request, new BasicHttpClientResponseHandler()); + logger.debug("Response -> {}", response); } } } \ No newline at end of file diff --git a/apache-httpclient/pom.xml b/apache-httpclient/pom.xml index 26eb319ac0..c371d1fc06 100644 --- a/apache-httpclient/pom.xml +++ b/apache-httpclient/pom.xml @@ -54,6 +54,42 @@ + + org.apache.httpcomponents.core5 + httpcore5 + ${httpcore5.version} + + + commons-logging + commons-logging + + + + + + org.apache.httpcomponents.client5 + httpclient5-fluent + ${httpclient5-fluent.version} + + + commons-logging + commons-logging + + + + + + org.apache.httpcomponents.client5 + httpclient5 + ${httpclient5.version} + + + commons-logging + commons-logging + + + + com.github.tomakehurst wiremock @@ -78,6 +114,10 @@ 2.5.1 4.5.8 + + 5.2 + 5.2 + 5.2 - \ No newline at end of file + 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 7576e49034..720049378b 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java @@ -1,19 +1,24 @@ package com.baeldung.httpclient; -import org.apache.http.HttpEntity; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.entity.mime.content.FileBody; -import org.apache.http.entity.mime.content.StringBody; -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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertTrue; + +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; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.entity.mime.StringBody; +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.HttpClientBuilder; + +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpStatus; import java.io.BufferedReader; import java.io.File; @@ -22,14 +27,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import com.baeldung.httpclient.handler.CustomHttpClientResponseHandler; -public class HttpClientMultipartLiveTest { +class HttpClientMultipartLiveTest { // No longer available // private static final String SERVER = "http://echo.200please.com"; @@ -38,41 +39,16 @@ public class HttpClientMultipartLiveTest { private static final String TEXTFILENAME = "temp.txt"; private static final String IMAGEFILENAME = "image.jpg"; private static final String ZIPFILENAME = "zipFile.zip"; - private static final Logger LOGGER = Logger.getLogger("com.baeldung.httpclient.HttpClientMultipartLiveTest"); - private CloseableHttpClient client; private HttpPost post; private BufferedReader rd; - private CloseableHttpResponse response; - @Before - public final void before() { - client = HttpClientBuilder.create() - .build(); + @BeforeEach + public void before() { post = new HttpPost(SERVER); } - @After - public final void after() throws IllegalStateException, IOException { - post.completed(); - try { - client.close(); - } catch (final IOException e1) { - LOGGER.log(Level.SEVERE, e1.getMessage(), e1); - throw e1; - } - try { - rd.close(); - } catch (final IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw e; - } - ResponseUtil.closeResponse(response); - } - - // tests - @Test - public final void givenFileandMultipleTextParts_whenUploadwithAddPart_thenNoExceptions() throws IOException { + void givenFileandMultipleTextParts_whenUploadwithAddPart_thenNoExceptions() throws IOException { final URL url = Thread.currentThread() .getContextClassLoader() .getResource("uploads/" + TEXTFILENAME); @@ -83,53 +59,61 @@ public class HttpClientMultipartLiveTest { final StringBody stringBody2 = new StringBody("This is message 2", ContentType.MULTIPART_FORM_DATA); // final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + builder.setMode(HttpMultipartMode.LEGACY); builder.addPart("file", fileBody); builder.addPart("text1", stringBody1); builder.addPart("text2", stringBody2); final HttpEntity entity = builder.build(); - // - post.setEntity(entity); - response = client.execute(post); - final int statusCode = response.getStatusLine() - .getStatusCode(); - final String responseString = getContent(); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - // assertTrue(responseString.contains("Content-Type: multipart/form-data;")); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + post.setEntity(entity); + try(CloseableHttpClient client = HttpClientBuilder.create() + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(post, new CustomHttpClientResponseHandler())){ + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + } } @Test - public final void givenFileandTextPart_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoExeption() throws IOException { + void givenFileandTextPart_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoExeption() throws IOException { final URL url = Thread.currentThread() .getContextClassLoader() .getResource("uploads/" + TEXTFILENAME); final File file = new File(url.getPath()); final String message = "This is a multipart post"; final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + builder.setMode(HttpMultipartMode.LEGACY); builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, TEXTFILENAME); builder.addTextBody("text", message, ContentType.DEFAULT_BINARY); final HttpEntity entity = builder.build(); post.setEntity(entity); - response = client.execute(post); - final int statusCode = response.getStatusLine() - .getStatusCode(); - final String responseString = getContent(); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - // assertTrue(responseString.contains("Content-Type: multipart/form-data;")); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + + try(CloseableHttpClient client = HttpClientBuilder.create() + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(post, new CustomHttpClientResponseHandler())){ + + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + } } @Test - public final void givenFileAndInputStreamandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { + void givenFileAndInputStreamandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { final URL url = Thread.currentThread() .getContextClassLoader() .getResource("uploads/" + ZIPFILENAME); @@ -140,64 +124,75 @@ public class HttpClientMultipartLiveTest { final File file = new File(url2.getPath()); final String message = "This is a multipart post"; final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + builder.setMode(HttpMultipartMode.LEGACY); builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, IMAGEFILENAME); builder.addBinaryBody("upstream", inputStream, ContentType.create("application/zip"), ZIPFILENAME); builder.addTextBody("text", message, ContentType.TEXT_PLAIN); final HttpEntity entity = builder.build(); post.setEntity(entity); - response = client.execute(post); - final int statusCode = response.getStatusLine() - .getStatusCode(); - final String responseString = getContent(); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - // assertTrue(responseString.contains("Content-Type: multipart/form-data;")); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); - inputStream.close(); + + try(CloseableHttpClient client = HttpClientBuilder.create() + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(post, new CustomHttpClientResponseHandler())){ + + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + inputStream.close(); + } } @Test - public final void givenCharArrayandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { + void givenCharArrayandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { final String message = "This is a multipart post"; final byte[] bytes = "binary code".getBytes(); final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + builder.setMode(HttpMultipartMode.LEGACY); builder.addBinaryBody("file", bytes, ContentType.DEFAULT_BINARY, TEXTFILENAME); builder.addTextBody("text", message, ContentType.TEXT_PLAIN); final HttpEntity entity = builder.build(); post.setEntity(entity); - response = client.execute(post); - final int statusCode = response.getStatusLine() - .getStatusCode(); - final String responseString = getContent(); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - // assertTrue(responseString.contains("Content-Type: multipart/form-data;")); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + + try(CloseableHttpClient client = HttpClientBuilder.create() + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(post, new CustomHttpClientResponseHandler())){ + + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + } + } // UTIL - private String getContent() throws IOException { - rd = new BufferedReader(new InputStreamReader(response.getEntity() - .getContent())); + private String getContent(HttpEntity httpEntity) throws IOException { + rd = new BufferedReader(new InputStreamReader(httpEntity.getContent())); String body = ""; StringBuilder content = new StringBuilder(); while ((body = rd.readLine()) != null) { - content.append(body).append("\n"); + content.append(body) + .append("\n"); } - return content.toString().trim(); + return content.toString() + .trim(); } - private String getContentTypeHeader() throws IOException { + private String getContentTypeHeader() { return post.getEntity() - .getContentType() - .toString(); + .getContentType(); } } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java new file mode 100644 index 0000000000..0559854b35 --- /dev/null +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java @@ -0,0 +1,11 @@ +package com.baeldung.httpclient.handler; + +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; + +public class CustomHttpClientResponseHandler implements HttpClientResponseHandler { + @Override + public ClassicHttpResponse handleResponse(ClassicHttpResponse response) { + return response; + } +} \ No newline at end of file diff --git a/apache-httpclient4/.gitignore b/apache-httpclient4/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/apache-httpclient4/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/apache-httpclient4/README.md b/apache-httpclient4/README.md new file mode 100644 index 0000000000..25791d05e6 --- /dev/null +++ b/apache-httpclient4/README.md @@ -0,0 +1,14 @@ +## Apache HttpClient 4 + +This module contains articles about Apache HttpClient 4.5 + +### Relevant Articles + +- [Apache HttpClient with SSL](https://www.baeldung.com/httpclient-ssl) +- [Apache HttpClient Timeout](https://www.baeldung.com/httpclient-timeout) +- [Custom HTTP Header with the Apache HttpClient](https://www.baeldung.com/httpclient-custom-http-header) + +### Running the Tests +To run the live tests, use the command: mvn clean install -Plive +This will start an embedded Jetty server on port 8082 using the Cargo plugin configured in the pom.xml file, +for the live Maven profile diff --git a/apache-httpclient4/pom.xml b/apache-httpclient4/pom.xml new file mode 100644 index 0000000000..6b449e3be1 --- /dev/null +++ b/apache-httpclient4/pom.xml @@ -0,0 +1,291 @@ + + + 4.0.0 + apache-httpclient4 + 0.1-SNAPSHOT + apache-httpclient4 + war + + + com.baeldung + parent-spring-5 + 0.0.1-SNAPSHOT + ../parent-spring-5 + + + + + + org.springframework.security + spring-security-web + ${spring-security.version} + + + org.springframework.security + spring-security-config + ${spring-security.version} + + + + org.springframework + spring-core + ${spring.version} + + + commons-logging + commons-logging + + + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-jdbc + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-aop + ${spring.version} + + + org.springframework + spring-tx + ${spring.version} + + + org.springframework + spring-expression + ${spring.version} + + + org.springframework + spring-web + ${spring.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + org.springframework + spring-oxm + ${spring.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + commons-logging + commons-logging + + + + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + 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} + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.apache.httpcomponents + httpasyncclient + ${httpasyncclient.version} + + + commons-logging + commons-logging + + + + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + provided + + + javax.servlet + jstl + ${jstl.version} + runtime + + + + com.google.guava + guava + ${guava.version} + + + + org.springframework + spring-test + ${spring.version} + test + + + + + httpclient-simple + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + true + + jetty8x + embedded + + + + + + + 8082 + + + + + + + + + + live + + + + org.codehaus.cargo + cargo-maven2-plugin + + + start-server + pre-integration-test + + start + + + + stop-server + post-integration-test + + stop + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + none + + + **/*LiveTest.java + + + cargo + + + + + + + + + + + + + 1.10 + 4.1.5 + + 2.5.1 + 4.4.16 + 4.5.14 + + 1.6.1 + + + \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java b/apache-httpclient4/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java new file mode 100644 index 0000000000..cafd8cfb7b --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java @@ -0,0 +1,30 @@ +package com.baeldung.basic; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +@Component +public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { + + @Override + public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException { + response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\""); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + final PrintWriter writer = response.getWriter(); + writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage()); + } + + @Override + public void afterPropertiesSet() { + setRealmName("Baeldung"); + super.afterPropertiesSet(); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java b/apache-httpclient4/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java new file mode 100644 index 0000000000..81f82a2c1c --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java @@ -0,0 +1,39 @@ +package com.baeldung.client; + +import java.net.URI; + +import org.apache.http.HttpHost; +import org.apache.http.client.AuthCache; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpComponentsClientHttpRequestFactory { + + HttpHost host; + + public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) { + super(); + this.host = host; + } + + protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { + return createHttpContext(); + } + + private HttpContext createHttpContext() { + + AuthCache authCache = new BasicAuthCache(); + + BasicScheme basicAuth = new BasicScheme(); + authCache.put(host, basicAuth); + + BasicHttpContext localcontext = new BasicHttpContext(); + localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache); + return localcontext; + } +} \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/client/RestTemplateFactory.java b/apache-httpclient4/src/main/java/com/baeldung/client/RestTemplateFactory.java new file mode 100644 index 0000000000..aac4f8cebd --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/client/RestTemplateFactory.java @@ -0,0 +1,44 @@ +package com.baeldung.client; + +import org.apache.http.HttpHost; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.support.BasicAuthenticationInterceptor; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class RestTemplateFactory implements FactoryBean, InitializingBean { + private RestTemplate restTemplate; + + public RestTemplateFactory() { + super(); + } + + // API + + @Override + public RestTemplate getObject() { + return restTemplate; + } + + @Override + public Class getObjectType() { + return RestTemplate.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public void afterPropertiesSet() { + HttpHost host = new HttpHost("localhost", 8082, "http"); + final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host); + restTemplate = new RestTemplate(requestFactory); + restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("user1", "user1Pass")); + } + +} \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/client/spring/ClientConfig.java b/apache-httpclient4/src/main/java/com/baeldung/client/spring/ClientConfig.java new file mode 100644 index 0000000000..03994b55a5 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/client/spring/ClientConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.client.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan("com.baeldung.client") +public class ClientConfig { + + public ClientConfig() { + super(); + } + + // beans + +} \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/filter/CustomFilter.java b/apache-httpclient4/src/main/java/com/baeldung/filter/CustomFilter.java new file mode 100644 index 0000000000..6bb12610fa --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/filter/CustomFilter.java @@ -0,0 +1,18 @@ +package com.baeldung.filter; + +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; + +public class CustomFilter extends GenericFilterBean { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + chain.doFilter(request, response); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java b/apache-httpclient4/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java new file mode 100644 index 0000000000..fb597e46c8 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java @@ -0,0 +1,49 @@ +package com.baeldung.filter; + +import com.baeldung.security.RestAuthenticationEntryPoint; +import org.springframework.beans.factory.annotation.Autowired; +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.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.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebSecurity +public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + + @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user1") + .password(passwordEncoder().encode("user1Pass")) + .authorities("ROLE_USER"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/securityNone") + .permitAll() + .anyRequest() + .authenticated() + .and() + .httpBasic() + .authenticationEntryPoint(authenticationEntryPoint); + + http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java b/apache-httpclient4/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java new file mode 100644 index 0000000000..7dc53e3e1e --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java @@ -0,0 +1,48 @@ +package com.baeldung.security; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.savedrequest.SavedRequest; +import org.springframework.util.StringUtils; + +public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { + + private RequestCache requestCache = new HttpSessionRequestCache(); + + @Override + public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws ServletException, IOException { + final SavedRequest savedRequest = requestCache.getRequest(request, response); + + if (savedRequest == null) { + super.onAuthenticationSuccess(request, response, authentication); + + return; + } + final String targetUrlParameter = getTargetUrlParameter(); + if (isAlwaysUseDefaultTargetUrl() || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) { + requestCache.removeRequest(request, response); + super.onAuthenticationSuccess(request, response, authentication); + + return; + } + + clearAuthenticationAttributes(request); + + // Use the DefaultSavedRequest URL + // final String targetUrl = savedRequest.getRedirectUrl(); + // logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl); + // getRedirectStrategy().sendRedirect(request, response, targetUrl); + } + + public void setRequestCache(final RequestCache requestCache) { + this.requestCache = requestCache; + } +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java b/apache-httpclient4/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java new file mode 100644 index 0000000000..1ae89adb89 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java @@ -0,0 +1,23 @@ +package com.baeldung.security; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +/** + * The Entry Point will not redirect to any sort of Login - it will return the 401 + */ +@Component +public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } + +} \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/spring/SecSecurityConfig.java b/apache-httpclient4/src/main/java/com/baeldung/spring/SecSecurityConfig.java new file mode 100644 index 0000000000..4ba9d47f8d --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/spring/SecSecurityConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; + +@Configuration +@ImportResource({ "classpath:webSecurityConfig.xml" }) +@ComponentScan("com.baeldung.security") +public class SecSecurityConfig { + + public SecSecurityConfig() { + super(); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/spring/WebConfig.java b/apache-httpclient4/src/main/java/com/baeldung/spring/WebConfig.java new file mode 100644 index 0000000000..8d5c1dc7f1 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/spring/WebConfig.java @@ -0,0 +1,30 @@ +package com.baeldung.spring; + +import java.util.List; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +@ComponentScan("com.baeldung.web") +public class WebConfig implements WebMvcConfigurer { + + public WebConfig() { + super(); + } + + // beans + + @Override + public void configureMessageConverters(final List> converters) { + converters.add(new MappingJackson2HttpMessageConverter()); + } + + // + +} \ No newline at end of file diff --git a/apache-httpclient4/src/main/java/com/baeldung/web/controller/BarController.java b/apache-httpclient4/src/main/java/com/baeldung/web/controller/BarController.java new file mode 100644 index 0000000000..02e6af03af --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/web/controller/BarController.java @@ -0,0 +1,31 @@ +package com.baeldung.web.controller; + +import com.baeldung.web.dto.Bar; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping(value = "/bars") +public class BarController { + + @Autowired + private ApplicationEventPublisher eventPublisher; + + public BarController() { + super(); + } + + // API + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ResponseBody + public Bar findOne(@PathVariable("id") final Long id) { + return new Bar(); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/web/controller/FooController.java b/apache-httpclient4/src/main/java/com/baeldung/web/controller/FooController.java new file mode 100644 index 0000000000..461a5e351a --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/web/controller/FooController.java @@ -0,0 +1,33 @@ +package com.baeldung.web.controller; + +import com.baeldung.web.dto.Foo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping(value = "/foos") +public class FooController { + + @Autowired + private ApplicationEventPublisher eventPublisher; + + public FooController() { + super(); + } + + // API + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ResponseBody + @PreAuthorize("hasRole('ROLE_USER')") + public Foo findOne(@PathVariable("id") final Long id) { + return new Foo(); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/web/dto/Bar.java b/apache-httpclient4/src/main/java/com/baeldung/web/dto/Bar.java new file mode 100644 index 0000000000..eb139b0ec1 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/web/dto/Bar.java @@ -0,0 +1,14 @@ +package com.baeldung.web.dto; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Bar implements Serializable { + + public Bar() { + super(); + } + +} diff --git a/apache-httpclient4/src/main/java/com/baeldung/web/dto/Foo.java b/apache-httpclient4/src/main/java/com/baeldung/web/dto/Foo.java new file mode 100644 index 0000000000..23cfab132d --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/web/dto/Foo.java @@ -0,0 +1,14 @@ +package com.baeldung.web.dto; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Foo implements Serializable { + + public Foo() { + super(); + } + +} diff --git a/apache-httpclient4/src/main/resources/logback.xml b/apache-httpclient4/src/main/resources/logback.xml new file mode 100644 index 0000000000..56af2d397e --- /dev/null +++ b/apache-httpclient4/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apache-httpclient4/src/main/resources/webSecurityConfig.xml b/apache-httpclient4/src/main/resources/webSecurityConfig.xml new file mode 100644 index 0000000000..2ff9a1de15 --- /dev/null +++ b/apache-httpclient4/src/main/resources/webSecurityConfig.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apache-httpclient4/src/main/webapp/WEB-INF/api-servlet.xml b/apache-httpclient4/src/main/webapp/WEB-INF/api-servlet.xml new file mode 100644 index 0000000000..1dbff70b83 --- /dev/null +++ b/apache-httpclient4/src/main/webapp/WEB-INF/api-servlet.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/apache-httpclient4/src/main/webapp/WEB-INF/web.xml b/apache-httpclient4/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..4b2dd54266 --- /dev/null +++ b/apache-httpclient4/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + Spring Security Custom Application + + + + contextClass + org.springframework.web.context.support.AnnotationConfigWebApplicationContext + + + contextConfigLocation + com.baeldung.spring + + + + org.springframework.web.context.ContextLoaderListener + + + + + api + org.springframework.web.servlet.DispatcherServlet + 1 + + + api + /api/* + + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + springSecurityFilterChain + /* + + + \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java new file mode 100644 index 0000000000..2785bc5d08 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java @@ -0,0 +1,99 @@ +package com.baeldung.client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLPeerUnverifiedException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +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.ssl.SSLContexts; + +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + + +class ClientLiveTest { + + final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; + + @Test + void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_2() throws GeneralSecurityException { + + final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + final Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); + + final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setConnectionManager(connectionManager) + .build(); + + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + } + + @Test + void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenCorrect() throws IOException { + final HttpGet getMethod = new HttpGet(urlOverHttps); + + try (final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .build()) { + + final HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + } + } + + @Test + void givenAcceptingAllCertificates_whenUsingRestTemplate_thenCorrect() { + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .build(); + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setHttpClient(httpClient); + + final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + } + + @Test + void whenHttpsUrlIsConsumed_thenException() { + String urlOverHttps = "https://localhost:8082/httpclient-simple"; + HttpGet getMethod = new HttpGet(urlOverHttps); + + assertThrows(SSLPeerUnverifiedException.class, () -> { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + }); + } +} \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java new file mode 100644 index 0000000000..c336e6a068 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java @@ -0,0 +1,92 @@ +package com.baeldung.client; + +import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLContext; + + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; + +import org.apache.http.conn.ssl.TrustStrategy; +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.ssl.SSLContexts; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +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 { + + final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; + + @Test + void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_2() throws GeneralSecurityException { + + final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + final Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); + + final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setConnectionManager(connectionManager) + .build(); + + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + } + + @Test + void givenAcceptingAllCertificatesUsing4_4_whenHttpsUrlIsConsumed_thenCorrect() throws IOException { + final CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); + + final HttpGet getMethod = new HttpGet(urlOverHttps); + final HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + } + + @Test + void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect(){ + final CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setHttpClient(httpClient); + + final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + } + + @Test + public void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + String urlOverHttps = "https://localhost:8082/httpclient-simple"; + HttpGet getMethod = new HttpGet(urlOverHttps); + HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + } +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientHeaderV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientHeaderV4LiveTest.java new file mode 100644 index 0000000000..eef813b3ff --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientHeaderV4LiveTest.java @@ -0,0 +1,24 @@ +package com.baeldung.httpclient; + +import java.io.IOException; +import org.apache.http.HttpHeaders; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.HttpClients; +import org.junit.jupiter.api.Test; + +class HttpClientHeaderV4LiveTest { + + private static final String SAMPLE_URL = "http://www.github.com"; + + @Test + void givenRequestBuildWithBuilder_whenRequestHasCustomContentType_thenCorrect() throws IOException { + HttpClient client = HttpClients.custom().build(); + HttpUriRequest request = RequestBuilder.get() + .setUri(SAMPLE_URL) + .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .build(); + client.execute(request); + } +} \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java new file mode 100644 index 0000000000..4d4dd7be15 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java @@ -0,0 +1,116 @@ +package com.baeldung.httpclient; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.http.HttpResponse; +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.config.SocketConfig; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +class HttpClientTimeoutV4LiveTest { + + private CloseableHttpResponse response; + + @AfterEach + public final void after() throws IllegalStateException, IOException { + ResponseUtil.closeResponse(response); + } + + + @Test + void givenUsingNewApi_whenSettingTimeoutViaRequestConfig_thenCorrect() throws IOException { + final int timeout = 2; + final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); + final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); + final HttpGet request = new HttpGet("http://www.github.com"); + + response = client.execute(request); + + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + } + + @Test + void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException { + final int timeout = 2; + + final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout * 1000).build(); + final CloseableHttpClient client = HttpClientBuilder.create().setDefaultSocketConfig(config).build(); + + final HttpGet request = new HttpGet("http://www.github.com"); + + response = client.execute(request); + + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + } + + @Test + void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException { + final int timeout = 5; + + final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); + final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); + + final HttpGet request = new HttpGet("http://www.github.com"); + + response = client.execute(request); + + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + } + + /** + * This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP) + */ + @Test + @Disabled + void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException { + final int timeout = 3; + + final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); + final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); + + final HttpGet request = new HttpGet("http://www.google.com:81"); + + assertThrows(ConnectTimeoutException.class, () -> { + client.execute(request); + }); + + } + + @Test + void whenSecuredRestApiIsConsumed_then200OK() throws IOException { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + + int timeout = 20; // seconds + RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000) + .setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); + HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1"); + getMethod.setConfig(requestConfig); + + int hardTimeout = 5; // seconds + TimerTask task = new TimerTask() { + @Override + public void run() { + getMethod.abort(); + } + }; + new Timer(true).schedule(task, hardTimeout * 1000); + + HttpResponse response = httpClient.execute(getMethod); + System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode()); + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpsClientV4SslLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpsClientV4SslLiveTest.java new file mode 100644 index 0000000000..6c7bcf9b08 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpsClientV4SslLiveTest.java @@ -0,0 +1,111 @@ +package com.baeldung.httpclient; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.ssl.TrustStrategy; +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.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.junit.jupiter.api.Test; + +class HttpsClientV4SslLiveTest { + + + // "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1" // local + // "https://mms.nw.ru/" // hosted + private static final String HOST_WITH_SSL = "https://mms.nw.ru/"; + + // tests + + @Test + void whenHttpsUrlIsConsumed_thenException() { + final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); + + assertThrows(SSLHandshakeException.class, () -> { + final CloseableHttpClient httpClient = HttpClientBuilder + .create() + .build(); + final HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + }); + } + + + @Test + void whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { + final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; + final SSLContext sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); + + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .build(); + + final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); + final HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + + httpClient.close(); + } + + @Test + void using_builder_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { + final SSLContext sslContext = new SSLContextBuilder() + .loadTrustMaterial(null, new TrustSelfSignedStrategy()) + .build(); + final NoopHostnameVerifier hostnameVerifier = new NoopHostnameVerifier(); + + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLHostnameVerifier(hostnameVerifier) + .setSSLSocketFactory(sslsf) + .build(); + + final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); + final HttpResponse response = httpClient.execute(getMethod); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + httpClient.close(); + + } + + @Test + void givenIgnoringCertificates_whenHttpsUrlIsConsumed_thenCorrect() throws Exception { + final SSLContext sslContext = new SSLContextBuilder() + .loadTrustMaterial(null, (certificate, authType) -> true) + .build(); + + final CloseableHttpClient client = HttpClients.custom() + .setSSLContext(sslContext) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .build(); + final HttpGet httpGet = new HttpGet(HOST_WITH_SSL); + httpGet.setHeader("Accept", "application/xml"); + + final HttpResponse response = client.execute(httpGet); + assertThat(response.getStatusLine() + .getStatusCode(), equalTo(200)); + } + +} \ No newline at end of file diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/ResponseUtil.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/ResponseUtil.java similarity index 100% rename from httpclient-simple/src/test/java/com/baeldung/httpclient/ResponseUtil.java rename to apache-httpclient4/src/test/java/com/baeldung/httpclient/ResponseUtil.java diff --git a/apache-httpclient4/src/test/resources/.gitignore b/apache-httpclient4/src/test/resources/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/apache-httpclient4/src/test/resources/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/apache-httpclient4/src/test/resources/test.in b/apache-httpclient4/src/test/resources/test.in new file mode 100644 index 0000000000..95d09f2b10 --- /dev/null +++ b/apache-httpclient4/src/test/resources/test.in @@ -0,0 +1 @@ +hello world \ No newline at end of file diff --git a/apache-libraries/pom.xml b/apache-libraries/pom.xml index 3d78869865..c1def03bee 100644 --- a/apache-libraries/pom.xml +++ b/apache-libraries/pom.xml @@ -118,11 +118,6 @@ curator-recipes ${curator.version}
- - org.apache.zookeeper - zookeeper - ${zookeeper.version} - com.fasterxml.jackson.core jackson-core @@ -191,17 +186,15 @@ - 1.8 - 1.8 1.8.2 - 2.19.0 - 1.1.2 - 1.1.0.Final - 1.2.0 + 2.45.0 + 2.0.6 + 2.0.1.Final + 1.2.15 3.10.0 - 1.2.1 - 1.2.1 - 1.2.1 + 1.2.15 + 1.2.15 + 1.2.15 1.8.4 2.1.1-incubating 3.4.11 diff --git a/apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroDeSerealizer.java b/apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroDeSerializer.java similarity index 84% rename from apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroDeSerealizer.java rename to apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroDeSerializer.java index 7d30c3d1ee..cf4c360ba4 100644 --- a/apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroDeSerealizer.java +++ b/apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroDeSerializer.java @@ -1,4 +1,4 @@ -package com.baeldung.avro.util.serealization; +package com.baeldung.avro.util.serialization; import com.baeldung.avro.util.model.AvroHttpRequest; import org.apache.avro.io.DatumReader; @@ -10,11 +10,11 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -public class AvroDeSerealizer { +public class AvroDeSerializer { - private static Logger logger = LoggerFactory.getLogger(AvroDeSerealizer.class); + private static Logger logger = LoggerFactory.getLogger(AvroDeSerializer.class); - public AvroHttpRequest deSerealizeAvroHttpRequestJSON(byte[] data) { + public AvroHttpRequest deSerializeAvroHttpRequestJSON(byte[] data) { DatumReader reader = new SpecificDatumReader<>(AvroHttpRequest.class); Decoder decoder = null; try { @@ -27,7 +27,7 @@ public class AvroDeSerealizer { return null; } - public AvroHttpRequest deSerealizeAvroHttpRequestBinary(byte[] data) { + public AvroHttpRequest deSerializeAvroHttpRequestBinary(byte[] data) { DatumReader employeeReader = new SpecificDatumReader<>(AvroHttpRequest.class); Decoder decoder = DecoderFactory.get() .binaryDecoder(data, null); diff --git a/apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroSerealizer.java b/apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroSerializer.java similarity index 87% rename from apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroSerealizer.java rename to apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroSerializer.java index 767b688dea..6d39060ec8 100644 --- a/apache-libraries/src/main/java/com/baeldung/avro/util/serealization/AvroSerealizer.java +++ b/apache-libraries/src/main/java/com/baeldung/avro/util/serialization/AvroSerializer.java @@ -1,4 +1,4 @@ -package com.baeldung.avro.util.serealization; +package com.baeldung.avro.util.serialization; import com.baeldung.avro.util.model.AvroHttpRequest; import org.apache.avro.io.*; @@ -9,11 +9,11 @@ import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; -public class AvroSerealizer { +public class AvroSerializer { - private static final Logger logger = LoggerFactory.getLogger(AvroSerealizer.class); + private static final Logger logger = LoggerFactory.getLogger(AvroSerializer.class); - public byte[] serealizeAvroHttpRequestJSON(AvroHttpRequest request) { + public byte[] serializeAvroHttpRequestJSON(AvroHttpRequest request) { DatumWriter writer = new SpecificDatumWriter<>(AvroHttpRequest.class); byte[] data = new byte[0]; ByteArrayOutputStream stream = new ByteArrayOutputStream(); @@ -30,7 +30,7 @@ public class AvroSerealizer { return data; } - public byte[] serealizeAvroHttpRequestBinary(AvroHttpRequest request) { + public byte[] serializeAvroHttpRequestBinary(AvroHttpRequest request) { DatumWriter writer = new SpecificDatumWriter<>(AvroHttpRequest.class); byte[] data = new byte[0]; ByteArrayOutputStream stream = new ByteArrayOutputStream(); diff --git a/apache-libraries/src/test/java/com/baeldung/avro/util/serealization/AvroSerealizerDeSerealizerIntegrationTest.java b/apache-libraries/src/test/java/com/baeldung/avro/util/serialization/AvroSerializerDeSerializerIntegrationTest.java similarity index 75% rename from apache-libraries/src/test/java/com/baeldung/avro/util/serealization/AvroSerealizerDeSerealizerIntegrationTest.java rename to apache-libraries/src/test/java/com/baeldung/avro/util/serialization/AvroSerializerDeSerializerIntegrationTest.java index 3d413e1939..964eeb6d87 100644 --- a/apache-libraries/src/test/java/com/baeldung/avro/util/serealization/AvroSerealizerDeSerealizerIntegrationTest.java +++ b/apache-libraries/src/test/java/com/baeldung/avro/util/serialization/AvroSerializerDeSerializerIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.avro.util.serealization; +package com.baeldung.avro.util.serialization; import com.baeldung.avro.util.model.Active; import com.baeldung.avro.util.model.AvroHttpRequest; @@ -13,16 +13,16 @@ import java.util.Objects; import static org.junit.Assert.*; -public class AvroSerealizerDeSerealizerIntegrationTest { +public class AvroSerializerDeSerializerIntegrationTest { - AvroSerealizer serealizer; - AvroDeSerealizer deSerealizer; + AvroSerializer serializer; + AvroDeSerializer deserializer; AvroHttpRequest request; @Before public void setUp() throws Exception { - serealizer = new AvroSerealizer(); - deSerealizer = new AvroDeSerealizer(); + serializer = new AvroSerializer(); + deserializer = new AvroDeSerializer(); ClientIdentifier clientIdentifier = ClientIdentifier.newBuilder() .setHostName("localhost") @@ -49,22 +49,22 @@ public class AvroSerealizerDeSerealizerIntegrationTest { @Test public void WhenSerializedUsingJSONEncoder_thenObjectGetsSerialized() { - byte[] data = serealizer.serealizeAvroHttpRequestJSON(request); + byte[] data = serializer.serializeAvroHttpRequestJSON(request); assertTrue(Objects.nonNull(data)); assertTrue(data.length > 0); } @Test public void WhenSerializedUsingBinaryEncoder_thenObjectGetsSerialized() { - byte[] data = serealizer.serealizeAvroHttpRequestBinary(request); + byte[] data = serializer.serializeAvroHttpRequestBinary(request); assertTrue(Objects.nonNull(data)); assertTrue(data.length > 0); } @Test public void WhenDeserializeUsingJSONDecoder_thenActualAndExpectedObjectsAreEqual() { - byte[] data = serealizer.serealizeAvroHttpRequestJSON(request); - AvroHttpRequest actualRequest = deSerealizer.deSerealizeAvroHttpRequestJSON(data); + byte[] data = serializer.serializeAvroHttpRequestJSON(request); + AvroHttpRequest actualRequest = deserializer.deSerializeAvroHttpRequestJSON(data); assertEquals(actualRequest, request); assertTrue(actualRequest.getRequestTime() .equals(request.getRequestTime())); @@ -72,12 +72,12 @@ public class AvroSerealizerDeSerealizerIntegrationTest { @Test public void WhenDeserializeUsingBinaryecoder_thenActualAndExpectedObjectsAreEqual() { - byte[] data = serealizer.serealizeAvroHttpRequestBinary(request); - AvroHttpRequest actualRequest = deSerealizer.deSerealizeAvroHttpRequestBinary(data); + byte[] data = serializer.serializeAvroHttpRequestBinary(request); + AvroHttpRequest actualRequest = deserializer.deSerializeAvroHttpRequestBinary(data); assertEquals(actualRequest, request); assertTrue(actualRequest.getRequestTime() .equals(request.getRequestTime())); } - + } diff --git a/apache-poi-2/README.md b/apache-poi-2/README.md index 2c0deec575..e2b5160109 100644 --- a/apache-poi-2/README.md +++ b/apache-poi-2/README.md @@ -11,4 +11,5 @@ This module contains articles about Apache POI. - [Creating a MS PowerPoint Presentation in Java](https://www.baeldung.com/apache-poi-slideshow) - [Finding the Last Row in an Excel Spreadsheet From Java](https://www.baeldung.com/java-excel-find-last-row) - [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) - More articles: [[<-- prev]](../apache-poi) diff --git a/apache-poi-2/src/main/java/com/baeldung/poi/excel/dateformat/ExcelDateFormat.java b/apache-poi-2/src/main/java/com/baeldung/poi/excel/dateformat/ExcelDateFormat.java new file mode 100644 index 0000000000..6ee2fb3c3b --- /dev/null +++ b/apache-poi-2/src/main/java/com/baeldung/poi/excel/dateformat/ExcelDateFormat.java @@ -0,0 +1,35 @@ +package com.baeldung.poi.excel.dateformat; + +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +public class ExcelDateFormat { + + public final static String CUSTOM_DATE_FORMAT = "m/d/yy h:mm"; + + /** + * Set default date format to a cell + * @param dateCell cell to set date format + * @param wb workbook to create date format cell style + */ + public void setDefaultDateFormat(XSSFCell dateCell, XSSFWorkbook wb) { + CellStyle cellStyle = wb.createCellStyle(); + cellStyle.setDataFormat((short) 14); + dateCell.setCellStyle(cellStyle); + } + + /** + * Set custom date format to a cell + * @param dateCell cell to set date format + * @param wb workbook to create date format cell style + */ + public void setCustomDateFormat(XSSFCell dateCell, XSSFWorkbook wb) { + CellStyle cellStyle = wb.createCellStyle(); + CreationHelper createHelper = wb.getCreationHelper(); + short format = createHelper.createDataFormat().getFormat(CUSTOM_DATE_FORMAT); + cellStyle.setDataFormat(format); + dateCell.setCellStyle(cellStyle); + } +} diff --git a/apache-poi-2/src/test/java/com/baeldung/poi/excel/dateformat/DateFormatUnitTest.java b/apache-poi-2/src/test/java/com/baeldung/poi/excel/dateformat/DateFormatUnitTest.java new file mode 100644 index 0000000000..fe211beb77 --- /dev/null +++ b/apache-poi-2/src/test/java/com/baeldung/poi/excel/dateformat/DateFormatUnitTest.java @@ -0,0 +1,95 @@ +package com.baeldung.poi.excel.dateformat; + +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Date; + +import static com.baeldung.poi.excel.dateformat.ExcelDateFormat.CUSTOM_DATE_FORMAT; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DateFormatUnitTest { + + private ExcelDateFormat excelDateFormat; + + private XSSFWorkbook wb; + + private Date date; + + + @BeforeEach + public void setup() { + excelDateFormat = new ExcelDateFormat(); + wb = new XSSFWorkbook(); + wb.createSheet(); + date = new Date(); + } + + @Test + void givenExcelDate_whenSetDefaultDate_thenSuccess() { + // given Excel Sheet + XSSFSheet sheet = wb.getSheetAt(0); + XSSFCell dateCell = sheet.createRow(0).createCell(0); + + // when set default date format + excelDateFormat.setDefaultDateFormat(dateCell, wb); + dateCell.setCellValue(date); + + // then success + assertEquals(date, dateCell.getDateCellValue()); + } + + @Test + void givenExcelDate_whenSetCustomDate_thenSuccess() { + // given Excel Sheet + XSSFSheet sheet = wb.getSheetAt(0); + XSSFCell dateCellCustom = sheet.createRow(0).createCell(0); + + // when set custom date format + excelDateFormat.setCustomDateFormat(dateCellCustom, wb); + dateCellCustom.setCellValue(date); + + // then success + assertEquals(CUSTOM_DATE_FORMAT, dateCellCustom.getCellStyle().getDataFormatString()); + assertEquals(date, dateCellCustom.getDateCellValue()); + } + + @Test + void givenExcelDefaultDateFormat_whenGetDefaultDateFormat_thenSuccess() { + // given Excel cell style with default date format + CellStyle cellStyle = wb.createCellStyle(); + + // when get default date format + cellStyle.setDataFormat((short) 14); + // then success + assertEquals("m/d/yy", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 15); + assertEquals("d-mmm-yy", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 16); + assertEquals("d-mmm", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 17); + assertEquals("mmm-yy", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 18); + assertEquals("h:mm AM/PM", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 19); + assertEquals("h:mm:ss AM/PM", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 20); + assertEquals("h:mm", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 21); + assertEquals("h:mm:ss", cellStyle.getDataFormatString()); + + cellStyle.setDataFormat((short) 22); + assertEquals("m/d/yy h:mm", cellStyle.getDataFormatString()); + } +} diff --git a/apache-velocity/pom.xml b/apache-velocity/pom.xml index f4b6de8872..a562ebeec0 100644 --- a/apache-velocity/pom.xml +++ b/apache-velocity/pom.xml @@ -63,6 +63,7 @@ 4.5.2 1.7 2.0 + 3.3.2 \ No newline at end of file diff --git a/asciidoctor/pom.xml b/asciidoctor/pom.xml index e24917f2f4..b72f050379 100644 --- a/asciidoctor/pom.xml +++ b/asciidoctor/pom.xml @@ -62,10 +62,10 @@ - 1.5.6 - 1.5.6 - 1.5.0-alpha.15 - 1.5.0-alpha.15 + 2.2.2 + 2.5.7 + 2.3.4 + 2.3.4 \ No newline at end of file diff --git a/aws-modules/aws-lambda/shipping-tracker/ShippingFunction/pom.xml b/aws-modules/aws-lambda/shipping-tracker/ShippingFunction/pom.xml index c36c81375d..24f2a76912 100644 --- a/aws-modules/aws-lambda/shipping-tracker/ShippingFunction/pom.xml +++ b/aws-modules/aws-lambda/shipping-tracker/ShippingFunction/pom.xml @@ -69,8 +69,8 @@ - 1.8 - 1.8 + 11 + 11 5.4.21.Final 1.2.0 3.1.0 diff --git a/aws-modules/aws-lambda/todo-reminder/ToDoFunction/pom.xml b/aws-modules/aws-lambda/todo-reminder/ToDoFunction/pom.xml index cb6dd08d1e..0dd2e4d14a 100644 --- a/aws-modules/aws-lambda/todo-reminder/ToDoFunction/pom.xml +++ b/aws-modules/aws-lambda/todo-reminder/ToDoFunction/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/maven-v4_0_0.xsd"> 4.0.0 helloworld ToDoFunction @@ -101,16 +101,16 @@ - 1.8 - 1.8 + 11 + 11 1.2.1 3.6.0 - 1.1.0 + 1.2.1 1.2.0 2.13.2 11.2 - 5.0.1 - 1.2.0 + 5.1.0 + 2.0.2 4.1.0 3.19.0 5.8.1 diff --git a/aws-modules/aws-reactive/pom.xml b/aws-modules/aws-reactive/pom.xml index fbad5e30d0..e6b50cadb2 100644 --- a/aws-modules/aws-reactive/pom.xml +++ b/aws-modules/aws-reactive/pom.xml @@ -77,6 +77,7 @@ org.projectlombok lombok + ${lombok.version} @@ -92,6 +93,7 @@ 2.2.1.RELEASE 2.17.283 + 1.18.20 \ No newline at end of file diff --git a/axon/README.md b/axon/README.md index 40547a68b8..9aeef05dd6 100644 --- a/axon/README.md +++ b/axon/README.md @@ -2,11 +2,17 @@ This module contains articles about Axon +## Profiles + +Optionally the code can be run with the 'mongo' profile to use Mongo to store the projection. Otherwise, an in-memory +projection is used. + ## Scripts -One script is included to easily start middleware using Docker: +Two scripts are included to easily start middleware using Docker matching the properties files: - `start_axon_server.sh` to start an Axon Server instance +- `start_mongo.sh` to start a MongoDB instance ### Relevant articles @@ -14,3 +20,5 @@ One script is included to easily start middleware using Docker: - [Multi-Entity Aggregates in Axon](https://www.baeldung.com/java-axon-multi-entity-aggregates) - [Snapshotting Aggregates in Axon](https://www.baeldung.com/axon-snapshotting-aggregates) - [Dispatching Queries in Axon Framework](https://www.baeldung.com/axon-query-dispatching) +- [Persisting the Query Model](https://www.baeldung.com/persisting-the-query-model) +- [Using and testing Axon applications via REST](https://www.baeldung.com/using-and-testing-axon-applications-via-rest) diff --git a/axon/pom.xml b/axon/pom.xml index df14233863..42e32758ea 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -44,6 +44,10 @@ org.springframework.boot spring-boot-starter-data-jpa + + org.axonframework.extensions.mongo + axon-mongo + io.projectreactor reactor-core @@ -68,10 +72,32 @@ reactor-test test + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${de.flapdoodle.embed.mongo.version} + test + + + org.awaitility + awaitility + test + + + org.springframework + spring-webflux + test + + + io.projectreactor.netty + reactor-netty-http + test + - 4.6.0 + 4.6.3 + 3.4.8 \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplication.java b/axon/src/main/java/com/baeldung/axon/OrderApplication.java index 8f507e141c..9e5334c3a3 100644 --- a/axon/src/main/java/com/baeldung/axon/OrderApplication.java +++ b/axon/src/main/java/com/baeldung/axon/OrderApplication.java @@ -9,5 +9,4 @@ public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } - } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java b/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java index 8b743144b4..e1b7d5b14c 100644 --- a/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java +++ b/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java @@ -11,8 +11,7 @@ import org.springframework.context.annotation.Configuration; public class OrderApplicationConfiguration { @Bean - public SnapshotTriggerDefinition orderAggregateSnapshotTriggerDefinition(Snapshotter snapshotter, - @Value("${axon.aggregate.order.snapshot-threshold:250}") int threshold) { + public SnapshotTriggerDefinition orderAggregateSnapshotTriggerDefinition(Snapshotter snapshotter, @Value("${axon.aggregate.order.snapshot-threshold:250}") int threshold) { return new EventCountSnapshotTriggerDefinition(snapshotter, threshold); } } diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java index 1065e9d22b..c58c0b27ac 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java @@ -12,6 +12,7 @@ import com.baeldung.axon.coreapi.events.ProductRemovedEvent; import com.baeldung.axon.coreapi.exceptions.DuplicateOrderLineException; import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException; import com.baeldung.axon.coreapi.exceptions.UnconfirmedOrderException; + import org.axonframework.commandhandling.CommandHandler; import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java index e471ecbfe0..aa774070c0 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderLine.java @@ -7,6 +7,7 @@ import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent; import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent; import com.baeldung.axon.coreapi.events.ProductRemovedEvent; import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException; + import org.axonframework.commandhandling.CommandHandler; import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.EntityId; diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java index 28736aaadc..8f2babc2dc 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/AddProductCommand.java @@ -42,9 +42,6 @@ public class AddProductCommand { @Override public String toString() { - return "AddProductCommand{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "AddProductCommand{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java index 244b69f3b7..37f1df2725 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -36,8 +36,6 @@ public class ConfirmOrderCommand { @Override public String toString() { - return "ConfirmOrderCommand{" + - "orderId='" + orderId + '\'' + - '}'; + return "ConfirmOrderCommand{" + "orderId='" + orderId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java index ceb7fd6a08..294d53cab8 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateOrderCommand.java @@ -36,8 +36,6 @@ public class CreateOrderCommand { @Override public String toString() { - return "CreateOrderCommand{" + - "orderId='" + orderId + '\'' + - '}'; + return "CreateOrderCommand{" + "orderId='" + orderId + '\'' + '}'; } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java index f6f4db00fc..0874f88df8 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/DecrementProductCountCommand.java @@ -42,9 +42,6 @@ public class DecrementProductCountCommand { @Override public String toString() { - return "DecrementProductCountCommand{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "DecrementProductCountCommand{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java index 548faabe37..aceb93e478 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/IncrementProductCountCommand.java @@ -42,9 +42,6 @@ public class IncrementProductCountCommand { @Override public String toString() { - return "IncrementProductCountCommand{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "IncrementProductCountCommand{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java index 7312bc1fdb..f0f3a6e071 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -36,8 +36,6 @@ public class ShipOrderCommand { @Override public String toString() { - return "ShipOrderCommand{" + - "orderId='" + orderId + '\'' + - '}'; + return "ShipOrderCommand{" + "orderId='" + orderId + '\'' + '}'; } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java index d2b7d58435..3253c2f1d5 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -33,8 +33,6 @@ public class OrderConfirmedEvent { @Override public String toString() { - return "OrderConfirmedEvent{" + - "orderId='" + orderId + '\'' + - '}'; + return "OrderConfirmedEvent{" + "orderId='" + orderId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java index 5d2d8b7f55..2bb86108f9 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderCreatedEvent.java @@ -33,8 +33,6 @@ public class OrderCreatedEvent { @Override public String toString() { - return "OrderCreatedEvent{" + - "orderId='" + orderId + '\'' + - '}'; + return "OrderCreatedEvent{" + "orderId='" + orderId + '\'' + '}'; } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java index 76aa684629..5161bc7bf1 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -33,8 +33,6 @@ public class OrderShippedEvent { @Override public String toString() { - return "OrderShippedEvent{" + - "orderId='" + orderId + '\'' + - '}'; + return "OrderShippedEvent{" + "orderId='" + orderId + '\'' + '}'; } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java index 091ef2a570..14510cb161 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductAddedEvent.java @@ -39,9 +39,6 @@ public class ProductAddedEvent { @Override public String toString() { - return "ProductAddedEvent{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "ProductAddedEvent{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java index 4017916791..eec424cb24 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountDecrementedEvent.java @@ -39,9 +39,6 @@ public class ProductCountDecrementedEvent { @Override public String toString() { - return "ProductCountDecrementedEvent{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "ProductCountDecrementedEvent{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java index 2910a9ea6f..0d008758c7 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductCountIncrementedEvent.java @@ -39,9 +39,6 @@ public class ProductCountIncrementedEvent { @Override public String toString() { - return "ProductCountIncrementedEvent{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "ProductCountIncrementedEvent{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java index 7f89ccd1cc..13ff77db26 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/ProductRemovedEvent.java @@ -39,9 +39,6 @@ public class ProductRemovedEvent { @Override public String toString() { - return "ProductRemovedEvent{" + - "orderId='" + orderId + '\'' + - ", productId='" + productId + '\'' + - '}'; + return "ProductRemovedEvent{" + "orderId='" + orderId + '\'' + ", productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java index 1810a053d3..9cef3e84ee 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/Order.java @@ -40,7 +40,6 @@ public class Order { products.computeIfPresent(productId, (id, count) -> --count); } - public void removeProduct(String productId) { products.remove(productId); } @@ -62,9 +61,7 @@ public class Order { return false; } Order that = (Order) o; - return Objects.equals(orderId, that.orderId) - && Objects.equals(products, that.products) - && orderStatus == that.orderStatus; + return Objects.equals(orderId, that.orderId) && Objects.equals(products, that.products) && orderStatus == that.orderStatus; } @Override @@ -74,10 +71,6 @@ public class Order { @Override public String toString() { - return "Order{" + - "orderId='" + orderId + '\'' + - ", products=" + products + - ", orderStatus=" + orderStatus + - '}'; + return "Order{" + "orderId='" + orderId + '\'' + ", products=" + products + ", orderStatus=" + orderStatus + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java index 37d2e67445..b4e66289b4 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderUpdatesQuery.java @@ -32,8 +32,6 @@ public class OrderUpdatesQuery { @Override public String toString() { - return "OrderUpdatesQuery{" + - "orderId='" + orderId + '\'' + - '}'; + return "OrderUpdatesQuery{" + "orderId='" + orderId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java index 3a4129685b..8c3bbf3528 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/TotalProductsShippedQuery.java @@ -32,8 +32,6 @@ public class TotalProductsShippedQuery { @Override public String toString() { - return "TotalProductsShippedQuery{" + - "productId='" + productId + '\'' + - '}'; + return "TotalProductsShippedQuery{" + "productId='" + productId + '\'' + '}'; } } diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java index 64058d5eca..186aab3c0c 100644 --- a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -8,12 +8,14 @@ import com.baeldung.axon.coreapi.commands.IncrementProductCountCommand; import com.baeldung.axon.coreapi.commands.ShipOrderCommand; import com.baeldung.axon.querymodel.OrderQueryService; import com.baeldung.axon.querymodel.OrderResponse; + import org.axonframework.commandhandling.gateway.CommandGateway; import org.springframework.http.MediaType; 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.RestController; + import reactor.core.publisher.Flux; import java.util.List; @@ -33,25 +35,28 @@ public class OrderRestEndpoint { @PostMapping("/ship-order") public CompletableFuture shipOrder() { - String orderId = UUID.randomUUID().toString(); + String orderId = UUID.randomUUID() + .toString(); return commandGateway.send(new CreateOrderCommand(orderId)) - .thenCompose(result -> commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"))) - .thenCompose(result -> commandGateway.send(new ConfirmOrderCommand(orderId))) - .thenCompose(result -> commandGateway.send(new ShipOrderCommand(orderId))); + .thenCompose(result -> commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"))) + .thenCompose(result -> commandGateway.send(new ConfirmOrderCommand(orderId))) + .thenCompose(result -> commandGateway.send(new ShipOrderCommand(orderId))); } @PostMapping("/ship-unconfirmed-order") public CompletableFuture shipUnconfirmedOrder() { - String orderId = UUID.randomUUID().toString(); + String orderId = UUID.randomUUID() + .toString(); return commandGateway.send(new CreateOrderCommand(orderId)) - .thenCompose(result -> commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"))) - // This throws an exception, as an Order cannot be shipped if it has not been confirmed yet. - .thenCompose(result -> commandGateway.send(new ShipOrderCommand(orderId))); + .thenCompose(result -> commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"))) + // This throws an exception, as an Order cannot be shipped if it has not been confirmed yet. + .thenCompose(result -> commandGateway.send(new ShipOrderCommand(orderId))); } @PostMapping("/order") public CompletableFuture createOrder() { - return createOrder(UUID.randomUUID().toString()); + return createOrder(UUID.randomUUID() + .toString()); } @PostMapping("/order/{order-id}") @@ -60,20 +65,17 @@ public class OrderRestEndpoint { } @PostMapping("/order/{order-id}/product/{product-id}") - public CompletableFuture addProduct(@PathVariable("order-id") String orderId, - @PathVariable("product-id") String productId) { + public CompletableFuture addProduct(@PathVariable("order-id") String orderId, @PathVariable("product-id") String productId) { return commandGateway.send(new AddProductCommand(orderId, productId)); } @PostMapping("/order/{order-id}/product/{product-id}/increment") - public CompletableFuture incrementProduct(@PathVariable("order-id") String orderId, - @PathVariable("product-id") String productId) { + public CompletableFuture incrementProduct(@PathVariable("order-id") String orderId, @PathVariable("product-id") String productId) { return commandGateway.send(new IncrementProductCountCommand(orderId, productId)); } @PostMapping("/order/{order-id}/product/{product-id}/decrement") - public CompletableFuture decrementProduct(@PathVariable("order-id") String orderId, - @PathVariable("product-id") String productId) { + public CompletableFuture decrementProduct(@PathVariable("order-id") String orderId, @PathVariable("product-id") String productId) { return commandGateway.send(new DecrementProductCountCommand(orderId, productId)); } diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java index fbdf819961..6e9dbbb335 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/InMemoryOrdersEventHandler.java @@ -18,7 +18,9 @@ import org.axonframework.eventhandling.EventHandler; import org.axonframework.queryhandling.QueryHandler; import org.axonframework.queryhandling.QueryUpdateEmitter; import org.reactivestreams.Publisher; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -30,6 +32,7 @@ import java.util.Optional; @Service @ProcessingGroup("orders") +@Profile("!mongo") public class InMemoryOrdersEventHandler implements OrdersEventHandler { private final Map orders = new HashMap<>(); @@ -106,7 +109,8 @@ public class InMemoryOrdersEventHandler implements OrdersEventHandler { @QueryHandler public Publisher handleStreaming(FindAllOrderedProductsQuery query) { - return Mono.fromCallable(orders::values).flatMapMany(Flux::fromIterable); + return Mono.fromCallable(orders::values) + .flatMapMany(Flux::fromIterable); } @QueryHandler diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java b/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java new file mode 100644 index 0000000000..d68569efc8 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MongoConfiguration.java @@ -0,0 +1,26 @@ +package com.baeldung.axon.querymodel; + +import com.mongodb.client.MongoClient; + +import org.axonframework.eventhandling.tokenstore.TokenStore; +import org.axonframework.extensions.mongo.DefaultMongoTemplate; +import org.axonframework.extensions.mongo.eventsourcing.tokenstore.MongoTokenStore; +import org.axonframework.serialization.Serializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("mongo") +public class MongoConfiguration { + + @Bean + public TokenStore getTokenStore(MongoClient client, Serializer serializer) { + return MongoTokenStore.builder() + .mongoTemplate(DefaultMongoTemplate.builder() + .mongoDatabase(client) + .build()) + .serializer(serializer) + .build(); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java new file mode 100644 index 0000000000..4da98a9f97 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MongoOrdersEventHandler.java @@ -0,0 +1,194 @@ +package com.baeldung.axon.querymodel; + +import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; +import com.baeldung.axon.coreapi.events.OrderCreatedEvent; +import com.baeldung.axon.coreapi.events.OrderShippedEvent; +import com.baeldung.axon.coreapi.events.ProductAddedEvent; +import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent; +import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent; +import com.baeldung.axon.coreapi.events.ProductRemovedEvent; +import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery; +import com.baeldung.axon.coreapi.queries.Order; +import com.baeldung.axon.coreapi.queries.OrderStatus; +import com.baeldung.axon.coreapi.queries.OrderUpdatesQuery; +import com.baeldung.axon.coreapi.queries.TotalProductsShippedQuery; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.Indexes; +import com.mongodb.client.result.UpdateResult; + +import groovyjarjarantlr4.v4.runtime.misc.NotNull; + +import org.axonframework.config.ProcessingGroup; +import org.axonframework.eventhandling.EventHandler; +import org.axonframework.queryhandling.QueryHandler; +import org.axonframework.queryhandling.QueryUpdateEmitter; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; + +import java.lang.invoke.MethodHandles; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +import static com.mongodb.client.model.Filters.*; + +@Service +@ProcessingGroup("orders") +@Profile("mongo") +public class MongoOrdersEventHandler implements OrdersEventHandler { + + static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup() + .lookupClass()); + + private final MongoCollection orders; + private final QueryUpdateEmitter emitter; + private static final String ORDER_COLLECTION_NAME = "orders"; + private static final String AXON_FRAMEWORK_DATABASE_NAME = "axonframework"; + + private static final String ORDER_ID_PROPERTY_NAME = "orderId"; + private static final String PRODUCTS_PROPERTY_NAME = "products"; + private static final String ORDER_STATUS_PROPERTY_NAME = "orderStatus"; + + public MongoOrdersEventHandler(MongoClient client, QueryUpdateEmitter emitter) { + orders = client.getDatabase(AXON_FRAMEWORK_DATABASE_NAME) + .getCollection(ORDER_COLLECTION_NAME); + orders.createIndex(Indexes.ascending(ORDER_ID_PROPERTY_NAME), new IndexOptions().unique(true)); + this.emitter = emitter; + } + + @EventHandler + public void on(OrderCreatedEvent event) { + orders.insertOne(orderToDocument(new Order(event.getOrderId()))); + } + + @EventHandler + public void on(ProductAddedEvent event) { + update(event.getOrderId(), o -> o.addProduct(event.getProductId())); + } + + @EventHandler + public void on(ProductCountIncrementedEvent event) { + update(event.getOrderId(), o -> o.incrementProductInstance(event.getProductId())); + } + + @EventHandler + public void on(ProductCountDecrementedEvent event) { + update(event.getOrderId(), o -> o.decrementProductInstance(event.getProductId())); + } + + @EventHandler + public void on(ProductRemovedEvent event) { + update(event.getOrderId(), o -> o.removeProduct(event.getProductId())); + } + + @EventHandler + public void on(OrderConfirmedEvent event) { + update(event.getOrderId(), Order::setOrderConfirmed); + } + + @EventHandler + public void on(OrderShippedEvent event) { + update(event.getOrderId(), Order::setOrderShipped); + } + + @QueryHandler + public List handle(FindAllOrderedProductsQuery query) { + List orderList = new ArrayList<>(); + orders.find() + .forEach(d -> orderList.add(documentToOrder(d))); + return orderList; + } + + @Override + public Publisher handleStreaming(FindAllOrderedProductsQuery query) { + return Flux.fromIterable(orders.find()) + .map(this::documentToOrder); + } + + @QueryHandler + public Integer handle(TotalProductsShippedQuery query) { + AtomicInteger result = new AtomicInteger(); + orders.find(shippedProductFilter(query.getProductId())) + .map(d -> d.get(PRODUCTS_PROPERTY_NAME, Document.class)) + .map(d -> d.getInteger(query.getProductId(), 0)) + .forEach(result::addAndGet); + return result.get(); + } + + @QueryHandler + public Order handle(OrderUpdatesQuery query) { + return getOrder(query.getOrderId()).orElse(null); + } + + @Override + public void reset(List orderList) { + orders.deleteMany(new Document()); + orderList.forEach(o -> orders.insertOne(orderToDocument(o))); + } + + private Optional getOrder(String orderId) { + return Optional.ofNullable(orders.find(eq(ORDER_ID_PROPERTY_NAME, orderId)) + .first()) + .map(this::documentToOrder); + } + + private Order emitUpdate(Order order) { + emitter.emit(OrderUpdatesQuery.class, q -> order.getOrderId() + .equals(q.getOrderId()), order); + return order; + } + + private Order updateOrder(Order order, Consumer updateFunction) { + updateFunction.accept(order); + return order; + } + + private UpdateResult persistUpdate(Order order) { + return orders.replaceOne(eq(ORDER_ID_PROPERTY_NAME, order.getOrderId()), orderToDocument(order)); + } + + private void update(String orderId, Consumer updateFunction) { + UpdateResult result = getOrder(orderId).map(o -> updateOrder(o, updateFunction)) + .map(this::emitUpdate) + .map(this::persistUpdate) + .orElse(null); + logger.info("Result of updating order with orderId '{}': {}", orderId, result); + } + + private Document orderToDocument(Order order) { + return new Document(ORDER_ID_PROPERTY_NAME, order.getOrderId()).append(PRODUCTS_PROPERTY_NAME, order.getProducts()) + .append(ORDER_STATUS_PROPERTY_NAME, order.getOrderStatus() + .toString()); + } + + private Order documentToOrder(@NotNull Document document) { + Order order = new Order(document.getString(ORDER_ID_PROPERTY_NAME)); + Document products = document.get(PRODUCTS_PROPERTY_NAME, Document.class); + products.forEach((k, v) -> order.getProducts() + .put(k, (Integer) v)); + String status = document.getString(ORDER_STATUS_PROPERTY_NAME); + if (OrderStatus.CONFIRMED.toString() + .equals(status)) { + order.setOrderConfirmed(); + } else if (OrderStatus.SHIPPED.toString() + .equals(status)) { + order.setOrderShipped(); + } + return order; + } + + private Bson shippedProductFilter(String productId) { + return and(eq(ORDER_STATUS_PROPERTY_NAME, OrderStatus.SHIPPED.toString()), exists(String.format(PRODUCTS_PROPERTY_NAME + ".%s", productId))); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java index ae391c3cb1..8196a98957 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderQueryService.java @@ -37,12 +37,12 @@ public class OrderQueryService { public Flux allOrdersStreaming() { Publisher publisher = queryGateway.streamingQuery(new FindAllOrderedProductsQuery(), Order.class); - return Flux.from(publisher).map(OrderResponse::new); + return Flux.from(publisher) + .map(OrderResponse::new); } public Integer totalShipped(String productId) { - return queryGateway.scatterGather(new TotalProductsShippedQuery(productId), - ResponseTypes.instanceOf(Integer.class), 10L, TimeUnit.SECONDS) + return queryGateway.scatterGather(new TotalProductsShippedQuery(productId), ResponseTypes.instanceOf(Integer.class), 10L, TimeUnit.SECONDS) .reduce(0, Integer::sum); } diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java index 90430b1e3d..2c4d32bff3 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderStatusResponse.java @@ -7,7 +7,8 @@ public enum OrderStatusResponse { static OrderStatusResponse toResponse(OrderStatus status) { for (OrderStatusResponse response : values()) { - if (response.toString().equals(status.toString())) { + if (response.toString() + .equals(status.toString())) { return response; } } diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java index 7e49abf93b..740e00cf72 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrdersEventHandler.java @@ -11,6 +11,7 @@ import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery; import com.baeldung.axon.coreapi.queries.Order; import com.baeldung.axon.coreapi.queries.OrderUpdatesQuery; import com.baeldung.axon.coreapi.queries.TotalProductsShippedQuery; + import org.reactivestreams.Publisher; import java.util.List; diff --git a/axon/src/main/resources/application-mongo.properties b/axon/src/main/resources/application-mongo.properties new file mode 100644 index 0000000000..f642d1591c --- /dev/null +++ b/axon/src/main/resources/application-mongo.properties @@ -0,0 +1,6 @@ +spring.data.mongodb.host=localhost +spring.data.mongodb.port=27017 +spring.data.mongodb.authentication-database=admin +spring.data.mongodb.username=admin1234 +spring.data.mongodb.password=somepassword +spring.data.mongodb.database=order-projection \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java index c1d6bdccc2..fe7f57f854 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -17,6 +17,7 @@ import com.baeldung.axon.coreapi.events.ProductRemovedEvent; import com.baeldung.axon.coreapi.exceptions.DuplicateOrderLineException; import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException; import com.baeldung.axon.coreapi.exceptions.UnconfirmedOrderException; + import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.axonframework.test.matchers.Matchers; @@ -26,8 +27,10 @@ import java.util.UUID; class OrderAggregateUnitTest { - private static final String ORDER_ID = UUID.randomUUID().toString(); - private static final String PRODUCT_ID = UUID.randomUUID().toString(); + private static final String ORDER_ID = UUID.randomUUID() + .toString(); + private static final String PRODUCT_ID = UUID.randomUUID() + .toString(); private FixtureConfiguration fixture; @@ -39,101 +42,95 @@ class OrderAggregateUnitTest { @Test void giveNoPriorActivity_whenCreateOrderCommand_thenShouldPublishOrderCreatedEvent() { fixture.givenNoPriorActivity() - .when(new CreateOrderCommand(ORDER_ID)) - .expectEvents(new OrderCreatedEvent(ORDER_ID)); + .when(new CreateOrderCommand(ORDER_ID)) + .expectEvents(new OrderCreatedEvent(ORDER_ID)); } @Test void givenOrderCreatedEvent_whenAddProductCommand_thenShouldPublishProductAddedEvent() { fixture.given(new OrderCreatedEvent(ORDER_ID)) - .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) - .expectEvents(new ProductAddedEvent(ORDER_ID, PRODUCT_ID)); + .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) + .expectEvents(new ProductAddedEvent(ORDER_ID, PRODUCT_ID)); } @Test void givenOrderCreatedEventAndProductAddedEvent_whenAddProductCommandForSameProductId_thenShouldThrowDuplicateOrderLineException() { fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID)) - .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) - .expectException(DuplicateOrderLineException.class) - .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(PRODUCT_ID))); + .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) + .expectException(DuplicateOrderLineException.class) + .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(PRODUCT_ID))); } @Test void givenOrderCreatedEventAndProductAddedEvent_whenIncrementProductCountCommand_thenShouldPublishProductCountIncrementedEvent() { fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID)) - .when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID)) - .expectEvents(new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID)); + .when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID)) + .expectEvents(new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID)); } @Test void givenOrderCreatedEventProductAddedEventAndProductCountIncrementedEvent_whenDecrementProductCountCommand_thenShouldPublishProductCountDecrementedEvent() { - fixture.given(new OrderCreatedEvent(ORDER_ID), - new ProductAddedEvent(ORDER_ID, PRODUCT_ID), - new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID)) - .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) - .expectEvents(new ProductCountDecrementedEvent(ORDER_ID, PRODUCT_ID)); + fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID)) + .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) + .expectEvents(new ProductCountDecrementedEvent(ORDER_ID, PRODUCT_ID)); } @Test void givenOrderCreatedEventAndProductAddedEvent_whenDecrementProductCountCommand_thenShouldPublishProductRemovedEvent() { fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID)) - .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) - .expectEvents(new ProductRemovedEvent(ORDER_ID, PRODUCT_ID)); + .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) + .expectEvents(new ProductRemovedEvent(ORDER_ID, PRODUCT_ID)); } @Test void givenOrderCreatedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() { fixture.given(new OrderCreatedEvent(ORDER_ID)) - .when(new ConfirmOrderCommand(ORDER_ID)) - .expectEvents(new OrderConfirmedEvent(ORDER_ID)); + .when(new ConfirmOrderCommand(ORDER_ID)) + .expectEvents(new OrderConfirmedEvent(ORDER_ID)); } @Test void givenOrderCreatedEventAndOrderConfirmedEvent_whenConfirmOrderCommand_thenExpectNoEvents() { fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID)) - .when(new ConfirmOrderCommand(ORDER_ID)) - .expectNoEvents(); + .when(new ConfirmOrderCommand(ORDER_ID)) + .expectNoEvents(); } @Test void givenOrderCreatedEvent_whenShipOrderCommand_thenShouldThrowUnconfirmedOrderException() { fixture.given(new OrderCreatedEvent(ORDER_ID)) - .when(new ShipOrderCommand(ORDER_ID)) - .expectException(UnconfirmedOrderException.class); + .when(new ShipOrderCommand(ORDER_ID)) + .expectException(UnconfirmedOrderException.class); } @Test void givenOrderCreatedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() { fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID)) - .when(new ShipOrderCommand(ORDER_ID)) - .expectEvents(new OrderShippedEvent(ORDER_ID)); + .when(new ShipOrderCommand(ORDER_ID)) + .expectEvents(new OrderShippedEvent(ORDER_ID)); } @Test void givenOrderCreatedEventProductAndOrderConfirmedEvent_whenAddProductCommand_thenShouldThrowOrderAlreadyConfirmedException() { fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID)) - .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) - .expectException(OrderAlreadyConfirmedException.class) - .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); + .when(new AddProductCommand(ORDER_ID, PRODUCT_ID)) + .expectException(OrderAlreadyConfirmedException.class) + .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); } @Test void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenIncrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() { - fixture.given(new OrderCreatedEvent(ORDER_ID), - new ProductAddedEvent(ORDER_ID, PRODUCT_ID), - new OrderConfirmedEvent(ORDER_ID)) - .when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID)) - .expectException(OrderAlreadyConfirmedException.class) - .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); + fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new OrderConfirmedEvent(ORDER_ID)) + .when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID)) + .expectException(OrderAlreadyConfirmedException.class) + .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); } @Test void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenDecrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() { - fixture.given(new OrderCreatedEvent(ORDER_ID), - new ProductAddedEvent(ORDER_ID, PRODUCT_ID), - new OrderConfirmedEvent(ORDER_ID)) - .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) - .expectException(OrderAlreadyConfirmedException.class) - .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); + fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new OrderConfirmedEvent(ORDER_ID)) + .when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID)) + .expectException(OrderAlreadyConfirmedException.class) + .expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID))); } } \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java b/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java new file mode 100644 index 0000000000..3b5c130c89 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/gui/OrderRestEndpointManualTest.java @@ -0,0 +1,188 @@ +package com.baeldung.axon.gui; + +import com.baeldung.axon.OrderApplication; +import com.baeldung.axon.querymodel.OrderResponse; +import com.baeldung.axon.querymodel.OrderStatusResponse; + +import org.junit.jupiter.api.*; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.netty.http.client.HttpClient; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest(classes = OrderApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +//marked as manual as the test is unstable on Jenkins due to low resources +class OrderRestEndpointManualTest { + + @LocalServerPort + private int port; + + @Test + @DirtiesContext + void givenCreateOrderCalled_whenCallingAllOrders_thenOneCreatedOrderIsReturned() { + WebClient client = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + createRandomNewOrder(client); + StepVerifier.create(retrieveListResponse(client.get() + .uri("http://localhost:" + port + "/all-orders"))) + .expectNextMatches(list -> 1 == list.size() && list.get(0) + .getOrderStatus() == OrderStatusResponse.CREATED) + .verifyComplete(); + } + + @Test + @DirtiesContext + void givenCreateOrderCalledThreeTimesAnd_whenCallingAllOrdersStreaming_thenTwoCreatedOrdersAreReturned() { + WebClient client = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + for (int i = 0; i < 3; i++) { + createRandomNewOrder(client); + } + StepVerifier.create(retrieveStreamingResponse(client.get() + .uri("http://localhost:" + port + "/all-orders-streaming"))) + .expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED) + .expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED) + .expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED) + .verifyComplete(); + } + + @Test + @DirtiesContext + void givenRuleExistThatNeedConfirmationBeforeShipping_whenCallingShipUnconfirmed_thenErrorReturned() { + WebClient client = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + StepVerifier.create(retrieveResponse(client.post() + .uri("http://localhost:" + port + "/ship-unconfirmed-order"))) + .verifyError(WebClientResponseException.class); + } + + @Test + @DirtiesContext + void givenShipOrderCalled_whenCallingAllShippedChairs_then234PlusOneIsReturned() { + WebClient client = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + verifyVoidPost(client, "http://localhost:" + port + "/ship-order"); + StepVerifier.create(retrieveIntegerResponse(client.get() + .uri("http://localhost:" + port + "/total-shipped/Deluxe Chair"))) + .assertNext(r -> assertEquals(235, r)) + .verifyComplete(); + } + + @Test + @DirtiesContext + void givenOrdersAreUpdated_whenCallingOrderUpdates_thenUpdatesReturned() { + WebClient updaterClient = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + WebClient receiverClient = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + String orderId = UUID.randomUUID() + .toString(); + String productId = UUID.randomUUID() + .toString(); + StepVerifier.create(retrieveResponse(updaterClient.post() + .uri("http://localhost:" + port + "/order/" + orderId))) + .assertNext(Assertions::assertNotNull) + .verifyComplete(); + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + executor.schedule(() -> addIncrementDecrementConfirmAndShipProduct(orderId, productId), 1L, TimeUnit.SECONDS); + try { + StepVerifier.create(retrieveStreamingResponse(receiverClient.get() + .uri("http://localhost:" + port + "/order-updates/" + orderId))) + .assertNext(p -> assertTrue(p.getProducts() + .isEmpty())) + .assertNext(p -> assertEquals(1, p.getProducts() + .get(productId))) + .assertNext(p -> assertEquals(2, p.getProducts() + .get(productId))) + .assertNext(p -> assertEquals(1, p.getProducts() + .get(productId))) + .assertNext(p -> assertEquals(OrderStatusResponse.CONFIRMED, p.getOrderStatus())) + .assertNext(p -> assertEquals(OrderStatusResponse.SHIPPED, p.getOrderStatus())) + .thenCancel() + .verify(); + } finally { + executor.shutdown(); + } + } + + private void addIncrementDecrementConfirmAndShipProduct(String orderId, String productId) { + WebClient client = WebClient.builder() + .clientConnector(httpConnector()) + .build(); + String base = "http://localhost:" + port + "/order/" + orderId; + verifyVoidPost(client, base + "/product/" + productId); + verifyVoidPost(client, base + "/product/" + productId + "/increment"); + verifyVoidPost(client, base + "/product/" + productId + "/decrement"); + verifyVoidPost(client, base + "/confirm"); + verifyVoidPost(client, base + "/ship"); + } + + private void createRandomNewOrder(WebClient client){ + StepVerifier.create(retrieveResponse(client.post() + .uri("http://localhost:" + port + "/order"))) + .assertNext(Assertions::assertNotNull) + .verifyComplete(); + } + + private void verifyVoidPost(WebClient client, String uri) { + StepVerifier.create(retrieveResponse(client.post() + .uri(uri))) + .verifyComplete(); + } + + private static ReactorClientHttpConnector httpConnector() { + HttpClient httpClient = HttpClient.create() + .wiretap(true); + return new ReactorClientHttpConnector(httpClient); + } + + private Mono retrieveResponse(WebClient.RequestBodySpec spec) { + return spec.retrieve() + .bodyToMono(String.class); + } + + private Mono retrieveListResponse(WebClient.RequestHeadersSpec spec) { + return spec.accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(ResponseList.class); + } + + private Mono retrieveIntegerResponse(WebClient.RequestHeadersSpec spec) { + return spec.retrieve() + .bodyToMono(Integer.class); + } + + private Flux retrieveStreamingResponse(WebClient.RequestHeadersSpec spec) { + return spec.retrieve() + .bodyToFlux(OrderResponse.class); + } + + private static class ResponseList extends ArrayList { + + private ResponseList() { + super(); + } + } +} diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java b/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java index 2396d0f10b..fb7833a3f6 100644 --- a/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java +++ b/axon/src/test/java/com/baeldung/axon/querymodel/AbstractOrdersEventHandlerUnitTest.java @@ -12,8 +12,10 @@ import com.baeldung.axon.coreapi.queries.Order; import com.baeldung.axon.coreapi.queries.OrderStatus; import com.baeldung.axon.coreapi.queries.OrderUpdatesQuery; import com.baeldung.axon.coreapi.queries.TotalProductsShippedQuery; + import org.axonframework.queryhandling.QueryUpdateEmitter; import org.junit.jupiter.api.*; + import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,10 +29,14 @@ import static org.mockito.Mockito.*; public abstract class AbstractOrdersEventHandlerUnitTest { - private static final String ORDER_ID_1 = UUID.randomUUID().toString(); - private static final String ORDER_ID_2 = UUID.randomUUID().toString(); - private static final String PRODUCT_ID_1 = UUID.randomUUID().toString(); - private static final String PRODUCT_ID_2 = UUID.randomUUID().toString(); + private static final String ORDER_ID_1 = UUID.randomUUID() + .toString(); + private static final String ORDER_ID_2 = UUID.randomUUID() + .toString(); + private static final String PRODUCT_ID_1 = UUID.randomUUID() + .toString(); + private static final String PRODUCT_ID_2 = UUID.randomUUID() + .toString(); private OrdersEventHandler handler; private static Order orderOne; private static Order orderTwo; @@ -39,12 +45,15 @@ public abstract class AbstractOrdersEventHandlerUnitTest { @BeforeAll static void createOrders() { orderOne = new Order(ORDER_ID_1); - orderOne.getProducts().put(PRODUCT_ID_1, 3); + orderOne.getProducts() + .put(PRODUCT_ID_1, 3); orderOne.setOrderShipped(); orderTwo = new Order(ORDER_ID_2); - orderTwo.getProducts().put(PRODUCT_ID_1, 1); - orderTwo.getProducts().put(PRODUCT_ID_2, 1); + orderTwo.getProducts() + .put(PRODUCT_ID_1, 1); + orderTwo.getProducts() + .put(PRODUCT_ID_2, 1); orderTwo.setOrderConfirmed(); } @@ -64,10 +73,18 @@ public abstract class AbstractOrdersEventHandlerUnitTest { assertNotNull(result); assertEquals(2, result.size()); - Order order_1 = result.stream().filter(o -> o.getOrderId().equals(ORDER_ID_1)).findFirst().orElse(null); + Order order_1 = result.stream() + .filter(o -> o.getOrderId() + .equals(ORDER_ID_1)) + .findFirst() + .orElse(null); assertEquals(orderOne, order_1); - Order order_2 = result.stream().filter(o -> o.getOrderId().equals(ORDER_ID_2)).findFirst().orElse(null); + Order order_2 = result.stream() + .filter(o -> o.getOrderId() + .equals(ORDER_ID_2)) + .findFirst() + .orElse(null); assertEquals(orderTwo, order_2); } @@ -75,9 +92,11 @@ public abstract class AbstractOrdersEventHandlerUnitTest { void givenTwoOrdersPlacedOfWhichOneNotShipped_whenFindAllOrderedProductsQueryStreaming_thenCorrectOrdersAreReturned() { resetWithTwoOrders(); final Consumer orderVerifier = order -> { - if (order.getOrderId().equals(orderOne.getOrderId())) { + if (order.getOrderId() + .equals(orderOne.getOrderId())) { assertEquals(orderOne, order); - } else if (order.getOrderId().equals(orderTwo.getOrderId())) { + } else if (order.getOrderId() + .equals(orderTwo.getOrderId())) { assertEquals(orderTwo, order); } else { throw new RuntimeException("Would expect either order one or order two"); @@ -85,10 +104,10 @@ public abstract class AbstractOrdersEventHandlerUnitTest { }; StepVerifier.create(Flux.from(handler.handleStreaming(new FindAllOrderedProductsQuery()))) - .assertNext(orderVerifier) - .assertNext(orderVerifier) - .expectComplete() - .verify(); + .assertNext(orderVerifier) + .assertNext(orderVerifier) + .expectComplete() + .verify(); } @Test @@ -120,7 +139,8 @@ public abstract class AbstractOrdersEventHandlerUnitTest { Order result = handler.handle(new OrderUpdatesQuery(ORDER_ID_1)); assertNotNull(result); assertEquals(ORDER_ID_1, result.getOrderId()); - assertEquals(3, result.getProducts().get(PRODUCT_ID_1)); + assertEquals(3, result.getProducts() + .get(PRODUCT_ID_1)); assertEquals(OrderStatus.SHIPPED, result.getOrderStatus()); } diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java b/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java new file mode 100644 index 0000000000..c183294dc1 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/querymodel/MongoOrdersEventHandlerUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.axon.querymodel; + +import com.mongodb.client.MongoClient; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; + +@DataMongoTest +public class MongoOrdersEventHandlerUnitTest extends AbstractOrdersEventHandlerUnitTest { + + @Autowired + MongoClient mongoClient; + + @Override + protected OrdersEventHandler getHandler() { + mongoClient.getDatabase("axonframework") + .drop(); + return new MongoOrdersEventHandler(mongoClient, emitter); + } +} diff --git a/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java index dfb4881fdc..4a89fe0e4e 100644 --- a/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/querymodel/OrderQueryServiceIntegrationTest.java @@ -6,7 +6,6 @@ import com.baeldung.axon.coreapi.events.OrderShippedEvent; import com.baeldung.axon.coreapi.events.ProductAddedEvent; import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent; import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent; -import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery; import com.baeldung.axon.coreapi.queries.Order; import org.axonframework.eventhandling.gateway.EventGateway; @@ -66,9 +65,9 @@ class OrderQueryServiceIntegrationTest { void givenOrderCreatedEventSend_whenCallingAllOrdersStreaming_thenOneOrderIsReturned() { Flux result = queryService.allOrdersStreaming(); StepVerifier.create(result) - .assertNext(order -> assertEquals(orderId, order.getOrderId())) - .expectComplete() - .verify(); + .assertNext(order -> assertEquals(orderId, order.getOrderId())) + .expectComplete() + .verify(); } @Test diff --git a/axon/src/test/resources/application.properties b/axon/src/test/resources/application.properties index 35b5452b57..c42b7a4e90 100644 --- a/axon/src/test/resources/application.properties +++ b/axon/src/test/resources/application.properties @@ -1 +1,2 @@ +spring.mongodb.embedded.version=5.0.6 axon.axonserver.enabled=false \ No newline at end of file diff --git a/axon/start_mongo.sh b/axon/start_mongo.sh new file mode 100755 index 0000000000..2cc5a3a7cf --- /dev/null +++ b/axon/start_mongo.sh @@ -0,0 +1,7 @@ +docker run \ + -d \ + --name order_projection \ + -p 27017:27017 \ + -e MONGO_INITDB_ROOT_USERNAME=admin1234 \ + -e MONGO_INITDB_ROOT_PASSWORD=somepassword \ + mongo \ No newline at end of file diff --git a/azure/pom.xml b/azure/pom.xml index ae20ae7785..6a06282a71 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -36,8 +36,8 @@ runtime - mysql - mysql-connector-java + com.mysql + mysql-connector-j runtime diff --git a/core-groovy-modules/core-groovy-2/README.md b/core-groovy-modules/core-groovy-2/README.md index 9f81ac6c16..f128b43092 100644 --- a/core-groovy-modules/core-groovy-2/README.md +++ b/core-groovy-modules/core-groovy-2/README.md @@ -14,4 +14,4 @@ This module contains articles about core Groovy concepts - [A Quick Guide to Working with Web Services in Groovy](https://www.baeldung.com/groovy-web-services) - [Categories in Groovy](https://www.baeldung.com/groovy-categories) - [How to Determine the Data Type in Groovy](https://www.baeldung.com/groovy-determine-data-type) -- [[<-- Prev]](/core-groovy) +- [[<-- Prev]](/core-groovy-modules/core-groovy) diff --git a/core-groovy-modules/core-groovy-2/pom.xml b/core-groovy-modules/core-groovy-2/pom.xml index a177844a15..ca6a9a62c7 100644 --- a/core-groovy-modules/core-groovy-2/pom.xml +++ b/core-groovy-modules/core-groovy-2/pom.xml @@ -83,7 +83,7 @@ org.codehaus.groovy groovy-eclipse-batch - ${groovy.version}-01 + ${groovy-eclipse-batch.version} @@ -155,16 +155,18 @@ - central - https://jcenter.bintray.com + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ 1.1.3 - 3.1.0 - 3.8.0 - 3.3.0-01 + 3.4.2 + 3.8.1 + 3.7.0 + 3.0.8-01 - \ No newline at end of file + diff --git a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/BaeldungCategory.groovy b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/BaeldungCategory.groovy index 479c39699f..ccb1c7fc95 100644 --- a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/BaeldungCategory.groovy +++ b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/BaeldungCategory.groovy @@ -1,17 +1,17 @@ -package com.baeldung.category; +package com.baeldung.category class BaeldungCategory { - public static String capitalize(String self) { - String capitalizedStr = self; + static String capitalize(String self) { + String capitalizedStr = self if (self.size() > 0) { - capitalizedStr = self.substring(0, 1).toUpperCase() + self.substring(1); + capitalizedStr = self.substring(0, 1).toUpperCase() + self.substring(1) } + return capitalizedStr } - - public static double toThePower(Number self, Number exponent) { - return Math.pow(self, exponent); - } + static double toThePower(Number self, Number exponent) { + return Math.pow(self, exponent) + } } diff --git a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/NumberCategory.groovy b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/NumberCategory.groovy index ccf2ed519b..4f38b87ec5 100644 --- a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/NumberCategory.groovy +++ b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/category/NumberCategory.groovy @@ -1,17 +1,15 @@ -package com.baeldung.category; - -import groovy.lang.Category +package com.baeldung.category @Category(Number) class NumberCategory { - public Number cube() { - return this*this*this + Number cube() { + return this**3 } - public int divideWithRoundUp(BigDecimal divisor, boolean isRoundUp) { + int divideWithRoundUp(BigDecimal divisor, boolean isRoundUp) { def mathRound = isRoundUp ? BigDecimal.ROUND_UP : BigDecimal.ROUND_DOWN - return (int)new BigDecimal(this).divide(divisor, 0, mathRound) + + return (int) new BigDecimal(this).divide(divisor, 0, mathRound) } - } diff --git a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy index 3ac88b7952..40c935ce08 100644 --- a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy +++ b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/determinedatatype/Person.groovy @@ -1,14 +1,19 @@ package com.baeldung.determinedatatype class Person { - - private int ageAsInt - private Double ageAsDouble - private String ageAsString - + + int ageAsInt + Double ageAsDouble + String ageAsString + Person() {} - Person(int ageAsInt) { this.ageAsInt = ageAsInt} - Person(Double ageAsDouble) { this.ageAsDouble = ageAsDouble} - Person(String ageAsString) { this.ageAsString = ageAsString} + + Person(int ageAsInt) { this.ageAsInt = ageAsInt } + + Person(Double ageAsDouble) { this.ageAsDouble = ageAsDouble } + + Person(String ageAsString) { this.ageAsString = ageAsString } +} + +class Student extends Person { } -class Student extends Person {} diff --git a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/Employee.groovy b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/Employee.groovy index f49d0f906b..cade7dab3c 100644 --- a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/Employee.groovy +++ b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/Employee.groovy @@ -1,18 +1,14 @@ package com.baeldung.metaprogramming -import groovy.transform.AutoClone -import groovy.transform.Canonical -import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString -import groovy.transform.TupleConstructor -import groovy.util.logging.* +import groovy.transform.* +import groovy.util.logging.Log -@Canonical +@ToString(includePackage = false, excludes = ['id']) @TupleConstructor @EqualsAndHashCode -@ToString(includePackage=false, excludes=['id']) -@Log -@AutoClone +@Canonical +@AutoClone(style = AutoCloneStyle.SIMPLE) +@Log class Employee { long id @@ -30,16 +26,15 @@ class Employee { def propertyMissing(String propertyName, propertyValue) { println "property '$propertyName' is not available" log.info "$propertyName is not available" - "property '$propertyName' is not available" + "property '$propertyName' with value '$propertyValue' is not available" } - def methodMissing(String methodName, def methodArgs) { + def methodMissing(String methodName, Object methodArgs) { log.info "$methodName is not defined" "method '$methodName' is not defined" } - + def logEmp() { log.info "Employee: $lastName, $firstName is of $age years age" } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/extension/BasicExtensions.groovy b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/extension/BasicExtensions.groovy index 0612ecb955..7e9f0111cd 100644 --- a/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/extension/BasicExtensions.groovy +++ b/core-groovy-modules/core-groovy-2/src/main/groovy/com/baeldung/metaprogramming/extension/BasicExtensions.groovy @@ -2,32 +2,31 @@ package com.baeldung.metaprogramming.extension import com.baeldung.metaprogramming.Employee -import java.time.LocalDate import java.time.Year class BasicExtensions { - + static int getYearOfBirth(Employee self) { return Year.now().value - self.age } - + static String capitalize(String self) { return self.substring(0, 1).toUpperCase() + self.substring(1) } static void printCounter(Integer self) { - while (self>0) { + while (self > 0) { println self self-- } } - + static Long square(Long self) { - return self*self + return self * self } - + static BigDecimal cube(BigDecimal self) { - return self*self*self + return self * self * self } - -} \ No newline at end of file + +} diff --git a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/category/CategoryUnitTest.groovy b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/category/CategoryUnitTest.groovy index a1f67b1e2e..370dfb316e 100644 --- a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/category/CategoryUnitTest.groovy +++ b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/category/CategoryUnitTest.groovy @@ -1,17 +1,17 @@ package com.baeldung.category -import groovy.time.* +import groovy.time.TimeCategory +import groovy.xml.DOMBuilder +import groovy.xml.QName +import groovy.xml.dom.DOMCategory + import java.text.SimpleDateFormat -import groovy.xml.* -import groovy.xml.dom.* -import com.baeldung.category.BaeldungCategory -import com.baeldung.category.NumberCategory class CategoryUnitTest extends GroovyTestCase { void test_whenUsingTimeCategory_thenOperationOnDate() { def jan_1_2019 = new Date("01/01/2019") - use (TimeCategory) { + use(TimeCategory) { assert jan_1_2019 + 10.seconds == new Date("01/01/2019 00:00:10") assert jan_1_2019 + 20.minutes == new Date("01/01/2019 00:20:00") @@ -30,7 +30,7 @@ class CategoryUnitTest extends GroovyTestCase { void test_whenUsingTimeCategory_thenOperationOnNumber() { SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy") - use (TimeCategory) { + use(TimeCategory) { assert sdf.format(5.days.from.now) == sdf.format(new Date() + 5.days) sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss") @@ -57,7 +57,7 @@ class CategoryUnitTest extends GroovyTestCase { def root = baeldungArticlesDom.documentElement - use (DOMCategory) { + use(DOMCategory) { assert root.article.size() == 2 def articles = root.article @@ -75,27 +75,26 @@ class CategoryUnitTest extends GroovyTestCase { assert root.article[2].title.text() == "Metaprogramming in Groovy" } } - + void test_whenUsingBaeldungCategory_thenCapitalizeString() { - use (BaeldungCategory) { + use(BaeldungCategory) { assert "norman".capitalize() == "Norman" - } + } } - + void test_whenUsingBaeldungCategory_thenOperationsOnNumber() { - use (BaeldungCategory) { + use(BaeldungCategory) { assert 50.toThePower(2) == 2500 assert 2.4.toThePower(4) == 33.1776 } } - + void test_whenUsingNumberCategory_thenOperationsOnNumber() { - use (NumberCategory) { + use(NumberCategory) { assert 3.cube() == 27 assert 25.divideWithRoundUp(6, true) == 5 assert 120.23.divideWithRoundUp(6.1, true) == 20 assert 150.9.divideWithRoundUp(12.1, false) == 12 } } - } diff --git a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy index 4c6589f207..414ba52fc5 100644 --- a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy +++ b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/determinedatatype/PersonTest.groovy @@ -1,56 +1,68 @@ package com.baeldung.determinedatatype -import org.junit.Assert -import org.junit.Test -import com.baeldung.determinedatatype.Person +import spock.lang.Specification -public class PersonTest { - - @Test - public void givenWhenParameterTypeIsInteger_thenReturnTrue() { +class PersonTest extends Specification { + + def "givenWhenParameterTypeIsIntegerThenReturnTrue"() { + given: Person personObj = new Person(10) - Assert.assertTrue(personObj.ageAsInt instanceof Integer) - } - - @Test - public void givenWhenParameterTypeIsDouble_thenReturnTrue() { - Person personObj = new Person(10.0) - Assert.assertTrue((personObj.ageAsDouble).getClass() == Double) - } - - @Test - public void givenWhenParameterTypeIsString_thenReturnTrue() { - Person personObj = new Person("10 years") - Assert.assertTrue(personObj.ageAsString.class == String) - } - - @Test - public void givenClassName_WhenParameterIsInteger_thenReturnTrue() { - Assert.assertTrue(Person.class.getDeclaredField('ageAsInt').type == int.class) - } - - @Test - public void givenWhenObjectIsInstanceOfType_thenReturnTrue() { - Person personObj = new Person() - Assert.assertTrue(personObj instanceof Person) + + expect: + personObj.ageAsInt.class == Integer } - @Test - public void givenWhenInstanceIsOfSubtype_thenReturnTrue() { + def "givenWhenParameterTypeIsDouble_thenReturnTrue"() { + given: + Person personObj = new Person(10.0) + + expect: + personObj.ageAsDouble.class == Double + } + + def "givenWhenParameterTypeIsString_thenReturnTrue"() { + given: + Person personObj = new Person("10 years") + + expect: + personObj.ageAsString.class == String + } + + def "givenClassName_WhenParameterIsInteger_thenReturnTrue"() { + expect: + Person.class.getDeclaredField('ageAsInt').type == int.class + } + + def "givenWhenObjectIsInstanceOfType_thenReturnTrue"() { + given: + Person personObj = new Person() + + expect: + personObj.class == Person + } + + def "givenWhenInstanceIsOfSubtype_thenReturnTrue"() { + given: Student studentObj = new Student() - Assert.assertTrue(studentObj in Person) + + expect: + studentObj.class.superclass == Person } - - @Test - public void givenGroovyList_WhenFindClassName_thenReturnTrue() { - def ageList = ['ageAsString','ageAsDouble', 10] - Assert.assertTrue(ageList.class == ArrayList) - Assert.assertTrue(ageList.getClass() == ArrayList) + + def "givenGroovyList_WhenFindClassName_thenReturnTrue"() { + given: + def ageList = ['ageAsString', 'ageAsDouble', 10] + + expect: + ageList.class == ArrayList + ageList.getClass() == ArrayList } - - @Test - public void givenGrooyMap_WhenFindClassName_thenReturnTrue() { - def ageMap = [ageAsString: '10 years', ageAsDouble: 10.0] - Assert.assertFalse(ageMap.class == LinkedHashMap) + + def "givenGroovyMap_WhenFindClassName_thenReturnTrue"() { + given: + def ageMap = [ageAsString: '10 years', ageAsDouble: 10.0] + + expect: + ageMap.getClass() == LinkedHashMap } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/metaprogramming/MetaprogrammingUnitTest.groovy b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/metaprogramming/MetaprogrammingUnitTest.groovy index 4a8631eb95..6959c97533 100644 --- a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/metaprogramming/MetaprogrammingUnitTest.groovy +++ b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/metaprogramming/MetaprogrammingUnitTest.groovy @@ -1,123 +1,163 @@ package com.baeldung.metaprogramming +import spock.lang.Specification -import java.time.LocalDate -import java.time.Period import java.time.Year -class MetaprogrammingUnitTest extends GroovyTestCase { +class MetaprogrammingUnitTest extends Specification { - Employee emp = new Employee(firstName: "Norman", lastName: "Lewis") + Employee emp - void testPropertyMissing() { - assert emp.address == "property 'address' is not available" + void setup() { + emp = new Employee(firstName: "Norman", lastName: "Lewis") } - void testMethodMissing() { + def "testPropertyMissing"() { + expect: + emp.address == "property 'address' is not available" + } + + def "testMethodMissing"() { + given: Employee emp = new Employee() - try { - emp.getFullName() - } catch(MissingMethodException e) { - println "method is not defined" - } - assert emp.getFullName() == "method 'getFullName' is not defined" + + expect: + emp.getFullName() == "method 'getFullName' is not defined" } - void testMetaClassProperty() { + def "testMetaClassProperty"() { + when: Employee.metaClass.address = "" - emp = new Employee(firstName: "Norman", lastName: "Lewis", address: "US") - assert emp.address == "US" + + and: + emp = new Employee(firstName: "Norman", + lastName: "Lewis", + address: "US") + + then: + emp.address == "US" } - void testMetaClassMethod() { + def "testMetaClassMethod"() { + when: emp.metaClass.getFullName = { "$lastName, $firstName" } - assert emp.getFullName() == "Lewis, Norman" + + then: + emp.getFullName() == "Lewis, Norman" } - void testMetaClassConstructor() { - try { - Employee emp = new Employee("Norman") - } catch(GroovyRuntimeException e) { - assert e.message == "Could not find matching constructor for: com.baeldung.metaprogramming.Employee(String)" - } + def "testOnlyNameConstructor"() { + when: + new Employee("Norman") + then: + thrown(GroovyRuntimeException) + } + + def "testMetaClassConstructor"() { + when: Employee.metaClass.constructor = { String firstName -> new Employee(firstName: firstName) } + and: Employee norman = new Employee("Norman") - assert norman.firstName == "Norman" - assert norman.lastName == null + + then: + norman.firstName == "Norman" + norman.lastName == null } - void testJavaMetaClass() { + def "testJavaMetaClass"() { + when: String.metaClass.capitalize = { String str -> str.substring(0, 1).toUpperCase() + str.substring(1) } - assert "norman".capitalize() == "Norman" + + and: + String.metaClass.static.joinWith = { String delimiter, String... args -> + String.join(delimiter, args) + } + + then: + "norman".capitalize() == "Norman" + String.joinWith(" -> ", "a", "b", "c") == "a -> b -> c" } - void testEmployeeExtension() { + def "testEmployeeExtension"() { + given: def age = 28 def expectedYearOfBirth = Year.now() - age Employee emp = new Employee(age: age) - assert emp.getYearOfBirth() == expectedYearOfBirth.value + + expect: + emp.getYearOfBirth() == expectedYearOfBirth.value } - void testJavaClassesExtensions() { + def "testJavaClassesExtensions"() { + when: 5.printCounter() - assert 40l.square() == 1600l - - assert (2.98).cube() == 26.463592 + then: + 40L.square() == 1600L + (2.98).cube() == 26.463592 } - void testStaticEmployeeExtension() { + def "testStaticEmployeeExtension"() { assert Employee.getDefaultObj().firstName == "firstName" assert Employee.getDefaultObj().lastName == "lastName" assert Employee.getDefaultObj().age == 20 } - void testToStringAnnotation() { - Employee employee = new Employee() - employee.id = 1 - employee.firstName = "norman" - employee.lastName = "lewis" - employee.age = 28 + def "testToStringAnnotation"() { + when: + Employee employee = new Employee().tap { + id = 1 + firstName = "norman" + lastName = "lewis" + age = 28 + } - assert employee.toString() == "Employee(norman, lewis, 28)" + then: + employee.toString() == "Employee(norman, lewis, 28)" } - void testTupleConstructorAnnotation() { + def "testTupleConstructorAnnotation"() { + when: Employee norman = new Employee(1, "norman", "lewis", 28) - assert norman.toString() == "Employee(norman, lewis, 28)" - Employee snape = new Employee(2, "snape") - assert snape.toString() == "Employee(snape, null, 0)" + then: + norman.toString() == "Employee(norman, lewis, 28)" + snape.toString() == "Employee(snape, null, 0)" } - - void testEqualsAndHashCodeAnnotation() { + + def "testEqualsAndHashCodeAnnotation"() { + when: Employee norman = new Employee(1, "norman", "lewis", 28) Employee normanCopy = new Employee(1, "norman", "lewis", 28) - assert norman.equals(normanCopy) - assert norman.hashCode() == normanCopy.hashCode() - } - - void testAutoCloneAnnotation() { - try { - Employee norman = new Employee(1, "norman", "lewis", 28) - def normanCopy = norman.clone() - assert norman == normanCopy - } catch(CloneNotSupportedException e) { - e.printStackTrace() - } + + then: + norman == normanCopy + norman.hashCode() == normanCopy.hashCode() } - void testLoggingAnnotation() { + def "testAutoCloneAnnotation"() { + given: + Employee norman = new Employee(1, "norman", "lewis", 28) + + when: + def normanCopy = norman.clone() + + then: + norman == normanCopy + } + + def "testLoggingAnnotation"() { + given: Employee employee = new Employee(1, "Norman", "Lewis", 28) - employee.logEmp() + employee.logEmp() // INFO: Employee: Lewis, Norman is of 28 years age } } diff --git a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/templateengine/TemplateEnginesUnitTest.groovy b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/templateengine/TemplateEnginesUnitTest.groovy index 1846ae664c..800f3b119e 100644 --- a/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/templateengine/TemplateEnginesUnitTest.groovy +++ b/core-groovy-modules/core-groovy-2/src/test/groovy/com/baeldung/templateengine/TemplateEnginesUnitTest.groovy @@ -1,48 +1,62 @@ package com.baeldung.templateengine +import groovy.text.GStringTemplateEngine import groovy.text.SimpleTemplateEngine import groovy.text.StreamingTemplateEngine -import groovy.text.GStringTemplateEngine -import groovy.text.XmlTemplateEngine import groovy.text.XmlTemplateEngine import groovy.text.markup.MarkupTemplateEngine import groovy.text.markup.TemplateConfiguration +import spock.lang.Specification -class TemplateEnginesUnitTest extends GroovyTestCase { - - def bindMap = [user: "Norman", signature: "Baeldung"] - - void testSimpleTemplateEngine() { +class TemplateEnginesUnitTest extends Specification { + + final Map BIND_MAP = [user: "Norman", signature: "Baeldung"] + + def "testSimpleTemplateEngine"() { + given: def smsTemplate = 'Dear <% print user %>, Thanks for reading our Article. ${signature}' - def smsText = new SimpleTemplateEngine().createTemplate(smsTemplate).make(bindMap) - assert smsText.toString() == "Dear Norman, Thanks for reading our Article. Baeldung" + when: + def smsText = new SimpleTemplateEngine().createTemplate(smsTemplate).make(BIND_MAP) + + then: + smsText.toString() == "Dear Norman, Thanks for reading our Article. Baeldung" } - - void testStreamingTemplateEngine() { + + def "testStreamingTemplateEngine"() { + given: def articleEmailTemplate = new File('src/main/resources/articleEmail.template') - bindMap.articleText = """1. Overview -This is a tutorial article on Template Engines""" //can be a string larger than 64k - - def articleEmailText = new StreamingTemplateEngine().createTemplate(articleEmailTemplate).make(bindMap) - - assert articleEmailText.toString() == """Dear Norman, -Please read the requested article below. -1. Overview -This is a tutorial article on Template Engines -From, -Baeldung""" - + //can be a string larger than 64k + BIND_MAP.articleText = """|1. Overview + |This is a tutorial article on Template Engines""".stripMargin() + + when: + def articleEmailText = new StreamingTemplateEngine().createTemplate(articleEmailTemplate).make(BIND_MAP) + + then: + articleEmailText.toString() == """|Dear Norman, + |Please read the requested article below. + |1. Overview + |This is a tutorial article on Template Engines + |From, + |Baeldung""".stripMargin() } - - void testGStringTemplateEngine() { + + def "testGStringTemplateEngine"() { + given: def emailTemplate = new File('src/main/resources/email.template') - def emailText = new GStringTemplateEngine().createTemplate(emailTemplate).make(bindMap) - - assert emailText.toString() == "Dear Norman,\nThanks for subscribing our services.\nBaeldung" + + when: + def emailText = new GStringTemplateEngine().createTemplate(emailTemplate).make(BIND_MAP) + + then: + emailText.toString() == """|Dear Norman, + |Thanks for subscribing our services. + |Baeldung""".stripMargin() } - - void testXmlTemplateEngine() { + + def "testXmlTemplateEngine"() { + given: def emailXmlTemplate = ''' def emailContent = "Thanks for subscribing our services." @@ -51,11 +65,16 @@ Baeldung""" ${signature} ''' - def emailXml = new XmlTemplateEngine().createTemplate(emailXmlTemplate).make(bindMap) + + when: + def emailXml = new XmlTemplateEngine().createTemplate(emailXmlTemplate).make(BIND_MAP) + + then: println emailXml.toString() } - - void testMarkupTemplateEngineHtml() { + + def "testMarkupTemplateEngineHtml"() { + given: def emailHtmlTemplate = """html { head { title('Service Subscription Email') @@ -66,14 +85,16 @@ Baeldung""" p('Baeldung') } }""" - - + + when: def emailHtml = new MarkupTemplateEngine().createTemplate(emailHtmlTemplate).make() + + then: println emailHtml.toString() - } - - void testMarkupTemplateEngineXml() { + + def "testMarkupTemplateEngineXml"() { + given: def emailXmlTemplate = """xmlDeclaration() xs{ email { @@ -83,14 +104,18 @@ Baeldung""" } } """ - TemplateConfiguration config = new TemplateConfiguration() - config.autoIndent = true - config.autoEscape = true - config.autoNewLine = true + TemplateConfiguration config = new TemplateConfiguration().with { + autoIndent = true + autoEscape = true + autoNewLine = true + return it + } + + when: def emailXml = new MarkupTemplateEngine(config).createTemplate(emailXmlTemplate).make() - + + then: println emailXml.toString() } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy-collections/pom.xml b/core-groovy-modules/core-groovy-collections/pom.xml index 5269121140..6d43ce7d18 100644 --- a/core-groovy-modules/core-groovy-collections/pom.xml +++ b/core-groovy-modules/core-groovy-collections/pom.xml @@ -113,9 +113,11 @@ - central - http://jcenter.bintray.com + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ - \ No newline at end of file + + diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/ListFindUnitTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/ListFindUnitTest.groovy index 82a2138be4..325cf18c5f 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/ListFindUnitTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/ListFindUnitTest.groovy @@ -1,58 +1,57 @@ package com.baeldung.find -import com.baeldung.find.Person -import org.junit.Test +import spock.lang.Specification -import static org.junit.Assert.* +class ListFindUnitTest extends Specification { -class ListFindUnitTest { - - private final personList = [ - new Person("Regina", "Fitzpatrick", 25), - new Person("Abagail", "Ballard", 26), - new Person("Lucian", "Walter", 30), + final personList = [ + new Person("Regina", "Fitzpatrick", 25), + new Person("Abagail", "Ballard", 26), + new Person("Lucian", "Walter", 30), ] - @Test - void whenListContainsElement_thenCheckReturnsTrue() { + def "whenListContainsElement_thenCheckReturnsTrue"() { + given: def list = ['a', 'b', 'c'] - assertTrue(list.indexOf('a') > -1) - assertTrue(list.contains('a')) + expect: + list.indexOf('a') > -1 + list.contains('a') } - @Test - void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() { + def "whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue"() { + given: def list = ['a', 'b', 'c'] - assertTrue('a' in list) + expect: + 'a' in list } - @Test - void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() { - assertTrue(personList.stream().anyMatch {it.age > 20}) - assertFalse(personList.stream().allMatch {it.age < 30}) + def "givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList"() { + expect: + personList.stream().anyMatch { it.age > 20 } + !personList.stream().allMatch { it.age < 30 } } - @Test - void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() { - assertTrue(personList.any {it.age > 20}) - assertFalse(personList.every {it.age < 30}) + def "givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList"() { + expect: + personList.any { it.age > 20 } + !personList.every { it.age < 30 } } - @Test - void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() { - assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent()) - assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent()) - assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3) - assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty()) + def "givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements"() { + expect: + personList.stream().filter { it.age > 20 }.findAny().isPresent() + !personList.stream().filter { it.age > 30 }.findAny().isPresent() + personList.stream().filter { it.age > 20 }.findAll().size() == 3 + personList.stream().filter { it.age > 30 }.findAll().isEmpty() } - @Test - void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() { - assertNotNull(personList.find {it.age > 20}) - assertNull(personList.find {it.age > 30}) - assertTrue(personList.findAll {it.age > 20}.size() == 3) - assertTrue(personList.findAll {it.age > 30}.isEmpty()) + def "givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements"() { + expect: + personList.find { it.age > 20 } == new Person("Regina", "Fitzpatrick", 25) + personList.find { it.age > 30 } == null + personList.findAll { it.age > 20 }.size() == 3 + personList.findAll { it.age > 30 }.isEmpty() } } diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/MapFindUnitTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/MapFindUnitTest.groovy index 16e231182b..74d85ad71b 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/MapFindUnitTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/MapFindUnitTest.groovy @@ -1,76 +1,81 @@ package com.baeldung.find -import com.baeldung.find.Person -import org.junit.Test +import spock.lang.Specification -import static org.junit.Assert.* +class MapFindUnitTest extends Specification { -class MapFindUnitTest { - - private final personMap = [ - Regina : new Person("Regina", "Fitzpatrick", 25), - Abagail: new Person("Abagail", "Ballard", 26), - Lucian : new Person("Lucian", "Walter", 30) + final personMap = [ + Regina: new Person("Regina", "Fitzpatrick", 25), + Abagail: new Person("Abagail", "Ballard", 26), + Lucian: new Person("Lucian", "Walter", 30) ] - @Test - void whenMapContainsKeyElement_thenCheckReturnsTrue() { + def "whenMapContainsKeyElement_thenCheckReturnsTrue"() { + given: def map = [a: 'd', b: 'e', c: 'f'] - assertTrue(map.containsKey('a')) - assertFalse(map.containsKey('e')) - assertTrue(map.containsValue('e')) + expect: + map.containsKey('a') + !map.containsKey('e') + map.containsValue('e') } - @Test - void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() { + def "whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue"() { + given: def map = [a: 'd', b: 'e', c: 'f'] - assertTrue('a' in map) - assertFalse('f' in map) + expect: + 'a' in map + 'f' !in map } - @Test - void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() { + def "whenMapContainsFalseBooleanValues_thenCheckReturnsFalse"() { + given: def map = [a: true, b: false, c: null] - assertTrue(map.containsKey('b')) - assertTrue('a' in map) - assertFalse('b' in map) - assertFalse('c' in map) + expect: + map.containsKey('b') + 'a' in map + 'b' !in map // get value of key 'b' and does the assertion + 'c' !in map } - @Test - void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() { - assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"}) - assertFalse(personMap.keySet().stream().allMatch {it == "Albert"}) - assertFalse(personMap.values().stream().allMatch {it.age < 30}) - assertTrue(personMap.entrySet().stream().anyMatch {it.key == "Abagail" && it.value.lastname == "Ballard"}) + def "givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap"() { + expect: + personMap.keySet().stream() + .anyMatch { it == "Regina" } + !personMap.keySet().stream() + .allMatch { it == "Albert" } + !personMap.values().stream() + .allMatch { it.age < 30 } + personMap.entrySet().stream() + .anyMatch { it.key == "Abagail" && it.value.lastname == "Ballard" } } - @Test - void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() { - assertTrue(personMap.keySet().any {it == "Regina"}) - assertFalse(personMap.keySet().every {it == "Albert"}) - assertFalse(personMap.values().every {it.age < 30}) - assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"}) + def "givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap"() { + expect: + personMap.keySet().any { it == "Regina" } + !personMap.keySet().every { it == "Albert" } + !personMap.values().every { it.age < 30 } + personMap.any { firstname, person -> firstname == "Abagail" && person.lastname == "Ballard" } } - @Test - void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() { - assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"}) - assertTrue(personMap.findAll {it.value.age > 20}.size() == 3) + def "givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements"() { + expect: + personMap.find { it.key == "Abagail" && it.value.lastname == "Ballard" } + personMap.findAll { it.value.age > 20 }.size() == 3 } - @Test - void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() { - assertTrue( - personMap.entrySet().stream() - .filter {it.key == "Abagail" && it.value.lastname == "Ballard"} - .findAny().isPresent()) - assertTrue( - personMap.entrySet().stream() - .filter {it.value.age > 20} - .findAll().size() == 3) + def "givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements"() { + expect: + personMap.entrySet().stream() + .filter { it.key == "Abagail" && it.value.lastname == "Ballard" } + .findAny() + .isPresent() + + personMap.entrySet().stream() + .filter { it.value.age > 20 } + .findAll() + .size() == 3 } } diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/Person.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/Person.groovy index e65826363a..a9266c4079 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/Person.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/Person.groovy @@ -1,37 +1,10 @@ package com.baeldung.find +import groovy.transform.Canonical + +@Canonical class Person { - private String firstname - private String lastname - private Integer age - - Person(String firstname, String lastname, Integer age) { - this.firstname = firstname - this.lastname = lastname - this.age = age - } - - String getFirstname() { - return firstname - } - - void setFirstname(String firstname) { - this.firstname = firstname - } - - String getLastname() { - return lastname - } - - void setLastname(String lastname) { - this.lastname = lastname - } - - Integer getAge() { - return age - } - - void setAge(Integer age) { - this.age = age - } + String firstname + String lastname + Integer age } diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/SetFindUnitTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/SetFindUnitTest.groovy index d2d03d5427..d82cf689d3 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/SetFindUnitTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/find/SetFindUnitTest.groovy @@ -1,16 +1,15 @@ package com.baeldung.find -import org.junit.Test +import spock.lang.Specification -import static org.junit.Assert.assertTrue +class SetFindUnitTest extends Specification { -class SetFindUnitTest { - - @Test - void whenSetContainsElement_thenCheckReturnsTrue() { + def "whenSetContainsElement_thenCheckReturnsTrue"() { + given: def set = ['a', 'b', 'c'] as Set - assertTrue(set.contains('a')) - assertTrue('a' in set) + expect: + set.contains('a') + 'a' in set } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/iteratemap/IterateMapUnitTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/iteratemap/IterateMapUnitTest.groovy index 970203ce85..4cbcaee2d8 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/iteratemap/IterateMapUnitTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/iteratemap/IterateMapUnitTest.groovy @@ -1,85 +1,54 @@ package com.baeldung.iteratemap -import com.baeldung.find.Person -import org.junit.Test +import spock.lang.Specification -import static org.junit.Assert.* +class IterateMapUnitTest extends Specification { -class IterateMapUnitTest { - - @Test - void whenUsingEach_thenMapIsIterated() { - def map = [ - 'FF0000' : 'Red', - '00FF00' : 'Lime', - '0000FF' : 'Blue', - 'FFFF00' : 'Yellow' - ] + final Map map = [ + 'FF0000': 'Red', + '00FF00': 'Lime', + '0000FF': 'Blue', + 'FFFF00': 'Yellow', + 'E6E6FA': 'Lavender', + 'D8BFD8': 'Thistle', + 'DDA0DD': 'Plum', + ] + def "whenUsingEach_thenMapIsIterated"() { + expect: map.each { println "Hex Code: $it.key = Color Name: $it.value" } } - @Test - void whenUsingEachWithEntry_thenMapIsIterated() { - def map = [ - 'E6E6FA' : 'Lavender', - 'D8BFD8' : 'Thistle', - 'DDA0DD' : 'Plum', - ] - + def "whenUsingEachWithEntry_thenMapIsIterated"() { + expect: map.each { entry -> println "Hex Code: $entry.key = Color Name: $entry.value" } } - @Test - void whenUsingEachWithKeyAndValue_thenMapIsIterated() { - def map = [ - '000000' : 'Black', - 'FFFFFF' : 'White', - '808080' : 'Gray' - ] - + def "whenUsingEachWithKeyAndValue_thenMapIsIterated"() { + expect: map.each { key, val -> println "Hex Code: $key = Color Name $val" } } - @Test - void whenUsingEachWithIndexAndEntry_thenMapIsIterated() { - def map = [ - '800080' : 'Purple', - '4B0082' : 'Indigo', - '6A5ACD' : 'Slate Blue' - ] - + def "whenUsingEachWithIndexAndEntry_thenMapIsIterated"() { + expect: map.eachWithIndex { entry, index -> - def indent = ((index == 0 || index % 2 == 0) ? " " : "") + def indent = index % 2 == 0 ? " " : "" println "$indent Hex Code: $entry.key = Color Name: $entry.value" } } - @Test - void whenUsingEachWithIndexAndKeyAndValue_thenMapIsIterated() { - def map = [ - 'FFA07A' : 'Light Salmon', - 'FF7F50' : 'Coral', - 'FF6347' : 'Tomato', - 'FF4500' : 'Orange Red' - ] - + def "whenUsingEachWithIndexAndKeyAndValue_thenMapIsIterated"() { + expect: map.eachWithIndex { key, val, index -> - def indent = ((index == 0 || index % 2 == 0) ? " " : "") + def indent = index % 2 == 0 ? " " : "" println "$indent Hex Code: $key = Color Name: $val" } } - @Test - void whenUsingForLoop_thenMapIsIterated() { - def map = [ - '2E8B57' : 'Seagreen', - '228B22' : 'Forest Green', - '008000' : 'Green' - ] - + def "whenUsingForLoop_thenMapIsIterated"() { + expect: for (entry in map) { println "Hex Code: $entry.key = Color Name: $entry.value" } diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy index e4c0a0c177..5baa19f360 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy @@ -1,173 +1,171 @@ package com.baeldung.lists -import static groovy.test.GroovyAssert.* -import org.junit.Test +import spock.lang.Specification -class ListUnitTest { - - @Test - void testCreateList() { +class ListUnitTest extends Specification { + def "testCreateList"() { + when: def list = [1, 2, 3] - assertNotNull(list) - def listMix = ['A', "b", 1, true] - assertTrue(listMix == ['A', "b", 1, true]) - def linkedList = [1, 2, 3] as LinkedList - assertTrue(linkedList instanceof LinkedList) - ArrayList arrList = [1, 2, 3] - assertTrue(arrList.class == ArrayList) - def copyList = new ArrayList(arrList) - assertTrue(copyList == arrList) - def cloneList = arrList.clone() - assertTrue(cloneList == arrList) + + then: + list + listMix == ['A', "b", 1, true] + linkedList instanceof LinkedList + arrList.class == ArrayList + copyList == arrList + cloneList == arrList } - @Test - void testCreateEmptyList() { - + def "testCreateEmptyList"() { + when: def emptyList = [] - assertTrue(emptyList.size() == 0) + + then: + emptyList.isEmpty() } - @Test - void testCompareTwoLists() { - + def "testCompareTwoLists"() { + when: def list1 = [5, 6.0, 'p'] def list2 = [5, 6.0, 'p'] - assertTrue(list1 == list2) + + then: + list1 == list2 } - @Test - void testGetItemsFromList(){ - + def "testGetItemsFromList"() { + when: def list = ["Hello", "World"] - assertTrue(list.get(1) == "World") - assertTrue(list[1] == "World") - assertTrue(list[-1] == "World") - assertTrue(list.getAt(1) == "World") - assertTrue(list.getAt(-2) == "Hello") + then: + list.get(1) == "World" + list[1] == "World" + list[-1] == "World" + list.getAt(1) == "World" + list.getAt(-2) == "Hello" } - @Test - void testAddItemsToList() { + def "testAddItemsToList"() { + given: + def list1 = [] + def list2 = [] + def list3 = [1, 2] - def list = [] + when: + list1 << 1 // [1] + list1.add("Apple") // [1, "Apple"] - list << 1 - list.add("Apple") - assertTrue(list == [1, "Apple"]) + list2[2] = "Box" // [null, "Box"] + list2[4] = true // [null, "Box", null, true] - list[2] = "Box" - list[4] = true - assertTrue(list == [1, "Apple", "Box", null, true]) + list1.add(1, 6.0) // [1, 6.0, "Apple"] + list1 += list3 // [1, 6.0, "Apple", 1, 2] + list1 += 12 // [1, 6.0, "Apple", 1, 2, 12] - list.add(1, 6.0) - assertTrue(list == [1, 6.0, "Apple", "Box", null, true]) - - def list2 = [1, 2] - list += list2 - list += 12 - assertTrue(list == [1, 6.0, "Apple", "Box", null, true, 1, 2, 12]) + then: + list1 == [1, 6.0, "Apple", 1, 2, 12] + list2 == [null, null, "Box", null, true] } - @Test - void testUpdateItemsInList() { + def "testUpdateItemsInList"() { + given: + def list = [1, "Apple", 80, "App"] - def list =[1, "Apple", 80, "App"] + when: list[1] = "Box" - list.set(2,90) - assertTrue(list == [1, "Box", 90, "App"]) + list.set(2, 90) + + then: + list == [1, "Box", 90, "App"] } - @Test - void testRemoveItemsFromList(){ - + def "testRemoveItemsFromList"() { + given: def list = [1, 2, 3, 4, 5, 5, 6, 6, 7] - list.remove(3) - assertTrue(list == [1, 2, 3, 5, 5, 6, 6, 7]) + when: + list.remove(3) // [1, 2, 3, 5, 5, 6, 6, 7] + list.removeElement(5) // [1, 2, 3, 5, 6, 6, 7] + list = list - 6 // [1, 2, 3, 5, 7] - list.removeElement(5) - assertTrue(list == [1, 2, 3, 5, 6, 6, 7]) - - assertTrue(list - 6 == [1, 2, 3, 5, 7]) + then: + list == [1, 2, 3, 5, 7] } - @Test - void testIteratingOnAList(){ - + def "testIteratingOnAList"() { + given: def list = [1, "App", 3, 4] - list.each{ println it * 2} - list.eachWithIndex{ it, i -> println "$i : $it" } + expect: + list.each { println it * 2 } + list.eachWithIndex { it, i -> println "$i : $it" } } - @Test - void testCollectingToAnotherList(){ - + def "testCollectingToAnotherList"() { + given: def list = ["Kay", "Henry", "Justin", "Tom"] - assertTrue(list.collect{"Hi " + it} == ["Hi Kay", "Hi Henry", "Hi Justin", "Hi Tom"]) + + when: + def collect = list.collect { "Hi " + it } + + then: + collect == ["Hi Kay", "Hi Henry", "Hi Justin", "Hi Tom"] } - @Test - void testJoinItemsInAList(){ - assertTrue(["One", "Two", "Three"].join(",") == "One,Two,Three") + def "testJoinItemsInAList"() { + expect: + ["One", "Two", "Three"].join(",") == "One,Two,Three" } - @Test - void testFilteringOnLists(){ + def "testFilteringOnLists"() { + given: def filterList = [2, 1, 3, 4, 5, 6, 76] - - assertTrue(filterList.find{it > 3} == 4) - - assertTrue(filterList.findAll{it > 3} == [4, 5, 6, 76]) - - assertTrue(filterList.findAll{ it instanceof Number} == [2, 1, 3, 4, 5, 6, 76]) - - assertTrue(filterList.grep( Number )== [2, 1, 3, 4, 5, 6, 76]) - - assertTrue(filterList.grep{ it> 6 }== [76]) - def conditionList = [2, 1, 3, 4, 5, 6, 76] - assertFalse(conditionList.every{ it < 6}) - - assertTrue(conditionList.any{ it%2 == 0}) + expect: + filterList.find { it > 3 } == 4 + filterList.findAll { it > 3 } == [4, 5, 6, 76] + filterList.findAll { it instanceof Number } == [2, 1, 3, 4, 5, 6, 76] + filterList.grep(Number) == [2, 1, 3, 4, 5, 6, 76] + filterList.grep { it > 6 } == [76] + !(conditionList.every { it < 6 }) + conditionList.any { it % 2 == 0 } } - @Test - void testGetUniqueItemsInAList(){ - assertTrue([1, 3, 3, 4].toUnique() == [1, 3, 4]) - + def "testGetUniqueItemsInAList"() { + given: def uniqueList = [1, 3, 3, 4] - uniqueList.unique() - assertTrue(uniqueList == [1, 3, 4]) - assertTrue(["A", "B", "Ba", "Bat", "Cat"].toUnique{ it.size()} == ["A", "Ba", "Bat"]) + when: + uniqueList.unique(true) + + then: + [1, 3, 3, 4].toUnique() == [1, 3, 4] + uniqueList == [1, 3, 4] + ["A", "B", "Ba", "Bat", "Cat"].toUnique { it.size() } == ["A", "Ba", "Bat"] } - @Test - void testSorting(){ - - assertTrue([1, 2, 1, 0].sort() == [0, 1, 1, 2]) - Comparator mc = {a,b -> a == b? 0: a < b? 1 : -1} - + def "testSorting"() { + given: + Comparator naturalOrder = { a, b -> a == b ? 0 : a < b ? -1 : 1 } def list = [1, 2, 1, 0] - list.sort(mc) - assertTrue(list == [2, 1, 1, 0]) - def strList = ["na", "ppp", "as"] - assertTrue(strList.max() == "ppp") - - Comparator minc = {a,b -> a == b? 0: a < b? -1 : 1} def numberList = [3, 2, 0, 7] - assertTrue(numberList.min(minc) == 0) + + when: + list.sort(naturalOrder.reversed()) + + then: + list == [2, 1, 1, 0] + strList.max() == "ppp" + [1, 2, 1, 0].sort() == [0, 1, 1, 2] + numberList.min(naturalOrder) == 0 } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/maps/MapTest.groovy b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/maps/MapTest.groovy index deb552c420..9529330089 100644 --- a/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/maps/MapTest.groovy +++ b/core-groovy-modules/core-groovy-collections/src/test/groovy/com/baeldung/maps/MapTest.groovy @@ -1,148 +1,160 @@ -package com.baeldung.maps; +package com.baeldung.maps -import static groovy.test.GroovyAssert.* -import org.junit.Test +import spock.lang.Specification -class MapTest{ - - @Test - void createMap() { +class MapTest extends Specification { + def "createMap"() { + when: def emptyMap = [:] - assertNotNull(emptyMap) + def map = [name: "Jerry", age: 42, city: "New York"] - assertTrue(emptyMap instanceof java.util.LinkedHashMap) - - def map = [name:"Jerry", age: 42, city: "New York"] - assertTrue(map.size() == 3) + then: + emptyMap != null + emptyMap instanceof java.util.LinkedHashMap + map.size() == 3 } - @Test - void addItemsToMap() { - - def map = [name:"Jerry"] - - map["age"] = 42 - - map.city = "New York" - + def "addItemsToMap"() { + given: + def map = [name: "Jerry"] def hobbyLiteral = "hobby" def hobbyMap = [(hobbyLiteral): "Singing"] + def appendToMap = [:] + + when: + map["age"] = 42 + map.city = "New York" + map.putAll(hobbyMap) - assertTrue(map == [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]) - assertTrue(hobbyMap.hobby == "Singing") - assertTrue(hobbyMap[hobbyLiteral] == "Singing") - - map.plus([1:20]) // returns new map + appendToMap.plus([1: 20]) + appendToMap << [2: 30] - map << [2:30] + then: + map == [name: "Jerry", age: 42, city: "New York", hobby: "Singing"] + hobbyMap.hobby == "Singing" + hobbyMap[hobbyLiteral] == "Singing" + + appendToMap == [2: 30] // plus(Map) returns new instance of Map } - @Test - void getItemsFromMap() { - - def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] - - assertTrue(map["name"] == "Jerry") - - assertTrue(map.name == "Jerry") - + def "getItemsFromMap"() { + when: + def map = [name: "Jerry", age: 42, city: "New York", hobby: "Singing"] def propertyAge = "age" - assertTrue(map[propertyAge] == 42) + + then: + map["name"] == "Jerry" + map.name == "Jerry" + map[propertyAge] == 42 + map."$propertyAge" == 42 } - @Test - void removeItemsFromMap() { + def "removeItemsFromMap"() { + given: + def map = [1: 20, a: 30, 2: 42, 4: 34, ba: 67, 6: 39, 7: 49] + def removeAllKeysOfTypeString = [1: 20, a: 30, ba: 67, 6: 39, 7: 49] + def retainAllEntriesWhereValueIsEven = [1: 20, a: 30, ba: 67, 6: 39, 7: 49] - def map = [1:20, a:30, 2:42, 4:34, ba:67, 6:39, 7:49] + when: + def minusMap = map - [2: 42, 4: 34] + removeAllKeysOfTypeString.removeAll { it.key instanceof String } + retainAllEntriesWhereValueIsEven.retainAll { it.value % 2 == 0 } - def minusMap = map.minus([2:42, 4:34]); - assertTrue(minusMap == [1:20, a:30, ba:67, 6:39, 7:49]) - - minusMap.removeAll{it -> it.key instanceof String} - assertTrue( minusMap == [ 1:20, 6:39, 7:49]) - - minusMap.retainAll{it -> it.value %2 == 0} - assertTrue( minusMap == [1:20]) + then: + minusMap == [1: 20, a: 30, ba: 67, 6: 39, 7: 49] + removeAllKeysOfTypeString == [1: 20, 6: 39, 7: 49] + retainAllEntriesWhereValueIsEven == [1: 20, a: 30] } - @Test - void iteratingOnMaps(){ - def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + def "iteratingOnMaps"() { + when: + def map = [name: "Jerry", age: 42, city: "New York", hobby: "Singing"] - map.each{ entry -> println "$entry.key: $entry.value" } - - map.eachWithIndex{ entry, i -> println "$i $entry.key: $entry.value" } - - map.eachWithIndex{ key, value, i -> println "$i $key: $value" } + then: + map.each { entry -> println "$entry.key: $entry.value" } + map.eachWithIndex { entry, i -> println "$i $entry.key: $entry.value" } + map.eachWithIndex { key, value, i -> println "$i $key: $value" } } - @Test - void filteringAndSearchingMaps(){ - def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + def "filteringAndSearchingMaps"() { + given: + def map = [name: "Jerry", age: 42, city: "New York", hobby: "Singing"] - assertTrue(map.find{ it.value == "New York"}.key == "city") + when: + def find = map.find { it.value == "New York" } + def finaAll = map.findAll { it.value == "New York" } + def grep = map.grep { it.value == "New York" } + def every = map.every { it -> it.value instanceof String } + def any = map.any { it -> it.value instanceof String } - assertTrue(map.findAll{ it.value == "New York"} == [city : "New York"]) + then: + find.key == "city" - map.grep{it.value == "New York"}.each{ it -> assertTrue(it.key == "city" && it.value == "New York")} + finaAll instanceof Map + finaAll == [city: "New York"] - assertTrue(map.every{it -> it.value instanceof String} == false) + grep instanceof Collection + grep.each { it -> assert it.key == "city" && it.value == "New York" } - assertTrue(map.any{it -> it.value instanceof String} == true) + every instanceof Boolean + !every + + any instanceof Boolean + any } - @Test - void collect(){ - - def map = [1: [name:"Jerry", age: 42, city: "New York"], - 2: [name:"Long", age: 25, city: "New York"], - 3: [name:"Dustin", age: 29, city: "New York"], - 4: [name:"Dustin", age: 34, city: "New York"]] - - def names = map.collect{entry -> entry.value.name} // returns only list - assertTrue(names == ["Jerry", "Long", "Dustin", "Dustin"]) - - def uniqueNames = map.collect([] as HashSet){entry -> entry.value.name} - assertTrue(uniqueNames == ["Jerry", "Long", "Dustin"] as Set) - - def idNames = map.collectEntries{key, value -> [key, value.name]} - assertTrue(idNames == [1:"Jerry", 2: "Long", 3:"Dustin", 4: "Dustin"]) - - def below30Names = map.findAll{it.value.age < 30}.collect{key, value -> value.name} - assertTrue(below30Names == ["Long", "Dustin"]) + def "collect"() { + given: + def map = [ + 1: [name: "Jerry", age: 42, city: "New York"], + 2: [name: "Long", age: 25, city: "New York"], + 3: [name: "Dustin", age: 29, city: "New York"], + 4: [name: "Dustin", age: 34, city: "New York"] + ] + when: + def names = map.collect { entry -> entry.value.name } // returns only list + def uniqueNames = map.collect { entry -> entry.value.name } + .unique() + def idNames = map.collectEntries { key, value -> [key, value.name] } + def below30Names = map.findAll { it.value.age < 30 } + .collect { key, value -> value.name } + then: + names == ["Jerry", "Long", "Dustin", "Dustin"] + uniqueNames == ["Jerry", "Long", "Dustin"] + idNames == [1: "Jerry", 2: "Long", 3: "Dustin", 4: "Dustin"] + below30Names == ["Long", "Dustin"] } - @Test - void group(){ - def map = [1:20, 2: 40, 3: 11, 4: 93] - - def subMap = map.groupBy{it.value % 2} - println subMap - assertTrue(subMap == [0:[1:20, 2:40 ], 1:[3:11, 4:93]]) + def "group"() { + given: + def map = [1: 20, 2: 40, 3: 11, 4: 93] + when: + def subMap = map.groupBy { it.value % 2 } def keySubMap = map.subMap([1, 2]) - assertTrue(keySubMap == [1:20, 2:40]) + then: + subMap == [0: [1: 20, 2: 40], 1: [3: 11, 4: 93]] + keySubMap == [1: 20, 2: 40] } - @Test - void sorting(){ - def map = [ab:20, a: 40, cb: 11, ba: 93] + def "sorting"() { + given: + def map = [ab: 20, a: 40, cb: 11, ba: 93] + when: def naturallyOrderedMap = map.sort() - assertTrue([a:40, ab:20, ba:93, cb:11] == naturallyOrderedMap) - def compSortedMap = map.sort({ k1, k2 -> k1 <=> k2 } as Comparator) - assertTrue([a:40, ab:20, ba:93, cb:11] == compSortedMap) - def cloSortedMap = map.sort({ it1, it2 -> it1.value <=> it1.value }) - assertTrue([cb:11, ab:20, a:40, ba:93] == cloSortedMap) + then: + naturallyOrderedMap == [a: 40, ab: 20, ba: 93, cb: 11] + compSortedMap == [a: 40, ab: 20, ba: 93, cb: 11] + cloSortedMap == [cb: 11, ab: 20, a: 40, ba: 93] } - } diff --git a/core-groovy-modules/core-groovy-strings/pom.xml b/core-groovy-modules/core-groovy-strings/pom.xml index e51ebfbd4b..fac0f25219 100644 --- a/core-groovy-modules/core-groovy-strings/pom.xml +++ b/core-groovy-modules/core-groovy-strings/pom.xml @@ -103,9 +103,10 @@ - central - https://jcenter.bintray.com + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ - \ No newline at end of file + diff --git a/core-groovy-modules/core-groovy-strings/src/test/groovy/com/baeldung/removeprefix/RemovePrefixTest.groovy b/core-groovy-modules/core-groovy-strings/src/test/groovy/com/baeldung/removeprefix/RemovePrefixTest.groovy index 61b81fe1b2..8b7ce9c355 100644 --- a/core-groovy-modules/core-groovy-strings/src/test/groovy/com/baeldung/removeprefix/RemovePrefixTest.groovy +++ b/core-groovy-modules/core-groovy-strings/src/test/groovy/com/baeldung/removeprefix/RemovePrefixTest.groovy @@ -1,70 +1,74 @@ package com.baeldung.removeprefix -import org.junit.Assert -import org.junit.Test +import spock.lang.Specification -class RemovePrefixTest { +class RemovePrefixTest extends Specification { - - @Test - public void whenCasePrefixIsRemoved_thenReturnTrue() { + def "whenCasePrefixIsRemoved_thenReturnTrue"() { + given: def trimPrefix = { it.startsWith('Groovy-') ? it.minus('Groovy-') : it } - + + when: def actual = trimPrefix("Groovy-Tutorials at Baeldung") def expected = "Tutorials at Baeldung" - Assert.assertEquals(expected, actual) + then: + expected == actual } - @Test - public void whenPrefixIsRemoved_thenReturnTrue() { - + def "whenPrefixIsRemoved_thenReturnTrue"() { + given: String prefix = "groovy-" String trimPrefix = "Groovy-Tutorials at Baeldung" - def actual; - if(trimPrefix.startsWithIgnoreCase(prefix)) { + + when: + def actual + if (trimPrefix.startsWithIgnoreCase(prefix)) { actual = trimPrefix.substring(prefix.length()) } - def expected = "Tutorials at Baeldung" - Assert.assertEquals(expected, actual) + then: + expected == actual } - @Test - public void whenPrefixIsRemovedUsingRegex_thenReturnTrue() { - + def "whenPrefixIsRemovedUsingRegex_thenReturnTrue"() { + given: def regex = ~"^([Gg])roovy-" String trimPrefix = "Groovy-Tutorials at Baeldung" + + when: String actual = trimPrefix - regex - def expected = "Tutorials at Baeldung" - Assert.assertEquals(expected, actual) + then: + expected == actual } - @Test - public void whenPrefixIsRemovedUsingReplaceFirst_thenReturnTrue() { - def regex = ~"^groovy" - String trimPrefix = "groovyTutorials at Baeldung's groovy page" + def "whenPrefixIsRemovedUsingReplaceFirst_thenReturnTrue"() { + given: + def regex = ~"^groovy" + String trimPrefix = "groovyTutorials at Baeldung's groovy page" + + when: String actual = trimPrefix.replaceFirst(regex, "") - def expected = "Tutorials at Baeldung's groovy page" - - Assert.assertEquals(expected, actual) + + then: + expected == actual } - @Test - public void whenPrefixIsRemovedUsingReplaceAll_thenReturnTrue() { - + def "whenPrefixIsRemovedUsingReplaceAll_thenReturnTrue"() { + given: String trimPrefix = "groovyTutorials at Baeldung groovy" + + when: String actual = trimPrefix.replaceAll(/^groovy/, "") - def expected = "Tutorials at Baeldung groovy" - Assert.assertEquals(expected, actual) + then: + expected == actual } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/pom.xml b/core-groovy-modules/core-groovy/pom.xml index 413fbde106..cf6cca9e18 100644 --- a/core-groovy-modules/core-groovy/pom.xml +++ b/core-groovy-modules/core-groovy/pom.xml @@ -3,6 +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 + core-groovy 1.0-SNAPSHOT core-groovy @@ -103,9 +104,10 @@ - central - https://jcenter.bintray.com + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ - \ No newline at end of file + diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/file/ReadFile.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/file/ReadFile.groovy index 4239fa534c..1418947cc7 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/file/ReadFile.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/file/ReadFile.groovy @@ -10,13 +10,14 @@ class ReadFile { int readFileLineByLine(String filePath) { File file = new File(filePath) def line, noOfLines = 0; + file.withReader { reader -> - while ((line = reader.readLine())!=null) - { + while ((line = reader.readLine()) != null) { println "${line}" noOfLines++ } } + return noOfLines } @@ -26,9 +27,7 @@ class ReadFile { * @return */ List readFileInList(String filePath) { - File file = new File(filePath) - def lines = file.readLines() - return lines + return new File(filePath).readLines() } /** @@ -37,9 +36,7 @@ class ReadFile { * @return */ String readFileString(String filePath) { - File file = new File(filePath) - String fileContent = file.text - return fileContent + return new File(filePath).text } /** @@ -48,9 +45,7 @@ class ReadFile { * @return */ String readFileStringWithCharset(String filePath) { - File file = new File(filePath) - String utf8Content = file.getText("UTF-8") - return utf8Content + return new File(filePath).getText("UTF-8") } /** @@ -59,49 +54,44 @@ class ReadFile { * @return */ byte[] readBinaryFile(String filePath) { - File file = new File(filePath) - byte[] binaryContent = file.bytes - return binaryContent + return new File(filePath).bytes } - + /** * More Examples of reading a file * @return */ def moreExamples() { - + //with reader with utf-8 new File("src/main/resources/utf8Content.html").withReader('UTF-8') { reader -> def line - while ((line = reader.readLine())!=null) { + while ((line = reader.readLine()) != null) { println "${line}" } } - - //collect api - def list = new File("src/main/resources/fileContent.txt").collect {it} - - //as operator + + // collect api + def list = new File("src/main/resources/fileContent.txt").collect { it } + + // as operator def array = new File("src/main/resources/fileContent.txt") as String[] - - //eachline - new File("src/main/resources/fileContent.txt").eachLine { line -> - println line - } - + + // eachline + new File("src/main/resources/fileContent.txt").eachLine { println it } + //newInputStream with eachLine - def is = new File("src/main/resources/fileContent.txt").newInputStream() - is.eachLine { - println it + + // try-with-resources automatically closes BufferedInputStream resource + try (def inputStream = new File("src/main/resources/fileContent.txt").newInputStream()) { + inputStream.eachLine { println it } } - is.close() - - //withInputStream + + // withInputStream new File("src/main/resources/fileContent.txt").withInputStream { stream -> stream.eachLine { line -> println line } } } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/strings/Concatenate.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/strings/Concatenate.groovy index b3a0852a0b..4a7c3f8529 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/strings/Concatenate.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/strings/Concatenate.groovy @@ -1,9 +1,10 @@ package com.baeldung.strings; class Concatenate { + String first = 'Hello' String last = 'Groovy' - + String doSimpleConcat() { return 'My name is ' + first + ' ' + last } @@ -23,21 +24,28 @@ class Concatenate { String doConcatUsingLeftShiftOperator() { return 'My name is ' << first << ' ' << last } - + String doConcatUsingArrayJoinMethod() { return ['My name is', first, last].join(' ') } String doConcatUsingArrayInjectMethod() { - return [first,' ', last] - .inject(new StringBuffer('My name is '), { initial, name -> initial.append(name); return initial }).toString() + return [first, ' ', last] + .inject(new StringBuffer('My name is '), { initial, name -> initial.append(name) }) + .toString() } - + String doConcatUsingStringBuilder() { - return new StringBuilder().append('My name is ').append(first).append(' ').append(last) + return new StringBuilder().append('My name is ') + .append(first) + .append(' ') + .append(last) } String doConcatUsingStringBuffer() { - return new StringBuffer().append('My name is ').append(first).append(' ').append(last) + return new StringBuffer().append('My name is ') + .append(first) + .append(' ') + .append(last) } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/AnimalTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/AnimalTrait.groovy index 6ec5cda571..a3fed81c8b 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/AnimalTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/AnimalTrait.groovy @@ -1,8 +1,8 @@ package com.baeldung.traits trait AnimalTrait { - + String basicBehavior() { return "Animalistic!!" } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Dog.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Dog.groovy index 3e0677ba18..fc53b1bef9 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Dog.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Dog.groovy @@ -1,9 +1,8 @@ package com.baeldung.traits class Dog implements WalkingTrait, SpeakingTrait { - + String speakAndWalk() { WalkingTrait.super.speakAndWalk() } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Employee.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Employee.groovy index b3e4285476..16f1fab984 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Employee.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Employee.groovy @@ -1,12 +1,14 @@ package com.baeldung.traits class Employee implements UserTrait { - + + @Override String name() { return 'Bob' } + @Override String lastName() { return "Marley" } -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Human.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Human.groovy index e78d59bbfd..5417334269 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Human.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/Human.groovy @@ -1,6 +1,6 @@ package com.baeldung.traits interface Human { - + String lastName() -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/SpeakingTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/SpeakingTrait.groovy index f437a94bd9..969982e8e0 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/SpeakingTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/SpeakingTrait.groovy @@ -1,13 +1,12 @@ package com.baeldung.traits trait SpeakingTrait { - + String basicAbility() { return "Speaking!!" } - + String speakAndWalk() { return "Speak and walk!!" } - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy index 0d395bffcd..1d1d188460 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy @@ -1,36 +1,35 @@ package com.baeldung.traits trait UserTrait implements Human { - + + String email + String address + + abstract String name() + String sayHello() { return "Hello!" } - - abstract String name() - + String showName() { - return "Hello, ${name()}!" + return "Hello, ${name()}!" } private String greetingMessage() { return 'Hello, from a private method!' } - + String greet() { def msg = greetingMessage() println msg msg } - + def self() { - return this + return this } - + String showLastName() { return "Hello, ${lastName()}!" } - - String email - String address } - \ No newline at end of file diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy index f5ae8fab30..e29561157c 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy @@ -1,9 +1,9 @@ package com.baeldung trait VehicleTrait extends WheelTrait { - + String showWheels() { - return "Num of Wheels $noOfWheels" + return "Num of Wheels $noOfWheels" } - -} \ No newline at end of file + +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WalkingTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WalkingTrait.groovy index 66cff8809f..84be49ec25 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WalkingTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WalkingTrait.groovy @@ -1,13 +1,13 @@ package com.baeldung.traits trait WalkingTrait { - + String basicAbility() { return "Walking!!" } - + String speakAndWalk() { return "Walk and speak!!" } - -} \ No newline at end of file + +} diff --git a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy index 364d5b883e..7f2448e185 100644 --- a/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy +++ b/core-groovy-modules/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy @@ -1,7 +1,6 @@ package com.baeldung trait WheelTrait { - + int noOfWheels - -} \ No newline at end of file +} diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/file/ReadFileUnitTest.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/file/ReadFileUnitTest.groovy index da1dfc10ba..87cfc79761 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/file/ReadFileUnitTest.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/file/ReadFileUnitTest.groovy @@ -1,71 +1,76 @@ package com.baeldung.file import spock.lang.Specification -import spock.lang.Ignore class ReadFileUnitTest extends Specification { ReadFile readFile - void setup () { + void setup() { readFile = new ReadFile() } - def 'Should return number of lines in File using ReadFile.readFileLineByLine given filePath' () { + def 'Should return number of lines in File using ReadFile.readFileLineByLine given filePath'() { given: - def filePath = "src/main/resources/fileContent.txt" + def filePath = "src/main/resources/fileContent.txt" + when: - def noOfLines = readFile.readFileLineByLine(filePath) + def noOfLines = readFile.readFileLineByLine(filePath) + then: - noOfLines - noOfLines instanceof Integer - assert noOfLines, 3 - } - - def 'Should return File Content in list of lines using ReadFile.readFileInList given filePath' () { - given: - def filePath = "src/main/resources/fileContent.txt" - when: - def lines = readFile.readFileInList(filePath) - then: - lines - lines instanceof List - assert lines.size(), 3 - } - - def 'Should return file content in string using ReadFile.readFileString given filePath' () { - given: - def filePath = "src/main/resources/fileContent.txt" - when: - def fileContent = readFile.readFileString(filePath) - then: - fileContent - fileContent instanceof String - fileContent.contains("""Line 1 : Hello World!!! -Line 2 : This is a file content. -Line 3 : String content""") - + noOfLines + noOfLines instanceof Integer + noOfLines == 3 } - def 'Should return UTF-8 encoded file content in string using ReadFile.readFileStringWithCharset given filePath' () { + def 'Should return File Content in list of lines using ReadFile.readFileInList given filePath'() { given: - def filePath = "src/main/resources/utf8Content.html" + def filePath = "src/main/resources/fileContent.txt" + when: - def encodedContent = readFile.readFileStringWithCharset(filePath) + def lines = readFile.readFileInList(filePath) + then: - encodedContent - encodedContent instanceof String + lines + lines instanceof List + lines.size() == 3 } - - def 'Should return binary file content in byte array using ReadFile.readBinaryFile given filePath' () { + + def 'Should return file content in string using ReadFile.readFileString given filePath'() { given: - def filePath = "src/main/resources/sample.png" + def filePath = "src/main/resources/fileContent.txt" + when: - def binaryContent = readFile.readBinaryFile(filePath) + def fileContent = readFile.readFileString(filePath) + then: - binaryContent - binaryContent instanceof byte[] - binaryContent.length == 329 + fileContent + fileContent instanceof String + fileContent.contains(["Line 1 : Hello World!!!", "Line 2 : This is a file content.", "Line 3 : String content"].join("\r\n")) } - -} \ No newline at end of file + + def 'Should return UTF-8 encoded file content in string using ReadFile.readFileStringWithCharset given filePath'() { + given: + def filePath = "src/main/resources/utf8Content.html" + + when: + def encodedContent = readFile.readFileStringWithCharset(filePath) + + then: + encodedContent + encodedContent instanceof String + } + + def 'Should return binary file content in byte array using ReadFile.readBinaryFile given filePath'() { + given: + def filePath = "src/main/resources/sample.png" + + when: + def binaryContent = readFile.readBinaryFile(filePath) + + then: + binaryContent + binaryContent instanceof byte[] + binaryContent.length == 329 + } +} diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy index ac96a55773..da982744e9 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy @@ -1,28 +1,29 @@ package com.baeldung.groovy.sql import groovy.sql.GroovyResultSet -import groovy.sql.GroovyRowResult import groovy.sql.Sql -import groovy.transform.CompileStatic -import static org.junit.Assert.* import org.junit.Test +import static org.junit.Assert.* + class SqlTest { - final Map dbConnParams = [url: 'jdbc:hsqldb:mem:testDB', user: 'sa', password: '', driver: 'org.hsqldb.jdbc.JDBCDriver'] + final Map dbConnParams = [url: 'jdbc:hsqldb:mem:testDB', + user: 'sa', + password: '', + driver: 'org.hsqldb.jdbc.JDBCDriver'] @Test void whenNewSqlInstance_thenDbIsAccessed() { def sql = Sql.newInstance(dbConnParams) sql.close() - sql.close() } @Test void whenTableDoesNotExist_thenSelectFails() { try { Sql.withInstance(dbConnParams) { Sql sql -> - sql.eachRow('select * from PROJECT') {} + sql.eachRow('SELECT * FROM PROJECT') {} } fail("An exception should have been thrown") @@ -34,12 +35,12 @@ class SqlTest { @Test void whenTableCreated_thenSelectIsPossible() { Sql.withInstance(dbConnParams) { Sql sql -> - def result = sql.execute 'create table PROJECT_1 (id integer not null, name varchar(50), url varchar(100))' + def result = sql.execute 'CREATE TABLE PROJECT_1 (ID INTEGER NOT NULL, NAME VARCHAR(50), URL VARCHAR(100))' assertEquals(0, sql.updateCount) assertFalse(result) - result = sql.execute('select * from PROJECT_1') + result = sql.execute('SELECT * FROM PROJECT_1') assertTrue(result) } @@ -48,7 +49,7 @@ class SqlTest { @Test void whenIdentityColumn_thenInsertReturnsNewId() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_2 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_2 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' def ids = sql.executeInsert("INSERT INTO PROJECT_2 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") assertEquals(0, ids[0][0]) @@ -62,9 +63,10 @@ class SqlTest { @Test void whenUpdate_thenNumberOfAffectedRows() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_3 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_3 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + def count = sql.executeUpdate("UPDATE PROJECT_3 SET URL = 'https://' + URL") assertEquals(2, count) @@ -74,7 +76,7 @@ class SqlTest { @Test void whenEachRow_thenResultSetHasProperties() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_4 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_4 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") @@ -93,7 +95,7 @@ class SqlTest { @Test void whenPagination_thenSubsetIsReturned() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") def rows = sql.rows('SELECT * FROM PROJECT_5 ORDER BY NAME', 1, 1) @@ -106,9 +108,11 @@ class SqlTest { @Test void whenParameters_thenReplacement() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_6 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' - sql.execute('INSERT INTO PROJECT_6 (NAME, URL) VALUES (?, ?)', 'tutorials', 'github.com/eugenp/tutorials') - sql.execute("INSERT INTO PROJECT_6 (NAME, URL) VALUES (:name, :url)", [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring']) + sql.execute 'CREATE TABLE PROJECT_6 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute('INSERT INTO PROJECT_6 (NAME, URL) VALUES (?, ?)', + 'tutorials', 'github.com/eugenp/tutorials') + sql.execute("INSERT INTO PROJECT_6 (NAME, URL) VALUES (:name, :url)", + [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring']) def rows = sql.rows("SELECT * FROM PROJECT_6 WHERE NAME = 'tutorials'") @@ -123,7 +127,7 @@ class SqlTest { @Test void whenParametersInGString_thenReplacement() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_7 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_7 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.execute "INSERT INTO PROJECT_7 (NAME, URL) VALUES (${'tutorials'}, ${'github.com/eugenp/tutorials'})" def name = 'REST with Spring' def url = 'github.com/eugenp/REST-With-Spring' @@ -143,7 +147,7 @@ class SqlTest { void whenTransactionRollback_thenNoDataInserted() { Sql.withInstance(dbConnParams) { Sql sql -> sql.withTransaction { - sql.execute 'create table PROJECT_8 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_8 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") sql.rollback() @@ -159,7 +163,7 @@ class SqlTest { void whenTransactionRollbackThenCommit_thenOnlyLastInserted() { Sql.withInstance(dbConnParams) { Sql sql -> sql.withTransaction { - sql.execute 'create table PROJECT_9 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_9 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") sql.rollback() sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") @@ -179,11 +183,12 @@ class SqlTest { Sql.withInstance(dbConnParams) { Sql sql -> try { sql.withTransaction { - sql.execute 'create table PROJECT_10 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_10 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_10 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") throw new Exception('rollback') } - } catch (ignored) {} + } catch (ignored) { + } def rows = sql.rows("SELECT * FROM PROJECT_10") @@ -196,11 +201,12 @@ class SqlTest { Sql.withInstance(dbConnParams) { Sql sql -> try { sql.cacheConnection { - sql.execute 'create table PROJECT_11 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_11 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_11 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") throw new Exception('This does not rollback') } - } catch (ignored) {} + } catch (ignored) { + } def rows = sql.rows("SELECT * FROM PROJECT_11") @@ -211,7 +217,7 @@ class SqlTest { /*@Test void whenModifyResultSet_thenDataIsChanged() { Sql.withInstance(dbConnParams) { Sql sql -> - sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute 'CREATE TABLE PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/json/JsonParserTest.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/json/JsonParserTest.groovy index e65550a3be..fa7b2fd3c8 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/json/JsonParserTest.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/json/JsonParserTest.groovy @@ -1,5 +1,6 @@ package com.baeldung.json +import groovy.json.JsonGenerator import spock.lang.Specification import java.text.SimpleDateFormat @@ -8,20 +9,42 @@ class JsonParserTest extends Specification { JsonParser jsonParser - void setup () { + void setup() { jsonParser = new JsonParser() } - def 'Should parse to Account given Json String' () { + def 'Should parse to Account given Json String'() { given: - def json = '{"id":"1234","value":15.6}' + def json = '{"id":"1234","value":15.6}' + when: - def account = jsonParser.toObject(json) + def account = jsonParser.toObject(json) + then: - account - account instanceof Account - account.id == '1234' - account.value == 15.6 + account + account instanceof Account + account.id == '1234' + account.value == 15.6 + } + + def 'Should format date and exclude value field'() { + given: + def account = new Account( + id: '123', + value: 15.6, + createdAt: new SimpleDateFormat('MM/dd/yyyy').parse('14/01/2023') + ) + + def jsonGenerator = new JsonGenerator.Options() + .dateFormat('MM/dd/yyyy') + .excludeFieldsByName('value') + .build() + + when: + def accountToJson = jsonGenerator.toJson(account) + + then: + accountToJson == '{"createdAt":"01/31/2024","id":"123"}' } /*def 'Should parse to Account given Json String with date property' () { @@ -52,15 +75,20 @@ class JsonParserTest extends Specification { json == '{"value":15.6,"createdAt":"2018-01-01T00:00:00+0000","id":"123"}' }*/ - def 'Should prettify given a json string' () { + def 'Should prettify given a json string'() { given: - String json = '{"value":15.6,"createdAt":"01/01/2018","id":"123456"}' + String json = '{"value":15.6,"createdAt":"01/01/2018","id":"123456"}' + when: - def jsonPretty = jsonParser.prettyfy(json) + def jsonPretty = jsonParser.prettyfy(json) + then: - jsonPretty - jsonPretty == '{\n "value": 15.6,\n "createdAt": "01/01/2018",\n "id": "123456"\n}' + jsonPretty + jsonPretty == '''\ +{ + "value": 15.6, + "createdAt": "01/01/2018", + "id": "123456" +}''' } - - } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/ConcatenateTest.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/ConcatenateTest.groovy index 3ef4a5d460..e4a178a14b 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/ConcatenateTest.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/ConcatenateTest.groovy @@ -1,101 +1,88 @@ -import com.baeldung.strings.Concatenate; +import com.baeldung.strings.Concatenate +import spock.lang.Specification -class ConcatenateTest extends GroovyTestCase { - - void testSimpleConcat() { - def name = new Concatenate() - name.first = 'Joe'; - name.last = 'Smith'; - def expected = 'My name is Joe Smith' - assertToString(name.doSimpleConcat(), expected) - } - - void testConcatUsingGString() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingGString(), expected) - } - - void testConcatUsingGStringClosures() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingGStringClosures(), expected) - } - - void testConcatUsingStringConcatMethod() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingStringConcatMethod(), expected) +class ConcatenateTest extends Specification { + + final Concatenate NAME = new Concatenate(first: 'Joe', last: 'Smith') + final String EXPECTED = "My name is Joe Smith"; + + def "SimpleConcat"() { + expect: + NAME.doSimpleConcat() == EXPECTED } - void testConcatUsingLeftShiftOperator() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingLeftShiftOperator(), expected) + def "ConcatUsingGString"() { + expect: + NAME.doConcatUsingGString() == EXPECTED } - void testConcatUsingArrayJoinMethod() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingArrayJoinMethod(), expected) + def "ConcatUsingGStringClosures"() { + expect: + NAME.doConcatUsingGStringClosures() == EXPECTED } - void testConcatUsingArrayInjectMethod() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingArrayInjectMethod(), expected) + def "ConcatUsingStringConcatMethod"() { + expect: + NAME.doConcatUsingStringConcatMethod() == EXPECTED } - void testConcatUsingStringBuilder() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingStringBuilder(), expected) + def "ConcatUsingLeftShiftOperator"() { + expect: + NAME.doConcatUsingLeftShiftOperator() == EXPECTED } - void testConcatUsingStringBuffer() { - def name = new Concatenate() - name.first = "Joe"; - name.last = "Smith"; - def expected = "My name is Joe Smith" - assertToString(name.doConcatUsingStringBuffer(), expected) + def "ConcatUsingArrayJoinMethod"() { + expect: + NAME.doConcatUsingArrayJoinMethod() == EXPECTED } - void testConcatMultilineUsingStringConcatMethod() { - def name = new Concatenate() - name.first = '''Joe + def "ConcatUsingArrayInjectMethod"() { + expect: + NAME.doConcatUsingArrayInjectMethod() == EXPECTED + } + + def "ConcatUsingStringBuilder"() { + expect: + NAME.doConcatUsingStringBuilder() == EXPECTED + } + + def "ConcatUsingStringBuffer"() { + expect: + NAME.doConcatUsingStringBuffer() == EXPECTED + } + + def "ConcatMultilineUsingStringConcatMethod"() { + when: + NAME.first = '''Joe Smith - '''; - name.last = 'Junior'; + ''' + NAME.last = 'Junior' + + then: def expected = '''My name is Joe Smith - Junior'''; - assertToString(name.doConcatUsingStringConcatMethod(), expected) + Junior''' + NAME.doConcatUsingStringConcatMethod() == expected } - void testGStringvsClosure(){ - def first = "Joe"; - def last = "Smith"; - def eagerGString = "My name is $first $last" - def lazyGString = "My name is ${-> first} ${-> last}" + def "GStringvsClosure"() { + given: + def eagerGString = "My name is $NAME.first $NAME.last" + def lazyGString = "My name is ${-> NAME.first} ${-> NAME.last}" - assert eagerGString == "My name is Joe Smith" - assert lazyGString == "My name is Joe Smith" - first = "David"; - assert eagerGString == "My name is Joe Smith" - assert lazyGString == "My name is David Smith" - } + expect: + eagerGString == "My name is Joe Smith" + lazyGString == "My name is Joe Smith" + } + + def "LazyVsEager"() { + given: + def eagerGString = "My name is $NAME.first $NAME.last" + def lazyGString = "My name is ${-> NAME.first} ${-> NAME.last}" + NAME.first = "David" + + expect: + eagerGString == "My name is Joe Smith" + lazyGString == "My name is David Smith" + } } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy index 3865bc73fa..89202d9500 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy @@ -13,7 +13,7 @@ class StringMatchingSpec extends Specification { expect: p instanceof Pattern - and: "you can use slash strings to avoid escaping of blackslash" + and: "you can use slash strings to avoid escaping of backslash" def digitPattern = ~/\d*/ digitPattern.matcher('4711').matches() } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtoint/ConvertStringToInt.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtoint/ConvertStringToInt.groovy index 48cf48fa8a..cce6ede989 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtoint/ConvertStringToInt.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtoint/ConvertStringToInt.groovy @@ -1,110 +1,119 @@ package com.baeldung.stringtoint -import org.junit.Test +import spock.lang.Specification import java.text.DecimalFormat -import static org.junit.Assert.assertEquals -import static org.junit.Assert.assertNull +class ConvertStringToInt extends Specification { -class ConvertStringToInt { + final String STRING_NUM = "123" + final int EXPECTED_INT = 123 - @Test - void givenString_whenUsingAsInteger_thenConvertToInteger() { - def stringNum = "123" + def "givenString_whenUsingAsInteger_thenConvertToInteger"() { + given: def invalidString = "123a" - Integer expectedInteger = 123 - Integer integerNum = stringNum as Integer + Integer integerNum = STRING_NUM as Integer + + when: def intNum = invalidString?.isInteger() ? invalidString as Integer : null - assertNull(null, intNum) - assertEquals(integerNum, expectedInteger) + then: + intNum == null + integerNum == EXPECTED_INT } - @Test - void givenString_whenUsingAsInt_thenConvertToInt() { - def stringNum = "123" - int expectedInt = 123 - int intNum = stringNum as int + def "givenString_whenUsingAsInt_thenConvertToInt"() { + given: + int intNum = STRING_NUM as int - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingToInteger_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 - int intNum = stringNum.toInteger() + def "givenString_whenUsingToInteger_thenConvertToInteger"() { + given: + int intNum = STRING_NUM.toInteger() - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingParseInt_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 - int intNum = Integer.parseInt(stringNum) + def "givenString_whenUsingParseInt_thenConvertToInteger"() { + given: + int intNum = Integer.parseInt(STRING_NUM) - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingValueOf_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 - int intNum = Integer.valueOf(stringNum) + def "givenString_whenUsingValueOf_thenConvertToInteger"() { + given: + int intNum = Integer.valueOf(STRING_NUM) - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingIntValue_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 - int intNum = new Integer(stringNum).intValue() + def "givenString_whenUsingIntValue_thenConvertToInteger"() { + given: + int intNum = Integer.valueOf(STRING_NUM).intValue() - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingNewInteger_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 - int intNum = new Integer(stringNum) + def "givenString_whenUsingNewInteger_thenConvertToInteger"() { + given: + Integer intNum = Integer.valueOf(STRING_NUM) - assertEquals(intNum, expectedInt) + expect: + intNum == EXPECTED_INT } - @Test - void givenString_whenUsingDecimalFormat_thenConvertToInteger() { - def stringNum = "123" - int expectedInt = 123 + def "givenString_whenUsingDecimalFormat_thenConvertToInteger"() { + given: DecimalFormat decimalFormat = new DecimalFormat("#") - int intNum = decimalFormat.parse(stringNum).intValue() - assertEquals(intNum, expectedInt) + when: + int intNum = decimalFormat.parse(STRING_NUM).intValue() + + then: + intNum == EXPECTED_INT } - @Test(expected = NumberFormatException.class) - void givenInvalidString_whenUsingAs_thenThrowNumberFormatException() { + def "givenInvalidString_whenUsingAs_thenThrowNumberFormatException"() { + given: def invalidString = "123a" + + when: invalidString as Integer + + then: + thrown(NumberFormatException) } - @Test(expected = NullPointerException.class) - void givenNullString_whenUsingToInteger_thenThrowNullPointerException() { + def "givenNullString_whenUsingToInteger_thenThrowNullPointerException"() { + given: def invalidString = null + + when: invalidString.toInteger() + + then: + thrown(NullPointerException) } - @Test - void givenString_whenUsingIsInteger_thenCheckIfCorrectValue() { + def "givenString_whenUsingIsInteger_thenCheckIfCorrectValue"() { + given: def invalidString = "123a" def validString = "123" + + when: def invalidNum = invalidString?.isInteger() ? invalidString as Integer : false def correctNum = validString?.isInteger() ? validString as Integer : false - assertEquals(false, invalidNum) - assertEquals(123, correctNum) + then: + !invalidNum + correctNum == 123 } } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/CharacterInGroovy.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/CharacterInGroovy.groovy index c043723d95..30365ec9d7 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/CharacterInGroovy.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/CharacterInGroovy.groovy @@ -1,19 +1,18 @@ package groovy.com.baeldung.stringtypes -import org.junit.Assert -import org.junit.Test +import spock.lang.Specification -class CharacterInGroovy { +class CharacterInGroovy extends Specification { - @Test - void 'character'() { + def 'character'() { + given: char a = 'A' as char char b = 'B' as char char c = (char) 'C' - Assert.assertTrue(a instanceof Character) - Assert.assertTrue(b instanceof Character) - Assert.assertTrue(c instanceof Character) + expect: + a instanceof Character + b instanceof Character + c instanceof Character } - } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/DoubleQuotedString.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/DoubleQuotedString.groovy index a730244d0a..e1074145f4 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/DoubleQuotedString.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/DoubleQuotedString.groovy @@ -1,67 +1,76 @@ package groovy.com.baeldung.stringtypes -import org.junit.Assert -import org.junit.Test +import spock.lang.Specification -class DoubleQuotedString { +class DoubleQuotedString extends Specification { - @Test - void 'escape double quoted string'() { + def 'escape double quoted string'() { + given: def example = "Hello \"world\"!" - println(example) + expect: + example == 'Hello "world"!' } - @Test - void 'String ang GString'() { + def 'String ang GString'() { + given: def string = "example" def stringWithExpression = "example${2}" - Assert.assertTrue(string instanceof String) - Assert.assertTrue(stringWithExpression instanceof GString) - Assert.assertTrue(stringWithExpression.toString() instanceof String) + expect: + string instanceof String + stringWithExpression instanceof GString + stringWithExpression.toString() instanceof String } - @Test - void 'placeholder with variable'() { + def 'placeholder with variable'() { + given: def name = "John" + + when: def helloName = "Hello $name!".toString() - Assert.assertEquals("Hello John!", helloName) + then: + helloName == "Hello John!" } - @Test - void 'placeholder with expression'() { + def 'placeholder with expression'() { + given: def result = "result is ${2 * 2}".toString() - Assert.assertEquals("result is 4", result) + expect: + result == "result is 4" } - @Test - void 'placeholder with dotted access'() { + def 'placeholder with dotted access'() { + given: def person = [name: 'John'] + when: def myNameIs = "I'm $person.name, and you?".toString() - Assert.assertEquals("I'm John, and you?", myNameIs) + then: + myNameIs == "I'm John, and you?" } - @Test - void 'placeholder with method call'() { + def 'placeholder with method call'() { + given: def name = 'John' + when: def result = "Uppercase name: ${name.toUpperCase()}".toString() - Assert.assertEquals("Uppercase name: JOHN", result) + then: + result == "Uppercase name: JOHN" } - @Test - void 'GString and String hashcode'() { + def 'GString and String hashcode'() { + given: def string = "2+2 is 4" def gstring = "2+2 is ${4}" - Assert.assertTrue(string.hashCode() != gstring.hashCode()) + expect: + string.hashCode() != gstring.hashCode() } - } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/SingleQuotedString.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/SingleQuotedString.groovy index 569991b788..924515570c 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/SingleQuotedString.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/SingleQuotedString.groovy @@ -1,15 +1,14 @@ package groovy.com.baeldung.stringtypes -import org.junit.Assert -import org.junit.Test +import spock.lang.Specification -class SingleQuotedString { +class SingleQuotedString extends Specification { - @Test - void 'single quoted string'() { - def example = 'Hello world' + def 'single quoted string'() { + given: + def example = 'Hello world!' - Assert.assertEquals('Hello world!', 'Hello' + ' world!') + expect: + example == 'Hello' + ' world!' } - } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/Strings.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/Strings.groovy index e45f352285..9d29210d81 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/Strings.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/stringtypes/Strings.groovy @@ -1,26 +1,29 @@ package groovy.com.baeldung.stringtypes -import org.junit.Assert -import org.junit.Test +import spock.lang.Specification -class Strings { +class Strings extends Specification { - @Test - void 'string interpolation '() { + def 'string interpolation '() { + given: def name = "Kacper" + when: def result = "Hello ${name}!" - Assert.assertEquals("Hello Kacper!", result.toString()) + then: + result.toString() == "Hello Kacper!" } - @Test - void 'string concatenation'() { + def 'string concatenation'() { + given: def first = "first" def second = "second" + when: def concatenation = first + second - Assert.assertEquals("firstsecond", concatenation) + then: + concatenation == "firstsecond" } } diff --git a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy index 85130e8f07..b47cba6437 100644 --- a/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy +++ b/core-groovy-modules/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy @@ -7,108 +7,111 @@ class TraitsUnitTest extends Specification { Employee employee Dog dog - void setup () { + void setup() { employee = new Employee() dog = new Dog() } - def 'Should return msg string when using Employee.sayHello method provided by UserTrait' () { + def 'Should return msg string when using Employee.sayHello method provided by UserTrait'() { when: - def msg = employee.sayHello() + def msg = employee.sayHello() + then: - msg - msg instanceof String - assert msg == "Hello!" + msg + msg instanceof String + msg == "Hello!" } - - def 'Should return displayMsg string when using Employee.showName method' () { + + def 'Should return displayMsg string when using Employee.showName method'() { when: - def displayMsg = employee.showName() + def displayMsg = employee.showName() + then: - displayMsg - displayMsg instanceof String - assert displayMsg == "Hello, Bob!" + displayMsg + displayMsg instanceof String + displayMsg == "Hello, Bob!" } - - def 'Should return greetMsg string when using Employee.greet method' () { + + def 'Should return greetMsg string when using Employee.greet method'() { when: - def greetMsg = employee.greet() + def greetMsg = employee.greet() + then: - greetMsg - greetMsg instanceof String - assert greetMsg == "Hello, from a private method!" + greetMsg + greetMsg instanceof String + greetMsg == "Hello, from a private method!" } - - def 'Should return MissingMethodException when using Employee.greetingMessage method' () { + + def 'Should return MissingMethodException when using Employee.greetingMessage method'() { when: - def exception - try { - employee.greetingMessage() - }catch(Exception e) { - exception = e - } - + employee.greetingMessage() + then: - exception - exception instanceof groovy.lang.MissingMethodException - assert exception.message == "No signature of method: com.baeldung.traits.Employee.greetingMessage()"+ - " is applicable for argument types: () values: []" + thrown(MissingMethodException) + specificationContext.thrownException.message == + "No signature of method: com.baeldung.traits.Employee.greetingMessage() is applicable for argument types: () values: []" } - - def 'Should return employee instance when using Employee.whoAmI method' () { + + def 'Should return employee instance when using Employee.whoAmI method'() { when: - def emp = employee.self() + def emp = employee.self() + then: - emp - emp instanceof Employee - assert emp.is(employee) + emp + emp instanceof Employee + emp.is(employee) } - - def 'Should display lastName when using Employee.showLastName method' () { + + def 'Should display lastName when using Employee.showLastName method'() { when: - def lastNameMsg = employee.showLastName() + def lastNameMsg = employee.showLastName() + then: - lastNameMsg - lastNameMsg instanceof String - assert lastNameMsg == "Hello, Marley!" + lastNameMsg + lastNameMsg instanceof String + lastNameMsg == "Hello, Marley!" } - - def 'Should be able to define properties of UserTrait in Employee instance' () { + + def 'Should be able to define properties of UserTrait in Employee instance'() { when: - employee = new Employee(email: "a@e.com", address: "baeldung.com") + employee = new Employee(email: "a@e.com", address: "baeldung.com") + then: - employee - employee instanceof Employee - assert employee.email == "a@e.com" - assert employee.address == "baeldung.com" + employee + employee instanceof Employee + employee.email == "a@e.com" + employee.address == "baeldung.com" } - - def 'Should execute basicAbility method from SpeakingTrait and return msg string' () { + + def 'Should execute basicAbility method from SpeakingTrait and return msg string'() { when: - def speakMsg = dog.basicAbility() + def speakMsg = dog.basicAbility() + then: - speakMsg - speakMsg instanceof String - assert speakMsg == "Speaking!!" + speakMsg + speakMsg instanceof String + speakMsg == "Speaking!!" } - - def 'Should verify multiple inheritance with traits and execute overridden traits method' () { + + def 'Should verify multiple inheritance with traits and execute overridden traits method'() { when: - def walkSpeakMsg = dog.speakAndWalk() - println walkSpeakMsg + def walkSpeakMsg = dog.speakAndWalk() + println walkSpeakMsg + then: - walkSpeakMsg - walkSpeakMsg instanceof String - assert walkSpeakMsg == "Walk and speak!!" + walkSpeakMsg + walkSpeakMsg instanceof String + walkSpeakMsg == "Walk and speak!!" } - - def 'Should implement AnimalTrait at runtime and access basicBehavior method' () { + + def 'Should implement AnimalTrait at runtime and access basicBehavior method'() { when: - def dogInstance = new Dog() as AnimalTrait - def basicBehaviorMsg = dogInstance.basicBehavior() + def dogInstance = new Dog() as AnimalTrait + def basicBehaviorMsg = dogInstance.basicBehavior() + then: - basicBehaviorMsg - basicBehaviorMsg instanceof String - assert basicBehaviorMsg == "Animalistic!!" + basicBehaviorMsg + basicBehaviorMsg instanceof String + basicBehaviorMsg == "Animalistic!!" } -} \ No newline at end of file +} diff --git a/core-groovy-modules/pom.xml b/core-groovy-modules/pom.xml index e1ff538942..6faa7f94c8 100644 --- a/core-groovy-modules/pom.xml +++ b/core-groovy-modules/pom.xml @@ -21,12 +21,12 @@ - 2.5.7 - 2.5.6 - 2.5.6 - 2.4.0 - 1.1-groovy-2.4 - 1.6 + 3.0.15 + 3.0.15 + 3.0.15 + 2.7.1 + 2.3-groovy-3.0 + 2.1.0 - \ No newline at end of file + diff --git a/core-java-modules/core-java-11-3/README.md b/core-java-modules/core-java-11-3/README.md index e77e5b7f3d..4f5eb3ea56 100644 --- a/core-java-modules/core-java-11-3/README.md +++ b/core-java-modules/core-java-11-3/README.md @@ -5,3 +5,4 @@ This module contains articles about Java 11 core features ### Relevant articles - [Adding Parameters to Java HttpClient Requests](https://www.baeldung.com/java-httpclient-request-parameters) - [Writing a List of Strings Into a Text File](https://www.baeldung.com/java-list-to-text-file) +- [Java HttpClient – Map JSON Response to Java Class](https://www.baeldung.com/java-httpclient-map-json-response) diff --git a/core-java-modules/core-java-11-3/pom.xml b/core-java-modules/core-java-11-3/pom.xml index b4a4591b28..ccccae5ba1 100644 --- a/core-java-modules/core-java-11-3/pom.xml +++ b/core-java-modules/core-java-11-3/pom.xml @@ -14,6 +14,20 @@ 1.0.0-SNAPSHOT ../../pom.xml + + + + com.google.code.gson + gson + ${gson.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + @@ -32,6 +46,8 @@ 11 11 + 2.14.1 + 2.10 \ No newline at end of file diff --git a/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/Todo.java b/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/Todo.java new file mode 100644 index 0000000000..01a1ee5c52 --- /dev/null +++ b/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/Todo.java @@ -0,0 +1,73 @@ +package com.baeldung.httppojo; + +import java.util.Objects; + +public class Todo { + + int userId; + int id; + String title; + boolean completed; + + public Todo() { + } + + public Todo(int userId, int id, String title, boolean completed) { + this.userId = userId; + this.id = id; + this.title = title; + this.completed = completed; + } + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Todo todo = (Todo) o; + return userId == todo.userId && id == todo.id && completed == todo.completed && Objects.equals(title, todo.title); + } + + @Override + public int hashCode() { + return Objects.hash(userId, id, title, completed); + } + + @Override + public String toString() { + return "{" + "userId=" + userId + ", id=" + id + ", title='" + title + '\'' + ", completed=" + completed + '}'; + } +} diff --git a/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/TodoAppClient.java b/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/TodoAppClient.java new file mode 100644 index 0000000000..c2295d97ce --- /dev/null +++ b/core-java-modules/core-java-11-3/src/main/java/com/baeldung/httppojo/TodoAppClient.java @@ -0,0 +1,107 @@ +package com.baeldung.httppojo; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.List; +import java.util.concurrent.CompletionException; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +public class TodoAppClient { + + ObjectMapper objectMapper = new ObjectMapper(); + + Gson gson = new GsonBuilder().create(); + + public String sampleApiRequest() throws Exception { + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://jsonplaceholder.typicode.com/todos")) + .build(); + + HttpResponse response = client.send(request, BodyHandlers.ofString()); + + return response.body(); + + } + + public Todo syncGson() throws Exception { + String response = sampleApiRequest(); + + List todo = gson.fromJson(response, new TypeToken>() { + }.getType()); + + return todo.get(1); + + } + + public Todo syncJackson() throws Exception { + String response = sampleApiRequest(); + + Todo[] todo = objectMapper.readValue(response, Todo[].class); + + return todo[1]; + + } + + public Todo asyncJackson() throws Exception { + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://jsonplaceholder.typicode.com/todos")) + .build(); + + TodoAppClient todoAppClient = new TodoAppClient(); + + List todo = HttpClient.newHttpClient() + .sendAsync(request, BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .thenApply(todoAppClient::readValueJackson) + .get(); + + return todo.get(1); + + } + + public Todo asyncGson() throws Exception { + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://jsonplaceholder.typicode.com/todos")) + .build(); + TodoAppClient todoAppClient = new TodoAppClient(); + + List todo = HttpClient.newHttpClient() + .sendAsync(request, BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .thenApply(todoAppClient::readValueGson) + .get(); + + return todo.get(1); + + } + + List readValueJackson(String content) { + + try { + return objectMapper.readValue(content, new TypeReference>() { + }); + } catch (IOException ioe) { + throw new CompletionException(ioe); + } + } + + List readValueGson(String content) { + + return gson.fromJson(content, new TypeToken>() { + }.getType()); + + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-11-3/src/test/java/com/baeldung/httppojo/HttpClientPojoClassUnitTest.java b/core-java-modules/core-java-11-3/src/test/java/com/baeldung/httppojo/HttpClientPojoClassUnitTest.java new file mode 100644 index 0000000000..a364a8d27e --- /dev/null +++ b/core-java-modules/core-java-11-3/src/test/java/com/baeldung/httppojo/HttpClientPojoClassUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.httppojo; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class HttpClientPojoClassUnitTest { + + Todo expectedTodo = new Todo(1, 2, "quis ut nam facilis et officia qui", false); + + @Test + public void givenSampleApiCall_whenResponseIsMappedByGson_thenCompareResponseMappedByGson() throws Exception { + TodoAppClient sampleGson = new TodoAppClient(); + + assertEquals(expectedTodo, sampleGson.syncGson()); + + } + + @Test + public void givenSampleApiCall_whenResponseIsMappedByJackson_thenCompareResponseMappedByJackson() throws Exception { + TodoAppClient sampleJackson = new TodoAppClient(); + + assertEquals(expectedTodo, sampleJackson.syncJackson()); + } + + @Test + public void givenSampleRestApi_whenApiIsConsumedByHttpClient_thenCompareJsonString() throws Exception { + TodoAppClient sampleTest = new TodoAppClient(); + assertNotNull(sampleTest.sampleApiRequest()); + + } + + @Test + public void givenSampleApiAsyncCall_whenResponseIsMappedByJackson_thenCompareResponseMappedByJackson() throws Exception { + TodoAppClient sampleAsynJackson = new TodoAppClient(); + assertEquals(expectedTodo, sampleAsynJackson.asyncJackson()); + } + + @Test + public void givenSampleApiAsyncCall_whenResponseIsMappedByGson_thenCompareResponseMappedByGson() throws Exception { + TodoAppClient sampleAsynGson = new TodoAppClient(); + assertEquals(expectedTodo, sampleAsynGson.asyncGson()); + } + +} diff --git a/core-java-modules/core-java-14/README.md b/core-java-modules/core-java-14/README.md index 00fd2fa320..97be9391fb 100644 --- a/core-java-modules/core-java-14/README.md +++ b/core-java-modules/core-java-14/README.md @@ -12,3 +12,4 @@ This module contains articles about Java 14. - [Java 14 Record Keyword](https://www.baeldung.com/java-record-keyword) - [New Features in Java 14](https://www.baeldung.com/java-14-new-features) - [Java 14 Record vs. Lombok](https://www.baeldung.com/java-record-vs-lombok) +- [Record vs. Final Class in Java](https://www.baeldung.com/java-record-vs-final-class) diff --git a/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/recordvsfinal/USCitizen.java b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/recordvsfinal/USCitizen.java new file mode 100644 index 0000000000..9ff3676ae7 --- /dev/null +++ b/core-java-modules/core-java-14/src/main/java/com/baeldung/java14/recordvsfinal/USCitizen.java @@ -0,0 +1,18 @@ +package com.baeldung.java14.recordvsfinal; + +public record USCitizen(String firstName, String lastName, String address) { + static int countryCode; + + // static initializer + static { + countryCode = 1; + } + + public static int getCountryCode() { + return countryCode; + } + + public String getFullName() { + return firstName + " " + lastName; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/recordvsfinal/USCitizenUnitTest.java b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/recordvsfinal/USCitizenUnitTest.java new file mode 100644 index 0000000000..bb4c16b500 --- /dev/null +++ b/core-java-modules/core-java-14/src/test/java/com/baeldung/java14/recordvsfinal/USCitizenUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.java14.recordvsfinal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class USCitizenUnitTest { + + @Test + public void givenName_whenGetNameAndCode_thenExpectedValuesReturned() { + + String firstName = "Joan"; + String lastName = "Winn"; + String address = "1892 Black Stallion Road"; + int countryCode = 1; + + USCitizen citizen = new USCitizen(firstName, lastName, address); + + assertEquals(firstName + " " + lastName, citizen.getFullName()); + assertEquals(countryCode, USCitizen.getCountryCode()); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/pom.xml b/core-java-modules/core-java-16/pom.xml index 4adc3ee6d1..a2c0d4855b 100644 --- a/core-java-modules/core-java-16/pom.xml +++ b/core-java-modules/core-java-16/pom.xml @@ -63,4 +63,4 @@ 3.0.0-M5 - \ No newline at end of file + diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/enumallt/DinosaurEnum.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/enumallt/DinosaurEnum.java new file mode 100644 index 0000000000..a50f79947c --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/enumallt/DinosaurEnum.java @@ -0,0 +1,19 @@ +package com.baeldung.instanceofalternative.enumallt; + +public enum DinosaurEnum { + Anatotitan { + @Override + public String move() { + return "running"; + } + }, + Euraptor { + @Override + public String move() { + return "flying"; + } + }; + + public abstract String move(); + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Anatotitan.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Anatotitan.java new file mode 100644 index 0000000000..ce59b58ad7 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Anatotitan.java @@ -0,0 +1,15 @@ +package com.baeldung.instanceofalternative.model; + +public class Anatotitan extends Dinosaur { + // polymorphism + @Override + public String move() { + return "running"; + } + + // non-polymorphism + public String run() { + return "running"; + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Dinosaur.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Dinosaur.java new file mode 100644 index 0000000000..38055054f5 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Dinosaur.java @@ -0,0 +1,9 @@ +package com.baeldung.instanceofalternative.model; + +public class Dinosaur { + + public String move() { + return "default movement"; + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Euraptor.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Euraptor.java new file mode 100644 index 0000000000..1de5257a0d --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/model/Euraptor.java @@ -0,0 +1,15 @@ +package com.baeldung.instanceofalternative.model; + +public class Euraptor extends Dinosaur { + // polymorphism + @Override + public String move() { + return "flying"; + } + + // non-polymorphism + public String flies() { + return "flying"; + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Anatotitan.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Anatotitan.java new file mode 100644 index 0000000000..84d93e7350 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Anatotitan.java @@ -0,0 +1,14 @@ +package com.baeldung.instanceofalternative.visitorspattern; + +public class Anatotitan implements Dino { + + String run() { + return "running"; + } + + @Override + public String move(Visitor dinobehave) { + return dinobehave.visit(this); + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Dino.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Dino.java new file mode 100644 index 0000000000..ef33baf2a4 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Dino.java @@ -0,0 +1,7 @@ +package com.baeldung.instanceofalternative.visitorspattern; + +public interface Dino { + + String move(Visitor dinoMove); + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/DinoVisitorImpl.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/DinoVisitorImpl.java new file mode 100644 index 0000000000..6fd71374fa --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/DinoVisitorImpl.java @@ -0,0 +1,15 @@ +package com.baeldung.instanceofalternative.visitorspattern; + +public class DinoVisitorImpl implements Visitor { + + @Override + public String visit(Anatotitan anatotitan) { + return anatotitan.run(); + } + + @Override + public String visit(Euraptor euraptor) { + return euraptor.flies(); + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Euraptor.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Euraptor.java new file mode 100644 index 0000000000..fdce1e6c0b --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Euraptor.java @@ -0,0 +1,14 @@ +package com.baeldung.instanceofalternative.visitorspattern; + +public class Euraptor implements Dino { + + String flies() { + return "flying"; + } + + @Override + public String move(Visitor dinobehave) { + return dinobehave.visit(this); + } + +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Visitor.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Visitor.java new file mode 100644 index 0000000000..75fada3533 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/instanceof_alternatives/visitorspattern/Visitor.java @@ -0,0 +1,9 @@ +package com.baeldung.instanceofalternative.visitorspattern; + +public interface Visitor { + + String visit(Anatotitan anatotitan); + + String visit(Euraptor euraptor); + +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/EnumUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/EnumUnitTest.java new file mode 100644 index 0000000000..73faa2a1ef --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/EnumUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.instanceoftest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.baeldung.instanceofalternative.enumallt.*; + +public class EnumUnitTest { + @Test + public void givenADinosaurSpecie_whenUsingEnum_thenGetMovementOfEuraptor() { + + assertEquals("flying", moveDinosaurUsingEnum(DinosaurEnum.Euraptor)); + } + + @Test + public void givenADinosaurSpecie_whenUsingEnum_thenGetMovementOfAnatotitan() { + assertEquals("running", moveDinosaurUsingEnum(DinosaurEnum.Anatotitan)); + } + + public static String moveDinosaurUsingEnum(DinosaurEnum dinosaurenum) { + return dinosaurenum.move(); + + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/ExampleSetupUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/ExampleSetupUnitTest.java new file mode 100644 index 0000000000..c42f77849b --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/ExampleSetupUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.instanceoftest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.baeldung.instanceofalternative.model.*; + +public class ExampleSetupUnitTest { + + @Test + public void givenADinosaurSpecie_whenUsingInstancof_thenGetMovementOfAnatotitan() { + + assertEquals("running", moveDinosaurUsingInstanceof(new Anatotitan())); + } + + @Test + public void givenADinosaurSpecie_whenUsingInstanceof_thenGetMovementOfEuraptor() { + assertEquals("flying", moveDinosaurUsingInstanceof(new Euraptor())); + } + + public static String moveDinosaurUsingInstanceof(Dinosaur dinosaur) { + + if (dinosaur instanceof Anatotitan) { + + Anatotitan anatotitan = (Anatotitan) dinosaur; + return anatotitan.run(); + } else if (dinosaur instanceof Euraptor) { + Euraptor euraptor = (Euraptor) dinosaur; + return euraptor.flies(); + } + return ""; + } + +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/GetClassUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/GetClassUnitTest.java new file mode 100644 index 0000000000..6a4886c8a3 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/GetClassUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.instanceoftest; + +import static org.junit.Assert.*; +import org.junit.Test; + +import com.baeldung.instanceofalternative.model.*; + +public class GetClassUnitTest { + + @Test + public void givenADinosaurSpecie_whenUsingGetClass_thenGetMovementOfAnatotitan() { + + assertEquals("running", moveDinosaurUsingGetClass(new Anatotitan())); + } + + @Test + public void givenADinosaurSpecie_whenUsingGetClass_thenGetMovementOfEuraptor() { + assertEquals("flying", moveDinosaurUsingGetClass(new Euraptor())); + } + + public static String moveDinosaurUsingGetClass(Dinosaur dinosaur) { + + if (dinosaur.getClass() + .equals(Anatotitan.class)) { + + Anatotitan anatotitan = (Anatotitan) dinosaur; + return anatotitan.run(); + } else if (dinosaur.getClass() + .equals(Euraptor.class)) { + Euraptor euraptor = (Euraptor) dinosaur; + return euraptor.flies(); + } + return ""; + } + +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/PolymorphismUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/PolymorphismUnitTest.java new file mode 100644 index 0000000000..960ed34c82 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/PolymorphismUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.instanceoftest; + +import static org.junit.Assert.*; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.baeldung.instanceofalternative.model.*; + +public class PolymorphismUnitTest { + + @Test + public void givenADinosaurSpecie_whenUsingPolymorphism_thenGetMovementOfAnatotitan() { + + assertEquals("running", moveDinosaurUsingPolymorphism(new Anatotitan())); + } + + @Test + public void givenADinosaurSpecie_whenUsingPolymorphism_thenGetMovementOfEuraptor() { + assertEquals("flying", moveDinosaurUsingPolymorphism(new Euraptor())); + } + + public static String moveDinosaurUsingPolymorphism(Dinosaur dinosaur) { + return dinosaur.move(); + } + +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/VisitorsPatternUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/VisitorsPatternUnitTest.java new file mode 100644 index 0000000000..287f7df798 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/instanceof_alternative_test/VisitorsPatternUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.instanceoftest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.baeldung.instanceofalternative.visitorspattern.*; + +public class VisitorsPatternUnitTest { + + @Test + public void givenADinosaurSpecie_whenUsingVisitorPattern_thenGetMovementOfAnatotitan() { + + assertEquals("running", moveDinosaurUsingVisitorPattern((Dino) new Anatotitan())); + } + + @Test + public void givenADinosaurSpecie_whenUsingVisitorPattern_thenGetMovementOfEuraptor() { + + assertEquals("flying", moveDinosaurUsingVisitorPattern((Dino) new Euraptor())); + } + + public static String moveDinosaurUsingVisitorPattern(Dino dinosaur) { + Visitor visitor = new DinoVisitorImpl(); + + return dinosaur.move(visitor); + } + +} diff --git a/core-java-modules/core-java-17/README.md b/core-java-modules/core-java-17/README.md index 9f39b0289f..1af860b7c4 100644 --- a/core-java-modules/core-java-17/README.md +++ b/core-java-modules/core-java-17/README.md @@ -6,3 +6,4 @@ - [New Features in Java 17](https://www.baeldung.com/java-17-new-features) - [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) diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Address.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Address.java new file mode 100644 index 0000000000..b654ffe2c5 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Address.java @@ -0,0 +1,40 @@ +package com.baeldung.java8to17; + +public class Address { + + private String street; + private String city; + private String pin; + + public Address(String street, String city, String pin) { + super(); + this.street = street; + this.city = city; + this.pin = pin; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getPin() { + return pin; + } + + public void setPin(String pin) { + this.pin = pin; + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Circle.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Circle.java new file mode 100644 index 0000000000..1e346653cf --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Circle.java @@ -0,0 +1,4 @@ +package com.baeldung.java8to17; + +public record Circle(double radius) implements Shape { +} \ No newline at end of file diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Person.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Person.java new file mode 100644 index 0000000000..a6c9f50fc8 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Person.java @@ -0,0 +1,30 @@ +package com.baeldung.java8to17; + +public class Person { + + private String name; + private Address address; + + public Person(String name, Address address) { + super(); + this.name = name; + this.address = address; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Rectangle.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Rectangle.java new file mode 100644 index 0000000000..79d2f0358b --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Rectangle.java @@ -0,0 +1,4 @@ +package com.baeldung.java8to17; + +public record Rectangle(double length, double width) implements Shape { +} \ No newline at end of file diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Shape.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Shape.java new file mode 100644 index 0000000000..60b5193468 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Shape.java @@ -0,0 +1,5 @@ +package com.baeldung.java8to17; + +public interface Shape { + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Student.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Student.java new file mode 100644 index 0000000000..056bc4b7d5 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/java8to17/Student.java @@ -0,0 +1,5 @@ +package com.baeldung.java8to17; + +public record Student(int rollNo, String name) { + +} diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/java17/Java8to17ExampleUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/java17/Java8to17ExampleUnitTest.java new file mode 100644 index 0000000000..950fc70988 --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/java17/Java8to17ExampleUnitTest.java @@ -0,0 +1,87 @@ +package com.baeldung.java17; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +import com.baeldung.java8to17.Address; +import com.baeldung.java8to17.Circle; +import com.baeldung.java8to17.Person; +import com.baeldung.java8to17.Rectangle; +import com.baeldung.java8to17.Student; + +public class Java8to17ExampleUnitTest { + + @Test + void givenMultiLineText_whenUsingTextBlock_thenStringIsReturned() { + String value = """ + This is a + Multi-line + Text + """; + + assertThat(value).isEqualTo("This is a\nMulti-line\nText\n"); + } + + @Test + void givenString_whenUsingUtilFunctions_thenReturnsExpectedResult() { + assertThat(" ".isBlank()); + assertThat("Twinkle ".repeat(2)).isEqualTo("Twinkle Twinkle "); + assertThat("Format Line".indent(4)).isEqualTo(" Format Line\n"); + assertThat("Line 1 \n Line2".lines()).asList().size().isEqualTo(2); + assertThat(" Text with white spaces ".strip()).isEqualTo("Text with white spaces"); + assertThat("Car, Bus, Train".transform(s1 -> Arrays.asList(s1.split(","))).get(0)).isEqualTo("Car"); + } + + @Test + void givenDataModel_whenUsingRecordType_thenBehavesLikeDTO() { + Student student = new Student(10, "Priya"); + Student student2 = new Student(10, "Priya"); + + assertThat(student.rollNo()).isEqualTo(10); + assertThat(student.name()).isEqualTo("Priya"); + assertThat(student.equals(student2)); + assertThat(student.hashCode()).isEqualTo(student2.hashCode()); + } + + @Test + void givenObject_whenThrowingNPE_thenReturnsHelpfulMessage() { + Person student = new Person("Lakshmi", new Address("35, West Street", null, null)); + + Exception exception = assertThrows(NullPointerException.class, () -> { + student.getAddress().getCity().toLowerCase(); + }); + + assertThat(exception.getMessage()).isEqualTo( + "Cannot invoke \"String.toLowerCase()\" because the return value of \"com.baeldung.java8to17.Address.getCity()\" is null"); + } + + @Test + void givenGenericObject_whenUsingPatternMatching_thenReturnsTargetType() { + String city = null; + Object obj = new Address("35, West Street", "Chennai", "6000041"); + + if (obj instanceof Address address) { + city = address.getCity(); + } + + assertThat(city).isEqualTo("Chennai"); + } + + @Test + void givenGenericObject_whenUsingSwitchExpression_thenPatternMatchesRightObject() { + Object shape = new Rectangle(10, 20); + + double circumference = switch (shape) { + case Rectangle r -> 2 * r.length() + 2 * r.width(); + case Circle c -> 2 * c.radius() * Math.PI; + default -> throw new IllegalArgumentException("Unknown shape"); + }; + + assertThat(circumference).isEqualTo(60); + } + +} diff --git a/core-java-modules/core-java-19/README.md b/core-java-modules/core-java-19/README.md new file mode 100644 index 0000000000..6a9c6c7fdd --- /dev/null +++ b/core-java-modules/core-java-19/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [Record Patterns in Java 19](https://www.baeldung.com/java-19-record-patterns) +- [Structured Concurrency in Java 19](https://www.baeldung.com/java-structured-concurrency) diff --git a/core-java-modules/core-java-19/pom.xml b/core-java-modules/core-java-19/pom.xml new file mode 100644 index 0000000000..096b13e679 --- /dev/null +++ b/core-java-modules/core-java-19/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + core-java-19 + + + 19 + 19 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 19 + 19 + --enable-preview + + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java new file mode 100644 index 0000000000..961575c88d --- /dev/null +++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java @@ -0,0 +1,3 @@ +package com.baeldung.features.records; + +public record GPSPoint (double lat, double lng) { } \ No newline at end of file diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java new file mode 100644 index 0000000000..00851c8d5e --- /dev/null +++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java @@ -0,0 +1,9 @@ +package com.baeldung.features.records; + +public sealed interface ILocation permits Location { + default String getName() { + return switch (this) { + case Location(var name, var ignored) -> name; + }; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java new file mode 100644 index 0000000000..fb50fbe645 --- /dev/null +++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java @@ -0,0 +1,5 @@ +package com.baeldung.features.records; + +public record Location(String name, GPSPoint gpsPoint) implements ILocation { +} + diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java new file mode 100644 index 0000000000..e7ddfef5f0 --- /dev/null +++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java @@ -0,0 +1,3 @@ +package com.baeldung.features.records; + +public record LocationWrapper(T t, String description) { } diff --git a/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java new file mode 100644 index 0000000000..10ad33b411 --- /dev/null +++ b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java @@ -0,0 +1,99 @@ +package com.baeldung.features; + +import com.baeldung.features.records.GPSPoint; +import com.baeldung.features.records.Location; +import com.baeldung.features.records.LocationWrapper; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + + +public class JEP405RecordPatternsUnitTest { + + Object object = new Location("Home", new GPSPoint(1.0, 2.0)); + + @Test + void givenObject_whenTestInstanceOfAndCastIdiom_shouldMatchNewInstanceOf() { + // old Code + if (object instanceof Location) { + Location l = (Location) object; + assertThat(l).isInstanceOf(Location.class); + } + // new code + if (object instanceof Location l) { + assertThat(l).isInstanceOf(Location.class); + } + } + + @Test + void givenObject_whenTestDestruct_shouldMatch() { + // when + if (object instanceof Location(var name, var gpsPoint)) { + // then + assertThat(name).isEqualTo("Home"); + assertThat(gpsPoint).isInstanceOf(GPSPoint.class); + } + + if (object instanceof Location(var name, GPSPoint(var lat, var lng))) { + assertThat(lat).isEqualTo(1.0); + assertThat(lng).isEqualTo(2.0); + } + } + + @Test + void givenObjectIsNull_whenTestNullCheck_shouldNotMatch() { + Location l = null; + if (l instanceof Location location) { + assertThat(location).isNotNull(); + } + } + + + @Test + void givenObject_whenTestGenericTypeInstanceOf_shouldMatch() { + LocationWrapper locationWrapper = new LocationWrapper<>(new Location("Home", new GPSPoint(1.0, 2.0)), "Description"); + if (locationWrapper instanceof LocationWrapper(var ignored, var description)) { + assertThat(description).isEqualTo("Description"); + } + } + + + @Test + void givenObject_whenTestSwitchExpressionWithTypePattern_shouldMatch() { + String result = switch (object) { + case Location l -> l.name(); + default -> "default"; + }; + assertThat(result).isEqualTo("Home"); + Double result2 = switch (object) { + case Location(var name, GPSPoint(var lat, var lng)) -> lat; + default -> 0.0; + }; + assertThat(result2).isEqualTo(1.0); + } + + @Test + void givenObject_whenTestGuardedSwitchExpressionWithTypePattern_shouldMatchAndGuard() { + String result = switch (object) { + case Location(var name, var ignored) when name.equals("Home") -> "Test"; + case Location(var name, var ignored) -> name; + default -> "default"; + }; + assertThat(result).isEqualTo("Test"); + + String otherResult = switch (new Location("Other", new GPSPoint(1.0, 2.0))) { + case Location(var name, var ignored) when name.equals("Home") -> "Test"; + case Location(var name, var ignored) -> name; + default -> "default"; + }; + assertThat(otherResult).isEqualTo("Other"); + + Object noLocation = new GPSPoint(1.0, 2.0); + String noLocationResult = switch (noLocation) { + case Location(var name, var ignored) when name.equals("Home") -> "Test"; + case Location(var name, var ignored) -> name; + default -> "default"; + }; + assertThat(noLocationResult).isEqualTo("default"); + } +} diff --git a/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP428StructuredConcurrencyUnitTest.java b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP428StructuredConcurrencyUnitTest.java new file mode 100644 index 0000000000..64cd84ba01 --- /dev/null +++ b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP428StructuredConcurrencyUnitTest.java @@ -0,0 +1,122 @@ +package com.baeldung.features; + +import jdk.incubator.concurrent.StructuredTaskScope; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.util.List; +import java.util.concurrent.*; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +public class JEP428StructuredConcurrencyUnitTest { + + private static final String ERROR_MESSAGE = "Failed to get the result"; + + @Test + public void givenStructuredConcurrency_whenThrowingException_thenCorrect() { + assertThatThrownBy(() -> { + try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { + Future shelter = scope.fork(this::getShelter); + Future> dogs = scope.fork(this::getDogsWithException); + scope.throwIfFailed(e -> new RuntimeException(ERROR_MESSAGE)); + scope.join(); + Response response = new Response(shelter.resultNow(), dogs.resultNow()); + + assertThat(response).isNotNull(); + assertThat(response.shelter()).isNotNull(); + assertThat(response.dogs()).isNotNull(); + assertThat(response.dogs().size()).isEqualTo(2); + } + }).isInstanceOf(RuntimeException.class) + .hasMessage(ERROR_MESSAGE); + } + + @Test + public void givenStructuredConcurrency_whenSlowTasksReachesDeadline_thenCorrect() { + assertThatThrownBy(() -> { + try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { + Future shelter = scope.fork(this::getShelter); + Future> dogs = scope.fork(this::getDogsSlowly); + scope.throwIfFailed(e -> new RuntimeException(ERROR_MESSAGE)); + scope.join(); + scope.joinUntil(Instant.now().plusMillis(50)); + Response response = new Response(shelter.resultNow(), dogs.resultNow()); + + assertThat(response).isNotNull(); + assertThat(response.shelter()).isNotNull(); + assertThat(response.dogs()).isNotNull(); + assertThat(response.dogs().size()).isEqualTo(2); + + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }).isInstanceOf(IllegalStateException.class); + } + + @Test + public void givenStructuredConcurrency_whenResultNow_thenCorrect() { + try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { + Future shelter = scope.fork(this::getShelter); + Future> dogs = scope.fork(this::getDogs); + scope.join(); + + Response response = new Response(shelter.resultNow(), dogs.resultNow()); + + assertThat(response).isNotNull(); + assertThat(response.shelter()).isNotNull(); + assertThat(response.dogs()).isNotNull(); + assertThat(response.dogs().size()).isEqualTo(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Test + public void givenUnstructuredConcurrency_whenGet_thenCorrect() { + Future shelter; + Future> dogs; + try (ExecutorService executorService = Executors.newFixedThreadPool(3)) { + shelter = executorService.submit(this::getShelter); + dogs = executorService.submit(this::getDogs); + Shelter theShelter = shelter.get(); // Join the shelter + List theDogs = dogs.get(); // Join the dogs + Response response = new Response(theShelter, theDogs); + + assertThat(response).isNotNull(); + assertThat(response.shelter()).isNotNull(); + assertThat(response.dogs()).isNotNull(); + assertThat(response.dogs().size()).isEqualTo(2); + + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + private Shelter getShelter() { + return new Shelter("Shelter"); + } + + private List getDogs() { + return List.of(new Dog("Buddy"), new Dog("Simba")); + } + + private List getDogsWithException() { + throw new RuntimeException(ERROR_MESSAGE); + } + + private List getDogsSlowly() throws InterruptedException { + Thread.sleep(1500); + throw new RuntimeException(ERROR_MESSAGE); + } + + record Shelter(String name) { + } + + record Dog(String name) { + } + + record Response(Shelter shelter, List dogs) { + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-8-2/README.md b/core-java-modules/core-java-8-2/README.md index c0bc63f21f..cad4a4f1fa 100644 --- a/core-java-modules/core-java-8-2/README.md +++ b/core-java-modules/core-java-8-2/README.md @@ -10,4 +10,5 @@ This module contains articles about Java 8 core features - [Interface With Default Methods vs Abstract Class](https://www.baeldung.com/java-interface-default-method-vs-abstract-class) - [Convert Between Byte Array and UUID in Java](https://www.baeldung.com/java-byte-array-to-uuid) - [Create a Simple “Rock-Paper-Scissors” Game in Java](https://www.baeldung.com/java-rock-paper-scissors) +- [VarArgs vs Array Input Parameters in Java](https://www.baeldung.com/varargs-vs-array) - [[<-- Prev]](/core-java-modules/core-java-8) diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/argsVsvarargs/StringArrayAndVarargs.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/argsVsvarargs/StringArrayAndVarargs.java new file mode 100644 index 0000000000..dc9137646f --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/argsVsvarargs/StringArrayAndVarargs.java @@ -0,0 +1,19 @@ +package com.baeldung.argsVsvarargs; + +public class StringArrayAndVarargs { + public static void capitalizeNames(String[] args) { + for(int i = 0; i < args.length; i++){ + args[i] = args[i].toUpperCase(); + } + + } + + public static String[] firstLetterOfWords(String... args) { + String[] firstLetter = new String[args.length]; + for(int i = 0; i < args.length; i++){ + firstLetter[i] = String.valueOf(args[i].charAt(0)); + } + return firstLetter; + } + +} diff --git a/core-java-modules/core-java-8-2/src/test/java/com/baeldung/argsVsvarargs/StringArrayAndVarargsUnitTest.java b/core-java-modules/core-java-8-2/src/test/java/com/baeldung/argsVsvarargs/StringArrayAndVarargsUnitTest.java new file mode 100644 index 0000000000..f917373229 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/test/java/com/baeldung/argsVsvarargs/StringArrayAndVarargsUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.argsVsvarargs; + +import static com.baeldung.argsVsvarargs.StringArrayAndVarargs.capitalizeNames; +import static com.baeldung.argsVsvarargs.StringArrayAndVarargs.firstLetterOfWords; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class StringArrayAndVarargsUnitTest { + + @Test + void whenCheckingArgumentClassName_thenNameShouldBeStringArray() { + String[] names = {"john", "ade", "kofi", "imo"}; + assertNotNull(names); + assertEquals("java.lang.String[]", names.getClass().getTypeName()); + capitalizeNames(names); + } + + @Test + void whenCheckingReturnedObjectClass_thenClassShouldBeStringArray() { + assertEquals(String[].class, firstLetterOfWords("football", "basketball", "volleyball").getClass()); + assertEquals(3, firstLetterOfWords("football", "basketball", "volleyball").length); + } +} \ 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 ff4ceaf6db..6061f3318d 100644 --- a/core-java-modules/core-java-8/README.md +++ b/core-java-modules/core-java-8/README.md @@ -11,4 +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) - [[More -->]](/core-java-modules/core-java-8-2) diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/monad/MonadSamples.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/monad/MonadSamples.java new file mode 100644 index 0000000000..87b7fe697e --- /dev/null +++ b/core-java-modules/core-java-8/src/main/java/com/baeldung/monad/MonadSamples.java @@ -0,0 +1,82 @@ +package com.baeldung.monad; + +import java.util.Optional; +import java.util.function.Function; + +class MonadBaseExample { + + public double multiplyBy2(double n) { + return n * 2; + } + + public double divideBy2(double n) { + return n / 2; + } + + public double add3(double n) { + return n + 3; + } + + public double subtract1(double n) { + return n - 1; + } + +} + +class MonadSample1 extends MonadBaseExample { + + public double apply(double n) { + return subtract1(add3(divideBy2(multiplyBy2(multiplyBy2(2))))); + } +} + +class MonadSample2 extends MonadBaseExample { + public double apply(double n) { + double n1 = multiplyBy2(n); + double n2 = multiplyBy2(n1); + double n3 = divideBy2(n2); + double n4 = add3(n3); + return subtract1(n4); + } +} + +class MonadSample3 extends MonadBaseExample { + + public double apply(double n) { + return Optional.of(n) + .flatMap(value -> Optional.of(multiplyBy2(value))) + .flatMap(value -> Optional.of(multiplyBy2(value))) + .flatMap(value -> Optional.of(divideBy2(value))) + .flatMap(value -> Optional.of(add3(value))) + .flatMap(value -> Optional.of(subtract1(value))) + .get(); + } + +} + + class MonadSample4 extends MonadBaseExample { + public boolean leftIdentity() { + Function> mapping = value -> Optional.of(value + 1); + return Optional.of(3).flatMap(mapping).equals(mapping.apply(3)); + } + + public boolean rightIdentity() { + return Optional.of(3).flatMap(Optional::of).equals(Optional.of(3)); + } + + public boolean associativity() { + Function> mapping = value -> Optional.of(value + 1); + Optional leftSide = Optional.of(3).flatMap(mapping).flatMap(Optional::of); + Optional rightSide = Optional.of(3).flatMap(v -> mapping.apply(v).flatMap(Optional::of)); + return leftSide.equals(rightSide); + } + + } + +class MonadSample5 extends MonadBaseExample { + public boolean fail() { + Function> mapping = value -> Optional.of(value == null ? -1 : value + 1); + return Optional.ofNullable((Integer) null).flatMap(mapping).equals(mapping.apply(null)); + } +} + diff --git a/core-java-modules/core-java-8/src/test/java/com/baeldung/monad/MonadSampleUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/baeldung/monad/MonadSampleUnitTest.java new file mode 100644 index 0000000000..c851f5f750 --- /dev/null +++ b/core-java-modules/core-java-8/src/test/java/com/baeldung/monad/MonadSampleUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.monad; + +import org.junit.Assert; +import org.junit.Test; + +public class MonadSampleUnitTest { + + @Test + public void whenNotUsingMonad_shouldBeOk() { + MonadSample1 test = new MonadSample1(); + Assert.assertEquals(6.0, test.apply(2), 0.000); + } + + @Test + public void whenNotUsingMonadButUsingTempVars_shouldBeOk() { + MonadSample2 test = new MonadSample2(); + Assert.assertEquals(6.0, test.apply(2), 0.000); + } + + @Test + public void whenUsingMonad_shouldBeOk() { + MonadSample3 test = new MonadSample3(); + Assert.assertEquals(6.0, test.apply(2), 0.000); + } + + @Test + public void whenTestingMonadProperties_shouldBeOk() { + MonadSample4 test = new MonadSample4(); + Assert.assertEquals(true, test.leftIdentity()); + Assert.assertEquals(true, test.rightIdentity()); + Assert.assertEquals(true, test.associativity()); + } + + @Test + public void whenBreakingMonadProperties_shouldBeFalse() { + MonadSample5 test = new MonadSample5(); + Assert.assertEquals(false, test.fail()); + } +} diff --git a/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/ClassWithSuppressWarningsNames.java b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/ClassWithSuppressWarningsNames.java index aad7cf49eb..d0a325a155 100644 --- a/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/ClassWithSuppressWarningsNames.java +++ b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/ClassWithSuppressWarningsNames.java @@ -17,7 +17,7 @@ public class ClassWithSuppressWarningsNames implements Serializable { list.add(Integer.valueOf(value)); } - @SuppressWarnings("deprecated") + @SuppressWarnings("deprecation") void suppressDeprecatedWarning() { ClassWithSuppressWarningsNames cls = new ClassWithSuppressWarningsNames(); cls.deprecatedMethod(); // no warning here diff --git a/core-java-modules/core-java-arrays-convert/README.md b/core-java-modules/core-java-arrays-convert/README.md index b28b97cb09..4365fd12f9 100644 --- a/core-java-modules/core-java-arrays-convert/README.md +++ b/core-java-modules/core-java-arrays-convert/README.md @@ -6,3 +6,4 @@ This module contains articles about arrays conversion in Java - [Convert a Float to a Byte Array in Java](https://www.baeldung.com/java-convert-float-to-byte-array) - [Converting Between Stream and Array in Java](https://www.baeldung.com/java-stream-to-array) - [Convert a Byte Array to a Numeric Representation in Java](https://www.baeldung.com/java-byte-array-to-number) +- [Converting a String Array Into an int Array in Java](https://www.baeldung.com/java-convert-string-array-to-int-array) diff --git a/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/StringArrayToIntArrayUnitTest.java b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/StringArrayToIntArrayUnitTest.java new file mode 100644 index 0000000000..3675778f90 --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/StringArrayToIntArrayUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.array.conversions; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + +public class StringArrayToIntArrayUnitTest { + private final String[] stringArray = new String[] { "1", "2", "3", "4", "5", "6", "42" }; + private final int[] expected = new int[] { 1, 2, 3, 4, 5, 6, 42 }; + + private final String[] stringArrayWithInvalidNum = new String[] { "1", "2", "hello", "4", "world", "6", "42" }; + private final int[] expectedWithInvalidInput = new int[] { 1, 2, Integer.MIN_VALUE, 4, Integer.MIN_VALUE, 6, 42 }; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + void givenStringArray_whenUseStreamApi_shouldGetExpectedIntArray() { + int[] result = Arrays.stream(stringArray).mapToInt(Integer::parseInt).toArray(); + assertArrayEquals(expected, result); + } + + @Test + void givenStringArrayWithInvalidNum_whenUseStreamApi_shouldGetExpectedIntArray() { + int[] result = Arrays.stream(stringArrayWithInvalidNum).mapToInt(s -> { + try { + return Integer.parseInt(s); + } catch (NumberFormatException ex) { + logger.warn("Invalid number format detected: {}, use Int.MinValue as the fallback", s); + return Integer.MIN_VALUE; + } + }).toArray(); + assertArrayEquals(expectedWithInvalidInput, result); + } + + @Test + void givenStringArray_whenConvertInLoop_shouldGetExpectedIntArray() { + int[] result = new int[stringArray.length]; + for (int i = 0; i < stringArray.length; i++) { + result[i] = Integer.parseInt(stringArray[i]); + } + assertArrayEquals(expected, result); + } + + @Test + void givenStringArrayWithInvalidNum_whenConvertInLoop_shouldGetExpectedIntArray() { + int[] result = new int[stringArrayWithInvalidNum.length]; + for (int i = 0; i < stringArrayWithInvalidNum.length; i++) { + try { + result[i] = Integer.parseInt(stringArrayWithInvalidNum[i]); + } catch (NumberFormatException exception) { + logger.warn("Invalid number format detected: [{}], use Int.MinValue as the fallback", stringArrayWithInvalidNum[i]); + result[i] = Integer.MIN_VALUE; + } + } + + assertArrayEquals(expectedWithInvalidInput, result); + } +} diff --git a/core-java-modules/core-java-arrays-operations-basic/src/test/java/com/baeldung/array/isobjectarray/CheckObjectIsArrayUnitTest.java b/core-java-modules/core-java-arrays-operations-basic/src/test/java/com/baeldung/array/isobjectarray/CheckObjectIsArrayUnitTest.java new file mode 100644 index 0000000000..ed38ab0765 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-basic/src/test/java/com/baeldung/array/isobjectarray/CheckObjectIsArrayUnitTest.java @@ -0,0 +1,78 @@ +package com.baeldung.array.isobjectarray; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Array; + +import org.junit.jupiter.api.Test; + +public class CheckObjectIsArrayUnitTest { + private static final Object ARRAY_INT = new int[] { 1, 2, 3, 4, 5 }; + private static final Object ARRAY_PERSON = new Person[] { new Person("Jackie Chan", "Hong Kong"), new Person("Tom Hanks", "United States") }; + + boolean isArray(Object obj) { + return obj instanceof Object[] || obj instanceof boolean[] || obj instanceof byte[] || obj instanceof short[] || obj instanceof char[] || obj instanceof int[] || obj instanceof long[] || obj instanceof float[] || obj instanceof double[]; + } + + @Test + void givenAnArrayObject_whenUsingInstanceof_getExpectedResult() { + assertTrue(ARRAY_PERSON instanceof Object[]); + assertFalse(ARRAY_INT instanceof Object[]); + assertTrue(ARRAY_INT instanceof int[]); + } + + @Test + void givenAnArrayObject_whenUsingOurIsArray_getExpectedResult() { + assertTrue(isArray(ARRAY_PERSON)); + assertTrue(isArray(ARRAY_INT)); + } + + @Test + void givenAnArrayObject_whenUsingClassIsArray_getExpectedResult() { + assertTrue(ARRAY_INT.getClass() + .isArray()); + assertTrue(ARRAY_PERSON.getClass() + .isArray()); + + assertEquals(Person.class, ARRAY_PERSON.getClass() + .getComponentType()); + assertEquals(int.class, ARRAY_INT.getClass() + .getComponentType()); + + } + + @Test + void givenAnArrayObject_whenUsingArrayGet_getExpectedElement() { + if (ARRAY_PERSON.getClass() + .isArray() && ARRAY_PERSON.getClass() + .getComponentType() == Person.class) { + Person person = (Person) Array.get(ARRAY_PERSON, 1); + assertEquals("Tom Hanks", person.getName()); + } + if (ARRAY_INT.getClass() + .isArray() && ARRAY_INT.getClass() + .getComponentType() == int.class) { + assertEquals(2, ((int) Array.get(ARRAY_INT, 1))); + } + } +} + +class Person { + private String name; + private String Location; + + public Person(String name, String location) { + this.name = name; + this.Location = location; + } + + public String getName() { + return name; + } + + public String getLocation() { + return Location; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-2/README.md b/core-java-modules/core-java-collections-2/README.md index d482ed7773..5a9bae8f9f 100644 --- a/core-java-modules/core-java-collections-2/README.md +++ b/core-java-modules/core-java-collections-2/README.md @@ -13,3 +13,4 @@ - [Getting the Size of an Iterable in Java](https://www.baeldung.com/java-iterable-size) - [Java Null-Safe Streams from Collections](https://www.baeldung.com/java-null-safe-streams-from-collections) - [Differences Between Iterator and Iterable and How to Use Them?](https://www.baeldung.com/java-iterator-vs-iterable) +- More articles: [[<-- prev]](/core-java-modules/core-java-collections) [[next -->]](/core-java-modules/core-java-collections-3) diff --git a/core-java-modules/core-java-collections-3/README.md b/core-java-modules/core-java-collections-3/README.md index 4249d8ad30..4c0657da2d 100644 --- a/core-java-modules/core-java-collections-3/README.md +++ b/core-java-modules/core-java-collections-3/README.md @@ -6,7 +6,7 @@ - [Time Comparison of Arrays.sort(Object[]) and Arrays.sort(int[])](https://www.baeldung.com/arrays-sortobject-vs-sortint) - [Java ArrayList vs Vector](https://www.baeldung.com/java-arraylist-vs-vector) -- [Differences Between HashMap and Hashtable](https://www.baeldung.com/hashmap-hashtable-differences) +- [Differences Between HashMap and Hashtable in Java](https://www.baeldung.com/hashmap-hashtable-differences) - [Differences Between Collection.clear() and Collection.removeAll()](https://www.baeldung.com/java-collection-clear-vs-removeall) - [Performance of contains() in a HashSet vs ArrayList](https://www.baeldung.com/java-hashset-arraylist-contains-performance) - [Fail-Safe Iterator vs Fail-Fast Iterator](https://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator) diff --git a/core-java-modules/core-java-collections-4/README.md b/core-java-modules/core-java-collections-4/README.md index cdb457e342..460af21179 100644 --- a/core-java-modules/core-java-collections-4/README.md +++ b/core-java-modules/core-java-collections-4/README.md @@ -7,7 +7,11 @@ - [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap) - [Java Deque vs. Stack](https://www.baeldung.com/java-deque-vs-stack) - [Collection.toArray(new T[0]) or .toArray(new T[size])](https://www.baeldung.com/java-collection-toarray-methods) -- [Create an Empty Map in Java](https://www.baeldung.com/java-create-empty-map) - [Sorting Objects in a List by Date](https://www.baeldung.com/java-sort-list-by-date) - [Fixed Size Queue Implementations in Java](https://www.baeldung.com/java-fixed-size-queue) - [Difference Between Java Enumeration and Iterator](https://www.baeldung.com/java-enumeration-vs-iterator) +- [Sort Collection of Objects by Multiple Fields in Java](https://www.baeldung.com/java-sort-collection-multiple-fields) +- [Guide to Java PriorityQueue](https://www.baeldung.com/java-priorityqueue) +- [Java Generics PECS – Producer Extends Consumer Super](https://www.baeldung.com/java-generics-pecs) +- [Reversing a Stack in Java](https://www.baeldung.com/java-reversing-a-stack) +- More articles: [[<-- prev]](/core-java-modules/core-java-collections-3) \ No newline at end of file diff --git a/core-java-modules/core-java-collections-4/pom.xml b/core-java-modules/core-java-collections-4/pom.xml index 51e2d6e0ee..e88d5a6740 100644 --- a/core-java-modules/core-java-collections-4/pom.xml +++ b/core-java-modules/core-java-collections-4/pom.xml @@ -25,6 +25,12 @@ commons-lang3 ${commons-lang3.version} + + org.junit.platform + junit-platform-runner + ${junit-platform.version} + test + @@ -32,4 +38,4 @@ 3.12.0 - + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/ProducerExtendsConsumerSupers.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/ProducerExtendsConsumerSupers.java new file mode 100644 index 0000000000..3c4b136b09 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/ProducerExtendsConsumerSupers.java @@ -0,0 +1,59 @@ +package com.baeldung.collections.pecs; + +import java.util.Arrays; +import java.util.List; + +import com.baeldung.collections.pecs.model.Customer; +import com.baeldung.collections.pecs.model.Operator; +import com.baeldung.collections.pecs.model.User; + +public class ProducerExtendsConsumerSupers { + + public void producerExtends() { + List operators = Arrays.asList(new Operator("sam"), new Operator("daniel")); + List customers = Arrays.asList(new Customer("arys"), new Customer("cristiana")); + + // sendEmails(operators); --> will not compile! + sendEmailsFixed(operators); + sendEmailsFixed(customers); + } + + private void sendEmails(List users) { + for (User user : users) { + System.out.println("sending email to " + user); + } + } + + private void sendEmailsFixed(List users) { + for (User user : users) { + System.out.println("sending email to " + user); + } + } + + public void consumerSupers() { + List allOperators = Arrays.asList(new Operator("tom")); + List allUsers = Arrays.asList(new Operator("tom"), new Customer("spencer")); + + // addUsersFromMarketingDepartment(allUsers); --> will not compile! + addUsersFromMarketingDepartmentFixed(allOperators); + addUsersFromMarketingDepartmentFixed(allUsers); + } + + private void addUsersFromMarketingDepartment(List users) { + users.add(new Operator("john doe")); + users.add(new Operator("jane doe")); + } + + private void addUsersFromMarketingDepartmentFixed(List users) { + users.add(new Operator("john doe")); + users.add(new Operator("jane doe")); + } + + private void addUsersAndSendEmails(List users) { + users.add(new Operator("john doe")); + for (User user : users) { + System.out.println("sending email to: " + user); + } + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Customer.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Customer.java new file mode 100644 index 0000000000..b3e97deddb --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Customer.java @@ -0,0 +1,7 @@ +package com.baeldung.collections.pecs.model; + +public class Customer extends User { + public Customer(String name) { + super(name); + } +} diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Operator.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Operator.java new file mode 100644 index 0000000000..e998088496 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/Operator.java @@ -0,0 +1,7 @@ +package com.baeldung.collections.pecs.model; + +public class Operator extends User { + public Operator(String name) { + super(name); + } +} diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/User.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/User.java new file mode 100644 index 0000000000..a0d9d6a9b7 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/pecs/model/User.java @@ -0,0 +1,9 @@ +package com.baeldung.collections.pecs.model; + +public class User { + private final String name; + + public User(String name) { + this.name = name; + } +} diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumber.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumber.java new file mode 100644 index 0000000000..554a13d642 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumber.java @@ -0,0 +1,27 @@ +package com.baeldung.collections.priorityqueue; + +public final class ColoredNumber { + private int value; + private String color; + + public ColoredNumber(int value, String color) { + this.value = value; + this.color = color; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumberComparable.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumberComparable.java new file mode 100644 index 0000000000..0e9a5ec498 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/priorityqueue/ColoredNumberComparable.java @@ -0,0 +1,44 @@ +package com.baeldung.collections.priorityqueue; + +public final class ColoredNumberComparable implements Comparable { + private int value; + private String color; + + public ColoredNumberComparable(int value, String color) { + this.value = value; + this.color = color; + } + + @Override + public int compareTo(ColoredNumberComparable o) { + // (both numbers are red) or (both numbers are not red) + if ((this.color.equals("red") && o.color.equals("red")) || + (!this.color.equals("red") && !o.color.equals("red"))) { + return Integer.compare(this.value, o.value); + } + // only the first number is red + else if (this.color.equals("red")) { + return -1; + } + // only the second number is red + else { + return 1; + } + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingQueue.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingQueue.java new file mode 100644 index 0000000000..6851ed7e88 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingQueue.java @@ -0,0 +1,42 @@ +package com.baeldung.collections.stackreversal; + +import com.baeldung.collections.sorting.Employee; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +public class ReverseStackUsingQueue { + public Stack reverseIntegerStack(Stack inputStack) { + Queue queue = new LinkedList<>(); + while (!inputStack.isEmpty()) { + queue.add(inputStack.pop()); + } + while (!queue.isEmpty()) { + inputStack.add(queue.remove()); + } + return inputStack; + } + + public Stack reverseStringStack(Stack inputStack) { + Queue queue = new LinkedList<>(); + while (!inputStack.isEmpty()) { + queue.add(inputStack.pop()); + } + while (!queue.isEmpty()) { + inputStack.add(queue.remove()); + } + return inputStack; + } + + public Stack reverseEmployeeStack(Stack inputStack) { + Queue employeeQ = new LinkedList<>(); + while (!inputStack.isEmpty()) { + employeeQ.add(inputStack.pop()); + } + while (!employeeQ.isEmpty()) { + inputStack.add(employeeQ.remove()); + } + return inputStack; + } +} diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingRecursion.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingRecursion.java new file mode 100644 index 0000000000..8dbe0c39a6 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/stackreversal/ReverseStackUsingRecursion.java @@ -0,0 +1,29 @@ +package com.baeldung.collections.stackreversal; + +import java.util.Stack; + +public class ReverseStackUsingRecursion { + public Stack reverseIntegerStack(Stack inputStack) { + reverseStack(inputStack); + return inputStack; + } + + private void reverseStack(Stack stack) { + if (stack.isEmpty()) { + return; + } + int top = stack.pop(); + reverseStack(stack); + insertBottom(stack, top); + } + + private void insertBottom(Stack stack, int value) { + if (stack.isEmpty()) { + stack.add(value); + } else { + int top = stack.pop(); + insertBottom(stack, value); + stack.add(top); + } + } +} diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java index 3b595472e0..7d4ec8249c 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/HashMapUnitTest.java @@ -2,9 +2,7 @@ package com.baeldung.collections.comparation; import org.junit.jupiter.api.Test; -import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java index aa6b7fa923..00a188737d 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/comparation/LinkedListUnitTest.java @@ -2,10 +2,8 @@ package com.baeldung.collections.comparation; import org.junit.jupiter.api.Test; -import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/priorityqueue/PriorityQueueComparatorUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/priorityqueue/PriorityQueueComparatorUnitTest.java new file mode 100644 index 0000000000..db10fa1ae8 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/priorityqueue/PriorityQueueComparatorUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.collections.priorityqueue; + +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.PriorityQueue; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class PriorityQueueComparatorUnitTest { + + @Test + void givenIntegerQueue_defaultComparator_followsNaturalOrdering() { + PriorityQueue integerQueue = new PriorityQueue<>(); + PriorityQueue integerQueueWithComparator = new PriorityQueue<>((Integer c1, Integer c2) -> Integer.compare(c1, c2)); + + integerQueueWithComparator.add(3); + integerQueue.add(3); + + integerQueueWithComparator.add(2); + integerQueue.add(2); + + integerQueueWithComparator.add(1); + integerQueue.add(1); + + assertThat(integerQueue.poll()).isEqualTo(1).isEqualTo(integerQueueWithComparator.poll()); + assertThat(integerQueue.poll()).isEqualTo(2).isEqualTo(integerQueueWithComparator.poll()); + assertThat(integerQueue.poll()).isEqualTo(3).isEqualTo(integerQueueWithComparator.poll()); + } + + @Test + void givenIntegerQueue_reverseOrderComparator_followsInverseNaturalOrdering() { + PriorityQueue reversedQueue = new PriorityQueue<>(Collections.reverseOrder()); + + reversedQueue.add(1); + reversedQueue.add(2); + reversedQueue.add(3); + + assertThat(reversedQueue.poll()).isEqualTo(3); + assertThat(reversedQueue.poll()).isEqualTo(2); + assertThat(reversedQueue.poll()).isEqualTo(1); + } + + @Test + void givenNotComparableQueue_classCastException() { + assertThatThrownBy(() -> { + PriorityQueue queue = new PriorityQueue<>(); + queue.add(new ColoredNumber(3, "red")); + queue.add(new ColoredNumber(2, "blue")); + }).isInstanceOf(ClassCastException.class); + } + + @Test + void givenCustomOrderingQueue_orderIsCorrect() { + PriorityQueue queue = new PriorityQueue<>(); + queue.add(new ColoredNumberComparable(10, "red")); + queue.add(new ColoredNumberComparable(20, "red")); + queue.add(new ColoredNumberComparable(1, "blue")); + queue.add(new ColoredNumberComparable(2, "blue")); + + ColoredNumberComparable first = queue.poll(); + assertThat(first.getColor()).isEqualTo("red"); + assertThat(first.getValue()).isEqualTo(10); + + queue.poll(); + + ColoredNumberComparable third = queue.poll(); + assertThat(third.getColor()).isEqualTo("blue"); + assertThat(third.getValue()).isEqualTo(1); + } + +} + diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/EmployeeSortingByDateUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/EmployeeSortingByDateUnitTest.java index 250fb7b62b..de2f3d8ca7 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/EmployeeSortingByDateUnitTest.java +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/EmployeeSortingByDateUnitTest.java @@ -10,7 +10,7 @@ import java.util.Date; import java.util.List; import org.apache.commons.lang.time.DateUtils; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EmployeeSortingByDateUnitTest { diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/multiple/ComparatorsUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/multiple/ComparatorsUnitTest.java index 4608730567..e1297456be 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/multiple/ComparatorsUnitTest.java +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/sorting/multiple/ComparatorsUnitTest.java @@ -5,8 +5,9 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -import org.junit.Test; + import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class ComparatorsUnitTest { @Test diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/stackreversal/StackReversalUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/stackreversal/StackReversalUnitTest.java new file mode 100644 index 0000000000..ccadc4e7d3 --- /dev/null +++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/stackreversal/StackReversalUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.stackreversal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.baeldung.collections.sorting.Employee; +import com.baeldung.collections.stackreversal.ReverseStackUsingQueue; +import com.baeldung.collections.stackreversal.ReverseStackUsingRecursion; + +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.stream.Collectors; + +public class StackReversalUnitTest { + @Test + public void whenIntegerStack_thenReturnReversedIntegerStack(){ + ReverseStackUsingQueue reverseStack = new ReverseStackUsingQueue(); + Stack originalStack = generateStackFromGivenList(Arrays.stream(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).boxed().collect(Collectors.toList()), new Stack()); + Stack reverseList = generateStackFromGivenList(Arrays.stream(new int[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}).boxed().collect(Collectors.toList()), new Stack()); + assertEquals(reverseStack.reverseIntegerStack(originalStack), reverseList); + } + + @Test + public void whenStringStack_thenReturnReversedStringStack(){ + ReverseStackUsingQueue stackReversal = new ReverseStackUsingQueue(); + List listOfWords = Arrays.asList(new String[]{"Hello", "I", "am", "reversing", "a", "stack"}); + List listOfWordsReversed = new ArrayList<>(listOfWords); + Collections.reverse(listOfWordsReversed); + Stack originalStack = generateStackFromGivenList(listOfWords, new Stack()); + Stack reversedStack = generateStackFromGivenList(listOfWordsReversed, new Stack()); + assertEquals(stackReversal.reverseStringStack(originalStack), reversedStack); + } + + @Test + public void whenEmployeeStack_thenReturnReversedEmployeeStack(){ + ReverseStackUsingQueue stackReversal = new ReverseStackUsingQueue(); + Employee employee1 = new Employee("John Doe", new Date()); + Employee employee2 = new Employee("John Nash", new Date()); + Employee employee3 = new Employee("Ryan Howard", new Date()); + List employeeList = new ArrayList<>(); + employeeList.add(employee1); + employeeList.add(employee2); + employeeList.add(employee3); + List employeeReversed = new ArrayList<>(employeeList); + Collections.reverse(employeeReversed); + Stack originalStack = generateStackFromGivenList(employeeList, new Stack()); + Stack reverseStack = generateStackFromGivenList(employeeReversed, new Stack()); + assertEquals(stackReversal.reverseEmployeeStack(originalStack), reverseStack); + } + + @Test + public void givenIntegerStack_whenStackReversed_thenReturnReversedRecursion(){ + ReverseStackUsingRecursion reverseStack = new ReverseStackUsingRecursion(); + Stack originalStack = generateStackFromGivenList(Arrays.stream(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).boxed().collect(Collectors.toList()), new Stack()); + Stack reversedStack = generateStackFromGivenList(Arrays.stream(new int[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}).boxed().collect(Collectors.toList()), new Stack()); + assertEquals(reverseStack.reverseIntegerStack(originalStack), reversedStack); + } + + private Stack generateStackFromGivenList(List elements, Stack stack){ + int start = 0; + while (start < elements.size()){ + stack.add(elements.get(start++)); + } + return stack; + } +} diff --git a/core-java-modules/core-java-collections-5/README.md b/core-java-modules/core-java-collections-5/README.md new file mode 100644 index 0000000000..0d9b12b842 --- /dev/null +++ b/core-java-modules/core-java-collections-5/README.md @@ -0,0 +1,7 @@ +========= + +## Core Java Collections Cookbooks and Examples + +### Relevant Articles: +- [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro) +- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) diff --git a/core-java-modules/core-java-collections-5/pom.xml b/core-java-modules/core-java-collections-5/pom.xml new file mode 100644 index 0000000000..67c9f7120c --- /dev/null +++ b/core-java-modules/core-java-collections-5/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + core-java-collections-5 + 0.0.1-SNAPSHOT + core-java-collections-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.junit.platform + junit-platform-runner + ${junit-platform.version} + test + + + org.junit.jupiter + junit-jupiter + ${junit.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit.version} + test + + + org.roaringbitmap + RoaringBitmap + ${roaringbitmap.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + + + 5.9.2 + 0.9.38 + 1.36 + + diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmark.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmark.java new file mode 100644 index 0000000000..4968afb752 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmark.java @@ -0,0 +1,82 @@ +package com.baeldung.roaringbitmap; + +import java.util.BitSet; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.roaringbitmap.RoaringBitmap; + +@State(Scope.Thread) +public class BitSetsBenchmark { + private RoaringBitmap rb1; + private BitSet bs1; + private RoaringBitmap rb2; + private BitSet bs2; + private final static int SIZE = 10_000_000; + + @Setup + public void setup() { + rb1 = new RoaringBitmap(); + bs1 = new BitSet(SIZE); + rb2 = new RoaringBitmap(); + bs2 = new BitSet(SIZE); + for (int i = 0; i < SIZE / 2; i++) { + rb1.add(i); + bs1.set(i); + } + for (int i = SIZE / 2; i < SIZE; i++) { + rb2.add(i); + bs2.set(i); + } + } + + @Benchmark + public RoaringBitmap roaringBitmapUnion() { + return RoaringBitmap.or(rb1, rb2); + } + + @Benchmark + public BitSet bitSetUnion() { + BitSet result = (BitSet) bs1.clone(); + result.or(bs2); + return result; + } + + @Benchmark + public RoaringBitmap roaringBitmapIntersection() { + return RoaringBitmap.and(rb1, rb2); + } + + @Benchmark + public BitSet bitSetIntersection() { + BitSet result = (BitSet) bs1.clone(); + result.and(bs2); + return result; + } + + @Benchmark + public RoaringBitmap roaringBitmapDifference() { + return RoaringBitmap.andNot(rb1, rb2); + } + + @Benchmark + public BitSet bitSetDifference() { + BitSet result = (BitSet) bs1.clone(); + result.andNot(bs2); + return result; + } + + @Benchmark + public RoaringBitmap roaringBitmapXOR() { + return RoaringBitmap.xor(rb1, rb2); + } + + @Benchmark + public BitSet bitSetXOR() { + BitSet result = (BitSet) bs1.clone(); + result.xor(bs2); + return result; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmarkRunner.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmarkRunner.java new file mode 100644 index 0000000000..49d556df7e --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/roaringbitmap/BitSetsBenchmarkRunner.java @@ -0,0 +1,9 @@ +package com.baeldung.roaringbitmap; + +import java.io.IOException; + +public class BitSetsBenchmarkRunner { + public static void main(String... args) throws IOException { + org.openjdk.jmh.Main.main(args); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/roaringbitmap/RoaringBitmapBenchmarkUnitTest.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/roaringbitmap/RoaringBitmapBenchmarkUnitTest.java new file mode 100644 index 0000000000..07170512d9 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/roaringbitmap/RoaringBitmapBenchmarkUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.roaringbitmap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.roaringbitmap.RoaringBitmap; + +class RoaringBitmapBenchmarkUnitTest { + @Test + public void givenTwoRoaringBitmap_whenUsingOr_thenWillGetSetsUnion() { + RoaringBitmap expected = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8); + RoaringBitmap A = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5); + RoaringBitmap B = RoaringBitmap.bitmapOf(4, 5, 6, 7, 8); + RoaringBitmap union = RoaringBitmap.or(A, B); + assertEquals(expected, union); + } + + @Test + public void givenTwoRoaringBitmap_whenUsingAnd_thenWillGetSetsIntersection() { + RoaringBitmap expected = RoaringBitmap.bitmapOf(4, 5); + RoaringBitmap A = RoaringBitmap.bitmapOfRange(1, 6); + RoaringBitmap B = RoaringBitmap.bitmapOf(4, 5, 6, 7, 8); + RoaringBitmap intersection = RoaringBitmap.and(A, B); + assertEquals(expected, intersection); + } + + @Test + public void givenTwoRoaringBitmap_whenUsingAndNot_thenWillGetSetsDifference() { + RoaringBitmap expected = RoaringBitmap.bitmapOf(1, 2, 3); + RoaringBitmap A = new RoaringBitmap(); + A.add(1L, 6L); + RoaringBitmap B = RoaringBitmap.bitmapOf(4, 5, 6, 7, 8); + RoaringBitmap difference = RoaringBitmap.andNot(A, B); + assertEquals(expected, difference); + } + + @Test + public void givenTwoRoaringBitmap_whenUsingXOR_thenWillGetSetsSymmetricDifference() { + RoaringBitmap expected = RoaringBitmap.bitmapOf(1, 2, 3, 6, 7, 8); + RoaringBitmap A = RoaringBitmap.bitmapOfRange(1, 6); + RoaringBitmap B = RoaringBitmap.bitmapOfRange(4, 9); + RoaringBitmap xor = RoaringBitmap.xor(A, B); + assertEquals(expected, xor); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list/README.md b/core-java-modules/core-java-collections-array-list/README.md index d24f7492bb..e3d41d8f88 100644 --- a/core-java-modules/core-java-collections-array-list/README.md +++ b/core-java-modules/core-java-collections-array-list/README.md @@ -9,3 +9,7 @@ This module contains articles about the Java ArrayList collection - [Multi Dimensional ArrayList in Java](https://www.baeldung.com/java-multi-dimensional-arraylist) - [Removing an Element From an ArrayList](https://www.baeldung.com/java-arraylist-remove-element) - [The Capacity of an ArrayList vs the Size of an Array in Java](https://www.baeldung.com/java-list-capacity-array-size) +- [Case-Insensitive Searching in ArrayList](https://www.baeldung.com/java-arraylist-case-insensitive-search) +- [Storing Data Triple in a List in Java](https://www.baeldung.com/java-list-storing-triple) +- [Convert an ArrayList of Object to an ArrayList of String Elements](https://www.baeldung.com/java-object-list-to-strings) +- [Initialize an ArrayList with Zeroes or Null in Java](https://www.baeldung.com/java-arraylist-with-zeroes-or-null) diff --git a/core-java-modules/core-java-collections-array-list/pom.xml b/core-java-modules/core-java-collections-array-list/pom.xml index 6b040739e8..e3a115854c 100644 --- a/core-java-modules/core-java-collections-array-list/pom.xml +++ b/core-java-modules/core-java-collections-array-list/pom.xml @@ -5,6 +5,33 @@ 4.0.0 core-java-collections-array-list 0.1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + + 16 + 16 + 3.0.0-M3 + core-java-collections-array-list jar @@ -20,6 +47,12 @@ commons-collections4 ${commons-collections4.version} + + com.google.guava + guava + 31.1-jre + test + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacity.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacity.java new file mode 100644 index 0000000000..34f202a4dd --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacity.java @@ -0,0 +1,20 @@ +package com.baeldung.defaultarraylistcapacity; + +import java.lang.reflect.Field; +import java.util.ArrayList; + +public class DefaultArrayListCapacity { + + public static int getDefaultCapacity(ArrayList arrayList) throws Exception { + + if (arrayList == null) { + return 0; + } + + Field field = ArrayList.class.getDeclaredField("elementData"); + field.setAccessible(true); + + return ((Object[]) field.get(arrayList)).length; + } + +} diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZeros.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZeros.java new file mode 100644 index 0000000000..66862791aa --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZeros.java @@ -0,0 +1,15 @@ +package com.baeldung.initializearraylistwithnullorzeros; + +import java.util.ArrayList; + +public class InitializeArrayListWithNullOrZeros { + + public static void main(String[] args) { + + ArrayList arrayList = new ArrayList<>(); + for (int i = 0; i< 10; i++) { + arrayList.add(null); + } + } +} + diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseSearchUtil.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseSearchUtil.java new file mode 100644 index 0000000000..38532ef031 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseSearchUtil.java @@ -0,0 +1,14 @@ +package com.baeldung.list.ignorecase; + +import java.util.List; + +public class IgnoreCaseSearchUtil { + public static boolean ignoreCaseContains(List theList, String searchStr) { + for (String s : theList) { + if (searchStr.equalsIgnoreCase(s)) { + return true; + } + } + return false; + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseStringList.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseStringList.java new file mode 100644 index 0000000000..a27c2650ed --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/ignorecase/IgnoreCaseStringList.java @@ -0,0 +1,29 @@ +package com.baeldung.list.ignorecase; + +import java.util.ArrayList; +import java.util.Collection; + +public class IgnoreCaseStringList extends ArrayList { + + public IgnoreCaseStringList() { + + } + + public IgnoreCaseStringList(Collection c) { + super(c); + } + + @Override + public boolean contains(Object o) { + String searchStr = (String) o; + // Using Stream API: + // return this.stream().anyMatch(searchStr::equalsIgnoreCase); + for (String s : this) { + if (searchStr.equalsIgnoreCase(s)) { + return true; + } + } + return false; + } + +} diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/Node.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/Node.java new file mode 100644 index 0000000000..3e2c5693de --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/Node.java @@ -0,0 +1,17 @@ +package com.baeldung.listofobjectstolistofstring; + +public class Node { + + private final int x; + private final int y; + + public Node(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public String toString() { + return "Node (" + "x=" + x + ", y=" + y + ')'; + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/User.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/User.java new file mode 100644 index 0000000000..eb9298bce0 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/listofobjectstolistofstring/User.java @@ -0,0 +1,14 @@ +package com.baeldung.listofobjectstolistofstring; + +public class User { + private final String fullName; + + public User(String fullName) { + this.fullName = fullName; + } + + @Override + public String toString() { + return "User (" + "full name='" + fullName + ')'; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/triple/Triple.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/triple/Triple.java new file mode 100644 index 0000000000..b19266ad21 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/triple/Triple.java @@ -0,0 +1,26 @@ +package com.baeldung.triple; + +public class Triple { + + private final L left; + private final M middle; + private final R right; + + public Triple(L left, M middle, R right) { + this.left = left; + this.middle = middle; + this.right = right; + } + + public L getLeft() { + return left; + } + + public M getMiddle() { + return middle; + } + + public R getRight() { + return right; + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacityUnitTest.java b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacityUnitTest.java new file mode 100644 index 0000000000..0690e93879 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/defaultarraylistcapacity/DefaultArrayListCapacityUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.defaultarraylistcapacity; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +public class DefaultArrayListCapacityUnitTest { + + @Test + void givenEmptyArrayList_whenGetDefaultCapacity_thenReturnZero() throws Exception { + + ArrayList myList = new ArrayList<>(); + int defaultCapacity = DefaultArrayListCapacity.getDefaultCapacity(myList); + + assertEquals(0, defaultCapacity); + + } + + @Test + void givenEmptyArrayList_whenAddItemAndGetDefaultCapacity_thenReturn10() throws Exception { + + ArrayList myList = new ArrayList<>(); + myList.add("ITEM 1"); + + int defaultCapacity = DefaultArrayListCapacity.getDefaultCapacity(myList); + + assertEquals(10, defaultCapacity); + + } + +} diff --git a/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZerosUnitTest.java b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZerosUnitTest.java new file mode 100644 index 0000000000..00987fa198 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/initializearraylistwithnullorzeros/InitializeArrayListWithNullOrZerosUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.initializearraylistwithnullorzeros; + +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class InitializeArrayListWithNullOrZerosUnitTest { + + @Test + public void whenInitializingListWithNCopies_thenListIsCorrectlyPopulated() { + // when + ArrayList list = IntStream.of(new int[10]) + .boxed() + .collect(Collectors.toCollection(ArrayList::new)); + + // then + Assertions.assertEquals(10, list.size()); + Assertions.assertTrue(list.stream().allMatch(elem -> elem == 0)); + } + + @Test + public void whenInitializingListWithStream_thenListIsCorrectlyPopulated() { + + // when + ArrayList listWithZeros = Stream.generate(() -> 0) + .limit(10).collect(Collectors.toCollection(ArrayList::new)); + + ArrayList listWithNulls = Stream.generate(() -> null) + .limit(10).collect(Collectors.toCollection(ArrayList::new)); + + // then + Assertions.assertEquals(10, listWithZeros.size()); + Assertions.assertTrue(listWithZeros.stream().allMatch(elem -> elem == 0)); + + Assertions.assertEquals(10, listWithNulls.size()); + Assertions.assertTrue(listWithNulls.stream().allMatch(Objects::isNull)); + } + + @Test public void whenInitializingListWithIntStream_thenListIsCorrectlyPopulated() { + // when + ArrayList list = IntStream.of(new int[10]) + .boxed() + .collect(Collectors.toCollection(ArrayList::new)); + + // then + Assertions.assertEquals(10, list.size()); + Assertions.assertTrue(list.stream().allMatch(elem -> elem == 0)); } + + @Test + public void whenInitializingListWithAsList_thenListIsCorrectlyPopulated() { + // when + Integer[] integers = new Integer[10]; + Arrays.fill(integers, 0); + List integerList = new ArrayList<>(Arrays.asList(integers)); + + // then + Assertions.assertEquals(10, integerList.size()); + Assertions.assertTrue(integerList.stream().allMatch(elem -> elem == 0)); + } + + @Test + public void whenInitializingListWithVector_thenListIsCorrectlyPopulated() { + // when + List integerList = new Vector<>() {{setSize(10);}}; + + // then + Assertions.assertEquals(10, integerList.size()); + Assertions.assertTrue(integerList.stream().allMatch(Objects::isNull)); + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/list/ignorecase/IgnoreCaseContainsUnitTest.java b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/list/ignorecase/IgnoreCaseContainsUnitTest.java new file mode 100644 index 0000000000..5ca9bb1028 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/list/ignorecase/IgnoreCaseContainsUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.list.ignorecase; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class IgnoreCaseContainsUnitTest { + private static final List LANGUAGES = Arrays.asList("Java", "Python", "Kotlin", "Ruby", "Javascript", "Go"); + + @Test + void givenStringList_whenCallTheStandardContains_shouldReturnFalse() { + String searchStr = "jAvA"; + boolean result = LANGUAGES.contains(searchStr); + assertFalse(result); + } + + @Test + void givenStringList_whenSearchIgnoreCaseUsingStreamAPI_shouldReturnTrue() { + String searchStr = "koTliN"; + boolean result = LANGUAGES.stream().anyMatch(searchStr::equalsIgnoreCase); + assertTrue(result); + } + + @Test + void givenStringList_whenUsingUtilClass_shouldReturnTrue() { + String searchStr = "ruBY"; + boolean result = IgnoreCaseSearchUtil.ignoreCaseContains(LANGUAGES, searchStr); + assertTrue(result); + } + + @Test + void givenStringList_whenUsingIgnoreCaseStringList_shouldReturnTrue() { + String searchStr = "pYtHoN"; + List ignoreCaseList = new IgnoreCaseStringList(LANGUAGES); + boolean result = ignoreCaseList.contains(searchStr); + assertTrue(result); + + boolean resultContainAll = ignoreCaseList.containsAll(Arrays.asList("pYtHon", "jAvA", "koTliN", "ruBY")); + assertTrue(resultContainAll); + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/listofobjectstolistofstring/ConvertObjectListToStringListUnitTest.java b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/listofobjectstolistofstring/ConvertObjectListToStringListUnitTest.java new file mode 100644 index 0000000000..1d393a2945 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/listofobjectstolistofstring/ConvertObjectListToStringListUnitTest.java @@ -0,0 +1,92 @@ +package com.baeldung.listofobjectstolistofstring; + +import com.google.common.collect.Lists; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class ConvertObjectListToStringListUnitTest { + + @Test + public void givenObjectList_whenForEachUsedToConvert_thenReturnSuccess() { + List outputList = new ArrayList<>(objectListWithNull().size()); + for (Object obj : objectListWithNull()) { + outputList.add(Objects.toString(obj, null)); + } + Assert.assertEquals(expectedStringListWithNull(), outputList); + } + + @Test + public void givenObjectList_whenUsingStreamsToConvert_thenReturnSuccess() { + List outputList; + outputList = objectListWithNull().stream() + .map((obj) -> Objects.toString(obj, null)) + .collect(Collectors.toList()); + Assert.assertEquals(expectedStringListWithNull(), outputList); + + } + + @Test + public void givenObjectList_whenUsingStreamsUnmodifiableListToConvert_thenReturnSuccess() { + List outputList; + outputList = objectListWithNull().stream() + .filter(Objects::nonNull) + .map((obj) -> Objects.toString(obj, null)) + .collect(Collectors.toUnmodifiableList()); + Assert.assertEquals(expectedStringListWithoutNull(), outputList); + + } + + @Test + public void givenObjectList_whenUsingGuavaTransform_thenReturnSuccess() { + List outputList; + outputList = Lists.transform(objectListWithNull(), obj -> Objects.toString(obj, null)); + Assert.assertEquals(expectedStringListWithNull(), outputList); + } + + @Test + public void givenObjectListWithNoNull_whenUsingToList_thenReturnSuccess() { + List outputList; + outputList = objectListWithoutNull().stream() + .map((obj) -> Objects.toString(obj, null)) + .toList(); + Assert.assertEquals(expectedStringListWithoutNull(), outputList); + } + + private List expectedStringListWithNull() { + List listOfStrings = new ArrayList<>(); + listOfStrings.add("1"); + listOfStrings.add("true"); + listOfStrings.add("hello"); + listOfStrings.add(Double.toString(273773.98)); + listOfStrings.add(null); + listOfStrings.add(new Node(2, 4).toString()); + listOfStrings.add(new User("John Doe").toString()); + return listOfStrings; + } + + private List objectListWithNull() { + List listOfStrings = new ArrayList<>(); + listOfStrings.add(1); + listOfStrings.add(true); + listOfStrings.add("hello"); + listOfStrings.add(Double.valueOf(273773.98)); + listOfStrings.add(null); + listOfStrings.add(new Node(2, 4)); + listOfStrings.add(new User("John Doe")); + return listOfStrings; + } + + private List expectedStringListWithoutNull() { + return List.of("1", "true", "hello", Double.toString(273773.98), new Node(2, 4).toString(), new User("John Doe").toString()); + } + + private List objectListWithoutNull() { + return List.of(1, true, "hello", Double.valueOf(273773.98), new Node(2, 4), new User("John Doe")); + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/triple/TripleInListUnitTest.java b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/triple/TripleInListUnitTest.java new file mode 100644 index 0000000000..2196ae687f --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/test/java/com/baeldung/triple/TripleInListUnitTest.java @@ -0,0 +1,105 @@ +package com.baeldung.triple; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +public class TripleInListUnitTest { + + enum OP { + PLUS("+"), MINUS("-"), MULTIPLY("x"); + final String opSign; + + OP(String x) { + this.opSign = x; + } + } + + private String createQuestion(Long num1, OP operator, Long num2) { + long result; + switch (operator) { + case PLUS: + result = num1 + num2; + break; + case MINUS: + result = num1 - num2; + break; + case MULTIPLY: + result = num1 * num2; + break; + default: + throw new IllegalArgumentException("Unknown operator"); + } + return String.format("%d %s %d = ? ( answer: %d )", num1, operator.opSign, num2, result); + } + + private static final List EXPECTED_QUESTIONS = Arrays.asList( + "100 - 42 = ? ( answer: 58 )", + "100 + 42 = ? ( answer: 142 )", + "100 x 42 = ? ( answer: 4200 )"); + + @Test + void givenTripleValues_whenStoreAsList_thenTypeIsNotSafe() { + + List myTriple1 = new ArrayList(3); + myTriple1.add(100L); + myTriple1.add(OP.MINUS); + myTriple1.add(42L); + + List myTriple2 = new ArrayList(3); + myTriple2.add(100L); + myTriple2.add(OP.PLUS); + myTriple2.add(42L); + + List myTriple3 = new ArrayList(3); + myTriple3.add(100L); + myTriple3.add(OP.MULTIPLY); + myTriple3.add(42L); + + List listOfTriples = new ArrayList<>(Arrays.asList(myTriple1, myTriple2, myTriple3)); + + List oopsTriple = new ArrayList(3); + oopsTriple.add("Oops"); + oopsTriple.add(911L); + oopsTriple.add("The type is wrong"); + + listOfTriples.add(oopsTriple); + assertEquals(4, listOfTriples.size()); + + List questions = listOfTriples.stream() + .filter( + triple -> triple.size() == 3 + && triple.get(0) instanceof Long + && triple.get(1) instanceof OP + && triple.get(2) instanceof Long + ).map(triple -> { + Long left = (Long) triple.get(0); + OP op = (OP) triple.get(1); + Long right = (Long) triple.get(2); + return createQuestion(left, op, right); + }).collect(Collectors.toList()); + + assertEquals(EXPECTED_QUESTIONS, questions); + } + + @Test + void givenTripleValues_whenUsingTheTripleClass_thenTypeIsSafeAndNeat() { + Triple triple1 = new Triple<>(100L, OP.MINUS, 42L); + Triple triple2 = new Triple<>(100L, OP.PLUS, 42L); + Triple triple3 = new Triple<>(100L, OP.MULTIPLY, 42L); + Triple tripleOops = new Triple<>("Oops", 911L, "The type is wrong"); + + List> listOfTriples = new ArrayList<>(Arrays.asList(triple1, triple2, triple3)); + // listOfTriples.add(tripleOops); // Compiler error: "java: incompatible types ... " + + List questions = listOfTriples.stream() + .map(triple -> createQuestion(triple.getLeft(), triple.getMiddle(), triple.getRight())) + .collect(Collectors.toList()); + + assertEquals(EXPECTED_QUESTIONS, questions); + } +} 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 075f2b8736..904e876032 100644 --- a/core-java-modules/core-java-collections-conversions-2/README.md +++ b/core-java-modules/core-java-collections-conversions-2/README.md @@ -9,4 +9,6 @@ This module contains articles about conversions among Collection types and array - [Converting List to Map With a Custom Supplier](https://www.baeldung.com/list-to-map-supplier) - [Arrays.asList vs new ArrayList(Arrays.asList())](https://www.baeldung.com/java-arrays-aslist-vs-new-arraylist) - [Iterate Over a Set in Java](https://www.baeldung.com/java-iterate-set) +- [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) - More articles: [[<-- prev]](../core-java-collections-conversions) diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/combine2liststomap/CombineTwoListsInAMapUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/combine2liststomap/CombineTwoListsInAMapUnitTest.java new file mode 100644 index 0000000000..501ec16a21 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/combine2liststomap/CombineTwoListsInAMapUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.combine2liststomap; + +import static java.lang.Math.min; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.junit.jupiter.api.Test; + +public class CombineTwoListsInAMapUnitTest { + private static final List KEY_LIST = Arrays.asList("Number One", "Number Two", "Number Three", "Number Four", "Number Five"); + private static final List VALUE_LIST = Arrays.asList(1, 2, 3, 4, 5); + private static final Map EXPECTED_MAP = new HashMap() {{ + put("Number One", 1); + put("Number Two", 2); + put("Number Three", 3); + put("Number Four", 4); + put("Number Five", 5); + }}; + + @Test + void givenTwoLists_whenUsingLoopAndListGet_shouldGetExpectedMap() { + Map result = new HashMap<>(); + int size = KEY_LIST.size(); + if (KEY_LIST.size() != VALUE_LIST.size()) { + // throw an exception or print a warning + size = min(KEY_LIST.size(), VALUE_LIST.size()); + } + for (int i = 0; i < size; i++) { + result.put(KEY_LIST.get(i), VALUE_LIST.get(i)); + } + assertEquals(EXPECTED_MAP, result); + } + + @Test + void givenTwoLists_whenUsingStreamApiAndListGet_shouldGetExpectedMap() { + Map result = IntStream.range(0, KEY_LIST.size()) + .boxed() + .collect(Collectors.toMap(KEY_LIST::get, VALUE_LIST::get)); + assertEquals(EXPECTED_MAP, result); + } + + @Test + void givenTwoLists_whenUsingIterators_shouldGetExpectedMap() { + Map result = new HashMap<>(); + + Iterator ik = KEY_LIST.iterator(); + Iterator iv = VALUE_LIST.iterator(); + while (ik.hasNext() && iv.hasNext()) { + result.put(ik.next(), iv.next()); + } + + assertEquals(EXPECTED_MAP, result); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/intlisttostrlist/IntListToStringListUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/intlisttostrlist/IntListToStringListUnitTest.java new file mode 100644 index 0000000000..0990ef2b74 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/intlisttostrlist/IntListToStringListUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.intlisttostrlist; + + +import com.google.common.base.Functions; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IntListToStringListUnitTest { + private final static List INTEGER_LIST = Arrays.asList(1, 2, 3, 4, 5, 6, 7); + private final static List EXPECTED_LIST = Arrays.asList("1", "2", "3", "4", "5", "6", "7"); + + + @Test + void givenAnIntegerList_whenUsingStreamMap_shouldGetExpectedStringList() { + List result = INTEGER_LIST.stream().map(i -> i.toString()).collect(Collectors.toList()); + assertEquals(EXPECTED_LIST, result); + } + + @Test + void givenAnIntegerList_whenUsingGuava_shouldGetExpectedStringList() { + List result = Lists.transform(INTEGER_LIST, Functions.toStringFunction()); + assertEquals(EXPECTED_LIST, result); + } + + @Test + void givenAnIntegerList_whenUsingLoop_shouldGetExpectedStringList() { + List result = new ArrayList<>(); + for (Integer i : INTEGER_LIST) { + result.add(i.toString()); + } + assertEquals(EXPECTED_LIST, result); + } +} diff --git a/core-java-modules/core-java-collections-list-3/README.md b/core-java-modules/core-java-collections-list-3/README.md index bcc8b3f3ed..40ebaf7693 100644 --- a/core-java-modules/core-java-collections-list-3/README.md +++ b/core-java-modules/core-java-collections-list-3/README.md @@ -12,4 +12,5 @@ This module contains articles about the Java List collection - [How to Count Duplicate Elements in Arraylist](https://www.baeldung.com/java-count-duplicate-elements-arraylist) - [Finding the Differences Between Two Lists in Java](https://www.baeldung.com/java-lists-difference) - [List vs. ArrayList in Java](https://www.baeldung.com/java-list-vs-arraylist) +- [Set vs List in Java](https://www.baeldung.com/java-set-vs-list) - [[<-- Prev]](/core-java-modules/core-java-collections-list-2) diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/listandset/ListAndSetUnitTest.java b/core-java-modules/core-java-collections-list-3/src/test/java/com/baeldung/list/listandset/ListAndSetUnitTest.java similarity index 86% rename from core-java-modules/core-java-collections-4/src/test/java/com/baeldung/listandset/ListAndSetUnitTest.java rename to core-java-modules/core-java-collections-list-3/src/test/java/com/baeldung/list/listandset/ListAndSetUnitTest.java index c57c1f96b8..43154c8e17 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/listandset/ListAndSetUnitTest.java +++ b/core-java-modules/core-java-collections-list-3/src/test/java/com/baeldung/list/listandset/ListAndSetUnitTest.java @@ -1,10 +1,15 @@ -package com.baeldung.listandset; +package com.baeldung.list.listandset; -import org.junit.Test; -import org.junit.Assert; -import java.util.*; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; public class ListAndSetUnitTest { diff --git a/core-java-modules/core-java-collections-list-4/README.md b/core-java-modules/core-java-collections-list-4/README.md index 6966b60756..e5f2e8c718 100644 --- a/core-java-modules/core-java-collections-list-4/README.md +++ b/core-java-modules/core-java-collections-list-4/README.md @@ -11,5 +11,6 @@ This module contains articles about the Java List collection - [Difference Between Arrays.asList() and List.of()](https://www.baeldung.com/java-arrays-aslist-vs-list-of) - [How to Store HashMap Inside a List](https://www.baeldung.com/java-hashmap-inside-list) - [Convert a List to a Comma-Separated String](https://www.baeldung.com/java-list-comma-separated-string) -- [Set vs List in Java](https://www.baeldung.com/java-set-vs-list) +- [Inserting an Object in an ArrayList at a Specific Position](https://www.baeldung.com/java-insert-object-arraylist-specific-position) +- [Iterate Through Two ArrayLists Simultaneously](https://www.baeldung.com/iterate-through-two-arraylists-simultaneously) - [[<-- Prev]](/core-java-modules/core-java-collections-list-3) diff --git a/core-java-modules/core-java-collections-list-5/README.md b/core-java-modules/core-java-collections-list-5/README.md new file mode 100644 index 0000000000..d8cd989600 --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/README.md @@ -0,0 +1,7 @@ +## Core Java Collections List (Part 5) + +This module contains articles about the Java List collection + +### Relevant Articles: +- [Java List Interface](https://www.baeldung.com/java-list-interface) +- [Finding All Duplicates in a List in Java](https://www.baeldung.com/java-list-find-duplicates) diff --git a/core-java-modules/core-java-collections-list-5/pom.xml b/core-java-modules/core-java-collections-list-5/pom.xml new file mode 100644 index 0000000000..0807f7612c --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + core-java-collections-list-5 + 0.1.0-SNAPSHOT + core-java-collections-list-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + commons-lang + commons-lang + ${commons-lang.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + 2.2 + 3.12.0 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-5/src/main/java/com/baeldung/listduplicate/ListDuplicate.java b/core-java-modules/core-java-collections-list-5/src/main/java/com/baeldung/listduplicate/ListDuplicate.java new file mode 100644 index 0000000000..5e3e845916 --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/src/main/java/com/baeldung/listduplicate/ListDuplicate.java @@ -0,0 +1,69 @@ +package com.baeldung.listduplicate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ListDuplicate { + public List listDuplicateUsingSet(List list) { + List duplicates = new ArrayList<>(); + Set set = new HashSet<>(); + for (Integer i : list) { + if (set.contains(i)) { + duplicates.add(i); + } else { + set.add(i); + } + } + return duplicates; + } + + public List listDuplicateUsingMap(List list) { + List duplicates = new ArrayList<>(); + Map frequencyMap = new HashMap<>(); + for (Integer number : list) { + frequencyMap.put(number, frequencyMap.getOrDefault(number, 0) + 1); + } + for (int number : frequencyMap.keySet()) { + if (frequencyMap.get(number) != 1) { + duplicates.add(number); + } + } + return duplicates; + } + + public List listDuplicateUsingFilterAndSetAdd(List list) { + Set elements = new HashSet(); + return list.stream() + .filter(n -> !elements.add(n)) + .collect(Collectors.toList()); + } + + public List listDuplicateUsingCollectionsFrequency(List list) { + List duplicates = new ArrayList<>(); + Set set = list.stream() + .filter(i -> Collections.frequency(list, i) > 1) + .collect(Collectors.toSet()); + duplicates.addAll(set); + return duplicates; + } + + public List listDuplicateUsingMapAndCollectorsGroupingBy(List list) { + List duplicates = new ArrayList<>(); + Set set = list.stream() + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) + .entrySet() + .stream() + .filter(m -> m.getValue() > 1) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + duplicates.addAll(set); + return duplicates; + } +} diff --git a/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/list/ListUnitTest.java b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/list/ListUnitTest.java new file mode 100644 index 0000000000..2222bc5a6f --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/java/list/ListUnitTest.java @@ -0,0 +1,126 @@ +package com.baeldung.java.list; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.junit.Test; + +public class ListUnitTest { + + @Test + public void givenAFruitList_whenAddNewFruit_thenFruitIsAdded(){ + List fruits = new ArrayList<>(); + assertEquals("Unexpected number of fruits in the list, should have been 0", 0, fruits.size()); + + fruits.add("Apple"); + assertEquals("Unexpected number of fruits in the list, should have been 1", 1, fruits.size()); + } + + @Test + public void givenAFruitList_whenContainsFruit_thenFruitIsInTheList(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + assertTrue("Apple should be in the fruit list", fruits.contains("Apple")); + assertFalse("Banana should not be in the fruit list", fruits.contains("Banana")); + } + + @Test + public void givenAnEmptyFruitList_whenEmptyCheck_thenListIsEmpty(){ + List fruits = new ArrayList<>(); + assertTrue("Fruit list should be empty", fruits.isEmpty()); + + fruits.add("Apple"); + assertFalse("Fruit list should not be empty", fruits.isEmpty()); + } + + @Test + public void givenAFruitList_whenIterateOverIt_thenFruitsAreInOrder(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); // fruit at index 0 + fruits.add("Orange");// fruit at index 1 + fruits.add("Banana");// fruit at index 2 + int index = 0; + for (Iterator it = fruits.listIterator(); it.hasNext(); ) { + String fruit = it.next(); + assertEquals("Fruits should be in order", fruits.get(index++), fruit); + } + } + + @Test + public void givenAFruitList_whenRemoveFruit_thenFruitIsRemoved(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Orange"); + assertEquals("Unexpected number of fruits in the list, should have been 2", 2, fruits.size()); + + fruits.remove("Apple"); + assertEquals("Unexpected number of fruits in the list, should have been 1", 1, fruits.size()); + } + + @Test + public void givenAFruitList_whenSetFruit_thenFruitIsUpdated(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Orange"); + + fruits.set(0, "Banana"); + assertEquals("Fruit at index 0 should be Banana", "Banana", fruits.get(0)); + } + + @Test + public void givenAFruitList_whenSort_thenFruitsAreSorted(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Orange"); + fruits.add("Banana"); + + fruits.sort(Comparator.naturalOrder()); + + assertEquals("Fruit at index 0 should be Apple", "Apple", fruits.get(0)); + assertEquals("Fruit at index 1 should be Banana", "Banana", fruits.get(1)); + assertEquals("Fruit at index 2 should be Orange", "Orange", fruits.get(2)); + } + + @Test + public void givenAFruitList_whenSublist_thenWeGetASublist(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Orange"); + fruits.add("Banana"); + + List fruitsSublist = fruits.subList(0, 2); + assertEquals("Unexpected number of fruits in the sublist, should have been 2", 2, fruitsSublist.size()); + + assertEquals("Fruit at index 0 should be Apple", "Apple", fruitsSublist.get(0)); + assertEquals("Fruit at index 1 should be Orange", "Orange", fruitsSublist.get(1)); + } + + @Test + public void givenAFruitList_whenToArray_thenWeGetAnArray(){ + List fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Orange"); + fruits.add("Banana"); + + String[] fruitsArray = fruits.toArray(new String[0]); + assertEquals("Unexpected number of fruits in the array, should have been 3", 3, fruitsArray.length); + + assertEquals("Fruit at index 0 should be Apple", "Apple", fruitsArray[0]); + assertEquals("Fruit at index 1 should be Orange", "Orange", fruitsArray[1]); + assertEquals("Fruit at index 2 should be Banana", "Banana", fruitsArray[2]); + } + +} diff --git a/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/listduplicate/ListDuplicateUnitTest.java b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/listduplicate/ListDuplicateUnitTest.java new file mode 100644 index 0000000000..0d81387aea --- /dev/null +++ b/core-java-modules/core-java-collections-list-5/src/test/java/com/baeldung/listduplicate/ListDuplicateUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.listduplicate; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ListDuplicateUnitTest { + private static ListDuplicate listDuplicate; + + @BeforeClass + public static void setup() { + listDuplicate = new ListDuplicate(); + } + + @Test + public void givenList_whenUsingSet_thenReturnDuplicateElements() { + List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5); + List duplicates = listDuplicate.listDuplicateUsingSet(list); + Assert.assertEquals(duplicates.size(), 2); + Assert.assertEquals(duplicates.contains(3), true); + Assert.assertEquals(duplicates.contains(4), true); + Assert.assertEquals(duplicates.contains(1), false); + } + + @Test + public void givenList_whenUsingFrequencyMap_thenReturnDuplicateElements() { + List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5); + List duplicates = listDuplicate.listDuplicateUsingMap(list); + Assert.assertEquals(duplicates.size(), 2); + Assert.assertEquals(duplicates.contains(3), true); + Assert.assertEquals(duplicates.contains(4), true); + Assert.assertEquals(duplicates.contains(1), false); + } + + @Test + public void givenList_whenUsingFilterAndSetAdd_thenReturnDuplicateElements() { + List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5); + List duplicates = listDuplicate.listDuplicateUsingFilterAndSetAdd(list); + Assert.assertEquals(duplicates.size(), 2); + Assert.assertEquals(duplicates.contains(3), true); + Assert.assertEquals(duplicates.contains(4), true); + Assert.assertEquals(duplicates.contains(1), false); + } + + @Test + public void givenList_whenUsingCollectionsFrequency_thenReturnDuplicateElements() { + List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5); + List duplicates = listDuplicate.listDuplicateUsingCollectionsFrequency(list); + Assert.assertEquals(duplicates.size(), 2); + Assert.assertEquals(duplicates.contains(3), true); + Assert.assertEquals(duplicates.contains(4), true); + Assert.assertEquals(duplicates.contains(1), false); + } + + @Test + public void givenList_whenUsingMapAndCollectorsGroupingBy_thenReturnDuplicateElements() { + List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5); + List duplicates = listDuplicate.listDuplicateUsingCollectionsFrequency(list); + Assert.assertEquals(duplicates.size(), 2); + Assert.assertEquals(duplicates.contains(3), true); + Assert.assertEquals(duplicates.contains(4), true); + Assert.assertEquals(duplicates.contains(1), false); + } + +} diff --git a/core-java-modules/core-java-collections-maps-2/pom.xml b/core-java-modules/core-java-collections-maps-2/pom.xml index da51adac53..1e526ef892 100644 --- a/core-java-modules/core-java-collections-maps-2/pom.xml +++ b/core-java-modules/core-java-collections-maps-2/pom.xml @@ -61,4 +61,4 @@ 8.1.0 - + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-5/README.md b/core-java-modules/core-java-collections-maps-5/README.md index a131c669c6..e1817c7ba4 100644 --- a/core-java-modules/core-java-collections-maps-5/README.md +++ b/core-java-modules/core-java-collections-maps-5/README.md @@ -9,4 +9,5 @@ - [Java IdentityHashMap Class and Its Use Cases](https://www.baeldung.com/java-identityhashmap) - [How to Invert a Map in Java](https://www.baeldung.com/java-invert-map) - [Implementing a Map with Multiple Keys in Java](https://www.baeldung.com/java-multiple-keys-map) +- [Difference Between Map.ofEntries() and Map.of()](https://www.baeldung.com/map-ofentries-and-map-of) - More articles: [[<-- prev]](../core-java-collections-maps-4) diff --git a/core-java-modules/core-java-collections-maps-5/pom.xml b/core-java-modules/core-java-collections-maps-5/pom.xml index ba7083e42e..f12e044b23 100644 --- a/core-java-modules/core-java-collections-maps-5/pom.xml +++ b/core-java-modules/core-java-collections-maps-5/pom.xml @@ -34,6 +34,19 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + 5.2.5.RELEASE diff --git a/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/mapofvsmapofentries/MapOfEntriesVsMapOfUnitTest.java b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/mapofvsmapofentries/MapOfEntriesVsMapOfUnitTest.java new file mode 100644 index 0000000000..f8a8e33139 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-5/src/test/java/com/baeldung/map/mapofvsmapofentries/MapOfEntriesVsMapOfUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.map.mapofvsmapofentries; + +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class MapOfEntriesVsMapOfUnitTest { + + @Test + void mapOf() { + // Use Map.of() to create an empty immutable map + Map map = Map.of(); + assertNotNull(map); + + // Use Map.of() to create an immutable map with one entry + Map mapWithEntry = Map.of(1L, "value1"); + assertNotNull(mapWithEntry); + assertThat(mapWithEntry.size()).isEqualTo(1); + assertThat(mapWithEntry.get(1L)).isEqualTo("value1"); + + // Test if map is immutable + try { + mapWithEntry.put(2L, "value2"); + } catch (UnsupportedOperationException e) { + assertThat(e).isInstanceOf(UnsupportedOperationException.class); + } + } + + @Test + void mapOfEntries() { + // Use Map.ofEntries() to create an empty immutable map + Map map = Map.ofEntries(); + assertNotNull(map); + + // Use Map.ofEntries() to create an immutable map with two entries. + Map longUserMap = Map.ofEntries(Map.entry(1L, "User A"), Map.entry(2L, "User B")); + assertNotNull(longUserMap); + assertThat(longUserMap.size()).isEqualTo(2); + assertThat(longUserMap.get(1L)).isEqualTo("User A"); + assertThat(longUserMap.get(2L)).isEqualTo("User B"); + + // Test if map is immutable + try { + longUserMap.put(3L, "User C"); + } catch (UnsupportedOperationException e) { + assertThat(e).isInstanceOf(UnsupportedOperationException.class); + } + } +} diff --git a/core-java-modules/core-java-collections-maps-6/README.md b/core-java-modules/core-java-collections-maps-6/README.md new file mode 100644 index 0000000000..fc12a1bb25 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Copying All Keys and Values From One Hashmap Onto Another Without Replacing Existing Keys and Values](https://www.baeldung.com/java-copy-hashmap-no-changes) diff --git a/core-java-modules/core-java-collections-maps-6/pom.xml b/core-java-modules/core-java-collections-maps-6/pom.xml new file mode 100644 index 0000000000..9910d08691 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/pom.xml @@ -0,0 +1,20 @@ + + + core-java-collections-maps-6 + 0.1.0-SNAPSHOT + core-java-collections-maps-6 + jar + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + 4.0.0 + + + 5.2.5.RELEASE + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-6/src/main/java/com/baeldung/map/hashmapcopy/CopyingAHashMapToAnother.java b/core-java-modules/core-java-collections-maps-6/src/main/java/com/baeldung/map/hashmapcopy/CopyingAHashMapToAnother.java new file mode 100644 index 0000000000..77a6402a75 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/main/java/com/baeldung/map/hashmapcopy/CopyingAHashMapToAnother.java @@ -0,0 +1,47 @@ +package com.baeldung.map.hashmapcopy; + +import java.util.Map; + +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; + +public class CopyingAHashMapToAnother { + public Map copyByIteration(Map sourceMap, Map targetMap) { + for (Map.Entry entry : sourceMap.entrySet()) { + if (!targetMap.containsKey(entry.getKey())) { + targetMap.put(entry.getKey(), entry.getValue()); + } + } + return targetMap; + } + + public Map copyUsingPutAll(Map sourceMap, Map targetMap) { + sourceMap.keySet() + .removeAll(targetMap.keySet()); + targetMap.putAll(sourceMap); + return targetMap; + } + + public Map copyUsingPutIfAbsent(Map sourceMap, Map targetMap) { + for (Map.Entry entry : sourceMap.entrySet()) { + targetMap.putIfAbsent(entry.getKey(), entry.getValue()); + } + return targetMap; + } + + public Map copyUsingPutIfAbsentForEach(Map sourceMap, Map targetMap) { + sourceMap.forEach(targetMap::putIfAbsent); + return targetMap; + } + + public Map copyUsingMapMerge(Map sourceMap, Map targetMap) { + sourceMap.forEach((key, value) -> targetMap.merge(key, value, (oldVal, newVal) -> oldVal)); + return targetMap; + } + + public Map copyUsingGuavaMapDifference(Map sourceMap, Map targetMap) { + MapDifference differenceMap = Maps.difference(sourceMap, targetMap); + targetMap.putAll(differenceMap.entriesOnlyOnLeft()); + return targetMap; + } +} diff --git a/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/hashmapcopy/CopyHashMapIntoAnotherUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/hashmapcopy/CopyHashMapIntoAnotherUnitTest.java new file mode 100644 index 0000000000..b11f470eb3 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/hashmapcopy/CopyHashMapIntoAnotherUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.map.hashmapcopy; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.baeldung.map.hashmapcopy.CopyingAHashMapToAnother; + +public class CopyHashMapIntoAnotherUnitTest { + @Test + public void givenSourceAndTargetMapsWhenIteratedOverThenCopyingSuccess(){ + CopyingAHashMapToAnother obj = new CopyingAHashMapToAnother(); + Assert.assertEquals(generateExpectedResultMap(), obj.copyByIteration(generateSourceMap(), generateTargetMap())); + } + + @Test + public void givenSourceAndTargetMapsWhenUsedPutAllThenCopyingSuccess(){ + CopyingAHashMapToAnother obj = new CopyingAHashMapToAnother(); + Assert.assertEquals(generateExpectedResultMap(), obj.copyUsingPutAll(generateSourceMap(), generateTargetMap())); + } + + @Test + public void givenSourceAndTargetMapsWhenUsedPutIfAbsentThenCopyingSuccess(){ + CopyingAHashMapToAnother obj = new CopyingAHashMapToAnother(); + Assert.assertEquals(generateExpectedResultMap(), obj.copyUsingPutIfAbsent(generateSourceMap(), generateTargetMap())); + Assert.assertEquals(generateExpectedResultMap(), obj.copyUsingPutIfAbsentForEach(generateSourceMap(), generateTargetMap())); + } + + @Test + public void givenSourceAndTargetMapsWhenUsedMapMergeThenCopyingSuccess(){ + CopyingAHashMapToAnother obj = new CopyingAHashMapToAnother(); + Assert.assertEquals(generateExpectedResultMap(), obj.copyUsingMapMerge(generateSourceMap(), generateTargetMap())); + } + + @Test + public void givenSourceAndTargetMapsWhenMapDifferenceUsedThenCopyingSuccess(){ + CopyingAHashMapToAnother obj = new CopyingAHashMapToAnother(); + Assert.assertEquals(generateExpectedResultMap(), obj.copyUsingGuavaMapDifference(generateSourceMap(), generateTargetMap())); + } + + private Map generateSourceMap(){ + Map sourceMap = new HashMap<>(); + sourceMap.put("India", "Delhi"); + sourceMap.put("United States", "Washington D.C."); + sourceMap.put("United Kingdom", "London DC"); + return sourceMap; + } + + private Map generateTargetMap(){ + Map targetMap = new HashMap<>(); + targetMap.put("Zimbabwe", "Harare"); + targetMap.put("Norway", "Oslo"); + targetMap.put("United Kingdom", "London"); + return targetMap; + } + + private Map generateExpectedResultMap(){ + Map resultMap = new HashMap<>(); + resultMap.put("India", "Delhi"); + resultMap.put("United States", "Washington D.C."); + resultMap.put("United Kingdom", "London"); + resultMap.put("Zimbabwe", "Harare"); + resultMap.put("Norway", "Oslo"); + return resultMap; + } +} diff --git a/core-java-modules/core-java-collections-maps/README.md b/core-java-modules/core-java-collections-maps/README.md index 15cb32fbe8..034c71ba9a 100644 --- a/core-java-modules/core-java-collections-maps/README.md +++ b/core-java-modules/core-java-collections-maps/README.md @@ -12,4 +12,5 @@ This module contains articles about Map data structures in Java. - [Immutable Map Implementations in Java](https://www.baeldung.com/java-immutable-maps) - [Guide to Apache Commons MultiValuedMap](https://www.baeldung.com/apache-commons-multi-valued-map) - [The Java HashMap Under the Hood](https://www.baeldung.com/java-hashmap-advanced) +- [Create an Empty Map in Java](https://www.baeldung.com/java-create-empty-map) - More articles: [[next -->]](/core-java-modules/core-java-collections-maps-2) diff --git a/core-java-modules/core-java-collections-maps/pom.xml b/core-java-modules/core-java-collections-maps/pom.xml index 34b878df53..3a1bf0d8a1 100644 --- a/core-java-modules/core-java-collections-maps/pom.xml +++ b/core-java-modules/core-java-collections-maps/pom.xml @@ -20,6 +20,12 @@ commons-collections4 ${commons-collections4.version} + + org.junit.platform + junit-platform-runner + ${junit-platform.version} + test + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/maps/initialize/EmptyMapInitializer.java b/core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/EmptyMapInitializer.java similarity index 97% rename from core-java-modules/core-java-collections-4/src/main/java/com/baeldung/maps/initialize/EmptyMapInitializer.java rename to core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/EmptyMapInitializer.java index 78819cc21e..106de799e7 100644 --- a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/maps/initialize/EmptyMapInitializer.java +++ b/core-java-modules/core-java-collections-maps/src/main/java/com/baeldung/map/EmptyMapInitializer.java @@ -1,7 +1,5 @@ -package com.baeldung.maps.initialize; +package com.baeldung.map; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -10,6 +8,9 @@ import java.util.NavigableMap; import java.util.SortedMap; import java.util.TreeMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + public class EmptyMapInitializer { public static Map articleMap; diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/maps/initialize/EmptyMapInitializerUnitTest.java b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/EmptyMapInitializerUnitTest.java similarity index 96% rename from core-java-modules/core-java-collections-4/src/test/java/com/baeldung/maps/initialize/EmptyMapInitializerUnitTest.java rename to core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/EmptyMapInitializerUnitTest.java index 57183734cb..94a70cdd5d 100644 --- a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/maps/initialize/EmptyMapInitializerUnitTest.java +++ b/core-java-modules/core-java-collections-maps/src/test/java/com/baeldung/map/EmptyMapInitializerUnitTest.java @@ -1,11 +1,12 @@ -package com.baeldung.maps.initialize; - -import java.util.Map; -import org.junit.Test; +package com.baeldung.map; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Map; + +import org.junit.Test; + public class EmptyMapInitializerUnitTest { @Test(expected=UnsupportedOperationException.class) 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 48c70084ca..a11329365a 100644 --- a/core-java-modules/core-java-collections-set-2/README.md +++ b/core-java-modules/core-java-collections-set-2/README.md @@ -2,3 +2,5 @@ - [Using Streams to Collect Into a TreeSet](https://www.baeldung.com/java-stream-collect-into-treeset) - [A Guide to LinkedHashSet in Java](https://www.baeldung.com/java-linkedhashset) +- [Sorting a HashSet in Java](https://www.baeldung.com/java-sort-hashset) +- More articles: [[<-- prev]](/core-java-modules/core-java-collections-set) \ No newline at end of file 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 d3f54554e0..b1aadb0c22 100644 --- a/core-java-modules/core-java-collections-set-2/pom.xml +++ b/core-java-modules/core-java-collections-set-2/pom.xml @@ -15,6 +15,12 @@ + + org.junit.platform + junit-platform-runner + ${junit-platform.version} + test + diff --git a/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/hashset/sorting/HashSetUnitTest.java b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/hashset/sorting/HashSetUnitTest.java new file mode 100644 index 0000000000..ebb400570f --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/hashset/sorting/HashSetUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.hashset.sorting; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; + +public class HashSetUnitTest { + + @Test + void givenHashSet_whenUsingCollectionsSort_thenHashSetSorted() { + HashSet numberHashSet = new HashSet<>(); + numberHashSet.add(2); + numberHashSet.add(1); + numberHashSet.add(4); + numberHashSet.add(3); + // converting HashSet to arraylist + ArrayList arrayList = new ArrayList<>(numberHashSet); + // sorting the list + Collections.sort(arrayList); + assertThat(arrayList).containsExactly(1, 2, 3, 4); + } + + @Test + void givenHashSet_whenUsingTreeSet_thenHashSetSorted() { + HashSet numberHashSet = new HashSet<>(); + numberHashSet.add(2); + numberHashSet.add(1); + numberHashSet.add(4); + numberHashSet.add(3); + // TreeSet gets the value of hashSet + TreeSet treeSet = new TreeSet<>(); + treeSet.addAll(numberHashSet); + assertThat(treeSet).containsExactly(1, 2, 3, 4); + } + + @Test + void givenHashSet_whenUsingStream_thenHashSetSorted() { + HashSet numberHashSet = new HashSet<>(); + numberHashSet.add(200); + numberHashSet.add(100); + numberHashSet.add(400); + numberHashSet.add(300); + HashSet sortedHashSet = numberHashSet.stream().sorted() + .collect(Collectors.toCollection(LinkedHashSet::new)); + assertThat(sortedHashSet).containsExactly(100, 200, 300, 400); + } + +} diff --git a/core-java-modules/core-java-concurrency-2/src/main/java/com/baeldung/donerunnables/RunnableCompletionCheckerWithThreadPoolExecutor.java b/core-java-modules/core-java-concurrency-2/src/main/java/com/baeldung/donerunnables/RunnableCompletionCheckerWithThreadPoolExecutor.java index 17a13a1c19..aba75c5a3d 100644 --- a/core-java-modules/core-java-concurrency-2/src/main/java/com/baeldung/donerunnables/RunnableCompletionCheckerWithThreadPoolExecutor.java +++ b/core-java-modules/core-java-concurrency-2/src/main/java/com/baeldung/donerunnables/RunnableCompletionCheckerWithThreadPoolExecutor.java @@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory; public class RunnableCompletionCheckerWithThreadPoolExecutor { - private static final Logger LOGGER = LoggerFactory.getLogger(RunnableCompletionCheckerWithCompletableFuture.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RunnableCompletionCheckerWithThreadPoolExecutor.class); private static final int NUMBER_OF_RUNNABLES = 5; private static final int PAUSE_MILLIS = 1000; private static final int NUMBER_OF_THREADS = 5; diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithLock.java b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithLock.java index ef6b7ee8c8..09dfe575e6 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithLock.java +++ b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithLock.java @@ -1,7 +1,7 @@ package com.baeldung.concurrent.atomic; public class SafeCounterWithLock { - private volatile int counter; + private int counter; int getValue() { return counter; diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithoutLock.java b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithoutLock.java index 8b2aebba7c..e1117dd842 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithoutLock.java +++ b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/atomic/SafeCounterWithoutLock.java @@ -10,12 +10,6 @@ public class SafeCounterWithoutLock { } void increment() { - while(true) { - int existingValue = getValue(); - int newValue = existingValue + 1; - if(counter.compareAndSet(existingValue, newValue)) { - return; - } - } + counter.incrementAndGet(); } } diff --git a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/atomic/ThreadSafeCounterIntegrationTest.java b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/atomic/ThreadSafeCounterIntegrationTest.java index c3c44b40cf..9b4b628d0f 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/atomic/ThreadSafeCounterIntegrationTest.java +++ b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/atomic/ThreadSafeCounterIntegrationTest.java @@ -17,8 +17,8 @@ public class ThreadSafeCounterIntegrationTest { SafeCounterWithLock safeCounter = new SafeCounterWithLock(); IntStream.range(0, 1000) - .forEach(count -> service.submit(safeCounter::increment)); - service.awaitTermination(100, TimeUnit.MILLISECONDS); + .forEach(count -> service.execute(safeCounter::increment)); + shutdownAndAwaitTermination(service); assertEquals(1000, safeCounter.getValue()); } @@ -29,10 +29,30 @@ public class ThreadSafeCounterIntegrationTest { SafeCounterWithoutLock safeCounter = new SafeCounterWithoutLock(); IntStream.range(0, 1000) - .forEach(count -> service.submit(safeCounter::increment)); - service.awaitTermination(100, TimeUnit.MILLISECONDS); + .forEach(count -> service.execute(safeCounter::increment)); + shutdownAndAwaitTermination(service); assertEquals(1000, safeCounter.getValue()); } + + private void shutdownAndAwaitTermination(ExecutorService pool) { + // Disable new tasks from being submitted + pool.shutdown(); + try { + // Wait a while for existing tasks to terminate + if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) { + // Cancel currently executing tasks forcefully + pool.shutdownNow(); + // Wait a while for tasks to respond to being cancelled + if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) + System.err.println("Pool did not terminate"); + } + } catch (InterruptedException ex) { + // (Re-)Cancel if current thread also interrupted + pool.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } } diff --git a/core-java-modules/core-java-concurrency-basic-2/README.md b/core-java-modules/core-java-concurrency-basic-2/README.md index c9f1c11a89..455ff52081 100644 --- a/core-java-modules/core-java-concurrency-basic-2/README.md +++ b/core-java-modules/core-java-concurrency-basic-2/README.md @@ -11,4 +11,5 @@ This module contains articles about basic Java concurrency - [How to Stop Execution After a Certain Time in Java](https://www.baeldung.com/java-stop-execution-after-certain-time) - [How to Get the Number of Threads in a Java Process](https://www.baeldung.com/java-get-number-of-threads) - [Set the Name of a Thread in Java](https://www.baeldung.com/java-set-thread-name) +- [Thread vs. Single Thread Executor Service](https://www.baeldung.com/java-single-thread-executor-service) - [[<-- Prev]](../core-java-concurrency-basic)[[Next -->]](../core-java-concurrency-basic-3) 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 477f37e00a..46480c6b01 100644 --- a/core-java-modules/core-java-concurrency-basic-3/README.md +++ b/core-java-modules/core-java-concurrency-basic-3/README.md @@ -5,4 +5,5 @@ This module contains articles about basic Java concurrency. ### Relevant Articles: - [How to Handle InterruptedException in Java](https://www.baeldung.com/java-interrupted-exception) +- [Thread.sleep() vs Awaitility.await()](https://www.baeldung.com/java-thread-sleep-vs-awaitility-await) - [[<-- Prev]](../core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-basic-3/pom.xml b/core-java-modules/core-java-concurrency-basic-3/pom.xml index 7771d1200c..7289877550 100644 --- a/core-java-modules/core-java-concurrency-basic-3/pom.xml +++ b/core-java-modules/core-java-concurrency-basic-3/pom.xml @@ -24,4 +24,16 @@ + + 4.2.0 + + + + + org.awaitility + awaitility + ${awaitility.version} + test + + \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/RequestProcessor.java b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/RequestProcessor.java new file mode 100644 index 0000000000..9557a27f2a --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/RequestProcessor.java @@ -0,0 +1,35 @@ +package com.baeldung.concurrent; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class RequestProcessor { + + private Map requestStatuses = new HashMap<>(); + + public String processRequest() { + String requestId = UUID.randomUUID().toString(); + requestStatuses.put(requestId, "PROCESSING"); + + ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + executorService.schedule((() -> { + requestStatuses.put(requestId, "DONE"); + }), getRandomNumberBetween(500, 2000), TimeUnit.MILLISECONDS); + + return requestId; + } + + public String getStatus(String requestId) { + return requestStatuses.get(requestId); + } + + private int getRandomNumberBetween(int min, int max) { + Random random = new Random(); + return random.nextInt(max - min) + min; + } +} diff --git a/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/RequestProcessorUnitTest.java b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/RequestProcessorUnitTest.java new file mode 100644 index 0000000000..c437b08b34 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/RequestProcessorUnitTest.java @@ -0,0 +1,41 @@ +package com.baeldung.concurrent; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.TimeUnit; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("Request processor") +public class RequestProcessorUnitTest { + + RequestProcessor requestProcessor = new RequestProcessor(); + + @Test + @DisplayName("Wait for completion using Thread.sleep") + void whenWaitingWithThreadSleep_thenStatusIsDone() throws InterruptedException { + String requestId = requestProcessor.processRequest(); + + Thread.sleep(2000); + + assertEquals("DONE", requestProcessor.getStatus(requestId)); + } + + @Test + @DisplayName("Wait for completion using Awaitility") + void whenWaitingWithAwaitility_thenStatusIsDone() { + String requestId = requestProcessor.processRequest(); + + Awaitility.await() + .atMost(2, TimeUnit.SECONDS) + .pollDelay(500, TimeUnit.MILLISECONDS) + .until(() -> requestProcessor.getStatus(requestId), not(equalTo("PROCESSING"))); + + assertEquals("DONE", requestProcessor.getStatus(requestId)); + } + +} diff --git a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java similarity index 95% rename from core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java rename to core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java index 16d9aa4c9f..cd77069979 100644 --- a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java @@ -1,14 +1,15 @@ package com.baeldung.concurrent.executorservice; + import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; public class DelayedCallable implements Callable { - + private String name; private long period; private CountDownLatch latch; - + public DelayedCallable(String name, long period, CountDownLatch latch) { this(name, period); this.latch = latch; @@ -23,11 +24,11 @@ public class DelayedCallable implements Callable { try { Thread.sleep(period); - + if (latch != null) { latch.countDown(); } - + } catch (InterruptedException ex) { // handle exception ex.printStackTrace(); @@ -36,4 +37,4 @@ public class DelayedCallable implements Callable { return name; } -} +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java similarity index 90% rename from core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java rename to core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java index cd8b015be2..8e08914c3c 100644 --- a/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java +++ b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java @@ -1,15 +1,24 @@ package com.baeldung.concurrent.executorservice; +import static junit.framework.TestCase.assertTrue; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletionService; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; + import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.*; - -import static junit.framework.TestCase.assertTrue; - public class WaitingForThreadsToFinishManualTest { private static final Logger LOG = LoggerFactory.getLogger(WaitingForThreadsToFinishManualTest.class); @@ -26,18 +35,18 @@ public class WaitingForThreadsToFinishManualTest { Thread.currentThread().interrupt(); } } - + @Test public void givenMultipleThreads_whenUsingCountDownLatch_thenMainShoudWaitForAllToFinish() { ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); - + try { long startTime = System.currentTimeMillis(); // create a CountDownLatch that waits for the 2 threads to finish CountDownLatch latch = new CountDownLatch(2); - + for (int i = 0; i < 2; i++) { WORKER_THREAD_POOL.submit(() -> { try { @@ -69,13 +78,13 @@ public class WaitingForThreadsToFinishManualTest { ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); List> callables = Arrays.asList( - new DelayedCallable("fast thread", 100), + new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); try { long startProcessingTime = System.currentTimeMillis(); List> futures = WORKER_THREAD_POOL.invokeAll(callables); - + awaitTerminationAfterShutdown(WORKER_THREAD_POOL); try { @@ -100,7 +109,7 @@ public class WaitingForThreadsToFinishManualTest { } catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); - } + } } @Test @@ -109,7 +118,7 @@ public class WaitingForThreadsToFinishManualTest { CompletionService service = new ExecutorCompletionService<>(WORKER_THREAD_POOL); List> callables = Arrays.asList( - new DelayedCallable("fast thread", 100), + new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); for (Callable callable : callables) { @@ -142,4 +151,4 @@ public class WaitingForThreadsToFinishManualTest { awaitTerminationAfterShutdown(WORKER_THREAD_POOL); } } -} +} \ No newline at end of file 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 692c218395..c812ed4284 100644 --- a/core-java-modules/core-java-concurrency-collections-2/README.md +++ b/core-java-modules/core-java-concurrency-collections-2/README.md @@ -3,4 +3,5 @@ - [Introduction to Lock Striping](https://www.baeldung.com/java-lock-stripping) - [Guide to the Java TransferQueue](http://www.baeldung.com/java-transfer-queue) - [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) - [[<-- Prev]](/core-java-modules/core-java-concurrency-collections) diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessBenchmark.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessBenchmark.java index ceb53ce077..28231a15a8 100644 --- a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessBenchmark.java +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessBenchmark.java @@ -19,7 +19,7 @@ import org.openjdk.jmh.annotations.Warmup; @Warmup(iterations = 0) public class ConcurrentAccessBenchmark { static final int SLOTS = 4; - static final int THREADS = 10000; + static final int TASKS = 10000; static final int BUCKETS = Runtime.getRuntime().availableProcessors() * SLOTS; SingleLock singleLock = new SingleLock(); StripedLock stripedLock = new StripedLock(BUCKETS); @@ -28,27 +28,27 @@ public class ConcurrentAccessBenchmark { @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public Map singleLockHashMap() throws InterruptedException { - return singleLock.doWork(new HashMap(), THREADS, SLOTS); + return singleLock.doWork(new HashMap(), TASKS, SLOTS); } @Benchmark @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public Map stripedLockHashMap() throws InterruptedException { - return stripedLock.doWork(new HashMap(), THREADS, SLOTS); + return stripedLock.doWork(new HashMap(), TASKS, SLOTS); } @Benchmark @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public Map singleLockConcurrentHashMap() throws InterruptedException { - return singleLock.doWork(new ConcurrentHashMap(), THREADS, SLOTS); + return singleLock.doWork(new ConcurrentHashMap(), TASKS, SLOTS); } @Benchmark @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public Map stripedLockConcurrentHashMap() throws InterruptedException { - return stripedLock.doWork(new ConcurrentHashMap(), THREADS, SLOTS); + return stripedLock.doWork(new ConcurrentHashMap(), TASKS, SLOTS); } } diff --git a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessExperiment.java b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessExperiment.java index ec6d3895da..b24f0c8b19 100644 --- a/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessExperiment.java +++ b/core-java-modules/core-java-concurrency-collections-2/src/main/java/com/baeldung/concurrent/lock/ConcurrentAccessExperiment.java @@ -7,10 +7,10 @@ import com.google.common.base.Supplier; public abstract class ConcurrentAccessExperiment { - public final Map doWork(Map map, int threads, int slots) { - CompletableFuture[] requests = new CompletableFuture[threads * slots]; + public final Map doWork(Map map, int tasks, int slots) { + CompletableFuture[] requests = new CompletableFuture[tasks * slots]; - for (int i = 0; i < threads; i++) { + for (int i = 0; i < tasks; i++) { requests[slots * i + 0] = CompletableFuture.supplyAsync(putSupplier(map, i)); requests[slots * i + 1] = CompletableFuture.supplyAsync(getSupplier(map, i)); requests[slots * i + 2] = CompletableFuture.supplyAsync(getSupplier(map, i)); diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrenthashmap/ConcurrentHashMapUnitTest.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrenthashmap/ConcurrentHashMapUnitTest.java new file mode 100644 index 0000000000..2ae510b365 --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrenthashmap/ConcurrentHashMapUnitTest.java @@ -0,0 +1,109 @@ +package com.baeldung.concurrenthashmap; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ConcurrentHashMapUnitTest { + + private Map frequencyMap = new ConcurrentHashMap<>(); + + @BeforeEach + public void setup() { + frequencyMap.put(0, 0); + frequencyMap.put(1, 0); + frequencyMap.put(2, 0); + } + + @AfterEach + public void teardown() { + frequencyMap.clear(); + } + + @Test + public void givenOneThreadIsWriting_whenAnotherThreadReads_thenGetCorrectValue() throws Exception { + ExecutorService threadExecutor = Executors.newFixedThreadPool(3); + + Runnable writeAfter1Sec = () -> frequencyMap.computeIfPresent(1, (k, v) -> { + sleep(1); + return v + 1; + }); + + Callable readNow = () -> frequencyMap.get(1); + Callable readAfter2sec = () -> { + sleep(2); + return frequencyMap.get(1); + }; + + threadExecutor.submit(writeAfter1Sec); + List> results = threadExecutor.invokeAll(asList(readNow, readAfter2sec)); + + assertEquals(0, results.get(0).get()); + assertEquals(1, results.get(1).get()); + + threadExecutor.shutdown(); + } + + @Test + public void givenOneThreadIsWriting_whenAnotherThreadWritesAtSameKey_thenWaitAndGetCorrectValue() throws Exception { + ExecutorService threadExecutor = Executors.newFixedThreadPool(2); + + Callable writeAfter5Sec = () -> frequencyMap.computeIfPresent(1, (k, v) -> { + sleep(5); + return v + 1; + }); + + Callable writeAfter1Sec = () -> frequencyMap.computeIfPresent(1, (k, v) -> { + sleep(1); + return v + 1; + }); + + Future result1 = threadExecutor.submit(writeAfter5Sec); + sleep(1); + Future result2 = threadExecutor.submit(writeAfter1Sec); + + assertEquals(1, result1.get()); + assertEquals(2, result2.get()); + + threadExecutor.shutdown(); + } + + @Test + public void givenOneThreadIsWriting_whenAnotherThreadWritesAtDifferentKey_thenNotWait() throws InterruptedException { + ExecutorService threadExecutor = Executors.newFixedThreadPool(2); + + Callable writeAfter5Sec = () -> frequencyMap.computeIfPresent(1, (k, v) -> { + sleep(5); + return v + 1; + }); + + AtomicLong time = new AtomicLong(System.currentTimeMillis()); + Callable writeAfter1Sec = () -> frequencyMap.computeIfPresent(2, (k, v) -> { + sleep(1); + time.set((System.currentTimeMillis() - time.get()) / 1000); + return v + 1; + }); + + threadExecutor.invokeAll(asList(writeAfter5Sec, writeAfter1Sec)); + + assertEquals(1, time.get()); + + threadExecutor.shutdown(); + } + + private static void sleep(int timeout) { + try { + TimeUnit.SECONDS.sleep(timeout); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/CallableTask.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/CallableTask.java new file mode 100644 index 0000000000..bd01491e1e --- /dev/null +++ b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/CallableTask.java @@ -0,0 +1,10 @@ +package com.baeldung.concurrent.executorservice; + +import java.util.concurrent.Callable; + +public class CallableTask implements Callable { + @Override + public String call() throws Exception { + return "Hello world"; + } +} diff --git a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java deleted file mode 100644 index 83a9fb6692..0000000000 --- a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.concurrent.executorservice; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -public class ExecutorServiceDemo { - - ExecutorService executor = Executors.newFixedThreadPool(10); - - public void execute() { - - executor.submit(() -> { - new Task(); - }); - - executor.shutdown(); - executor.shutdownNow(); - try { - executor.awaitTermination(20l, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - -} diff --git a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ScheduledExecutorServiceDemo.java similarity index 59% rename from core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ScheduledExecutorServiceDemo.java index 0989195ba7..613cb6a022 100644 --- a/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java +++ b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ScheduledExecutorServiceDemo.java @@ -1,13 +1,15 @@ -package com.baeldung.concurrent.Scheduledexecutorservice; +package com.baeldung.concurrent.executorservice; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.function.Function; public class ScheduledExecutorServiceDemo { + private Task runnableTask; + private CallableTask callableTask; private void execute() { ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); getTasksToRun().apply(executorService); @@ -21,23 +23,14 @@ public class ScheduledExecutorServiceDemo { } private Function getTasksToRun() { + + runnableTask = new Task(); + callableTask = new CallableTask(); + return (executorService -> { - ScheduledFuture scheduledFuture1 = executorService.schedule(() -> { - // Task - }, 1, TimeUnit.SECONDS); - - ScheduledFuture scheduledFuture2 = executorService.scheduleAtFixedRate(() -> { - // Task - }, 1, 10, TimeUnit.SECONDS); - - ScheduledFuture scheduledFuture3 = executorService.scheduleWithFixedDelay(() -> { - // Task - }, 1, 10, TimeUnit.SECONDS); - - ScheduledFuture scheduledFuture4 = executorService.schedule(() -> { - // Task - return "Hellow world"; - }, 1, TimeUnit.SECONDS); + Future resultFuture = executorService.schedule(callableTask, 1, TimeUnit.SECONDS); + executorService.scheduleAtFixedRate( runnableTask, 100, 450, TimeUnit.SECONDS); + executorService.scheduleWithFixedDelay( runnableTask, 100, 150, TimeUnit.SECONDS); return null; }); } @@ -48,5 +41,4 @@ public class ScheduledExecutorServiceDemo { demo.executeWithMultiThread(); } - } diff --git a/core-java-modules/core-java-datetime-conversion/README.md b/core-java-modules/core-java-datetime-conversion/README.md index 2503459f50..11e4348838 100644 --- a/core-java-modules/core-java-datetime-conversion/README.md +++ b/core-java-modules/core-java-datetime-conversion/README.md @@ -7,3 +7,4 @@ This module contains articles about converting between Java date and time object - [Convert Time to Milliseconds in Java](https://www.baeldung.com/java-time-milliseconds) - [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) diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/localdatetimetozoneddatetime/LocalDateTimeToZonedDateTimeUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/localdatetimetozoneddatetime/LocalDateTimeToZonedDateTimeUnitTest.java new file mode 100644 index 0000000000..10a2e75372 --- /dev/null +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/localdatetimetozoneddatetime/LocalDateTimeToZonedDateTimeUnitTest.java @@ -0,0 +1,89 @@ +import org.junit.jupiter.api.Test; + +import java.time.*; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +public class LocalDateTimeToZonedDateTimeUnitTest { + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithAtZoneMethod_shouldConvertAndMaintainDateTimeValues(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 30, 22); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Canada/Atlantic")); + + assertEquals(localDateTime.getYear(), zonedDateTime.getYear()); + assertEquals(localDateTime.getMonth(), zonedDateTime.getMonth()); + assertEquals(localDateTime.getDayOfMonth(), zonedDateTime.getDayOfMonth()); + assertEquals(localDateTime.getHour(), zonedDateTime.getHour()); + assertEquals(localDateTime.getMinute(), zonedDateTime.getMinute()); + assertEquals(localDateTime.getSecond(), zonedDateTime.getSecond()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithAtZoneAndwithZoneSameInstantMethods_shouldConvert(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 30, 22); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Africa/Lagos")).withZoneSameInstant(ZoneId.of("Canada/Atlantic")); + + assertEquals("2021-12-31T19:30:22-04:00[Canada/Atlantic]", zonedDateTime.toString()); + assertEquals("-04:00", zonedDateTime.getOffset().toString()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithOfMethod_shouldConvert(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 11, 5, 7, 30, 22); + ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Africa/Accra")).withZoneSameInstant(ZoneId.of("Africa/Lagos")); + + assertEquals("2022-11-05T08:30:22+01:00[Africa/Lagos]", zonedDateTime.toString()); + assertEquals(localDateTime.getYear(), zonedDateTime.getYear()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithOfInstantMethod_shouldConvert(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 5, 17, 30, 22); + ZoneId zoneId = ZoneId.of("Africa/Lagos"); + ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime); + ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(localDateTime, zoneOffset, zoneId); + + assertEquals("2022-01-05T17:30:22+01:00[Africa/Lagos]", zonedDateTime.toString()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithOfLocalMethod_shouldConvert(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 8, 25, 8, 35, 22); + ZoneId zoneId = ZoneId.of("Africa/Lagos"); + ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime); + ZonedDateTime zonedDateTime = ZonedDateTime.ofLocal(localDateTime, zoneId, zoneOffset); + + assertEquals("2022-08-25T08:35:22+01:00[Africa/Lagos]", zonedDateTime.toString()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithOfStrictMethod_shouldConvert(){ + LocalDateTime localDateTime = LocalDateTime.of(2002, 12, 25, 6, 18, 2); + ZoneId zoneId = ZoneId.of("Asia/Tokyo"); + ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime); + ZonedDateTime zonedDateTime = ZonedDateTime.ofStrict(localDateTime, zoneOffset, zoneId); + + assertEquals("2002-12-25T06:18:02+09:00[Asia/Tokyo]", zonedDateTime.toString()); + } + + @Test + void whenConvertLocalDateTimeToZonedDateTimeWithInvalidZoneOffSet_shouldThrowDateTimeException(){ + LocalDateTime localDateTime = LocalDateTime.of(2022, 12, 25, 6, 18, 2);; + ZoneId zoneId = ZoneId.of("Asia/Tokyo"); + ZoneOffset zoneOffset = ZoneOffset.UTC; + assertThrows(DateTimeException.class, () -> ZonedDateTime.ofStrict(localDateTime, zoneOffset, zoneId)); + } + + + @Test + void whenConvertZonedDateTimeToLocalDateTimeWithToLocalDateTimeMethod_shouldConvert(){ + ZonedDateTime zonedDateTime = ZonedDateTime.of(2011, 2, 12, 6, 14, 1, 58086000, ZoneId.of("Asia/Tokyo")); + LocalDateTime localDateTime = zonedDateTime.toLocalDateTime(); + + assertEquals("2011-02-12T06:14:01.058086+09:00[Asia/Tokyo]", zonedDateTime.toString()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions-4/README.md b/core-java-modules/core-java-exceptions-4/README.md index ccc40f3858..dc76b90fc7 100644 --- a/core-java-modules/core-java-exceptions-4/README.md +++ b/core-java-modules/core-java-exceptions-4/README.md @@ -8,4 +8,6 @@ This module contains articles about core java exceptions - [Convert long to int Type in Java](https://www.baeldung.com/java-convert-long-to-int) - [“Sneaky Throws” in Java](https://www.baeldung.com/java-sneaky-throws) - [Get the Current Stack Trace in Java](https://www.baeldung.com/java-get-current-stack-trace) +- [Errors and Exceptions in Java](https://www.baeldung.com/java-errors-vs-exceptions) +- [Fix the IllegalArgumentException: No enum const class](https://www.baeldung.com/java-fix-no-enum-const-class) - [[<-- Prev]](../core-java-exceptions-3) diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/CheckedExceptionExcample.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/CheckedExceptionExcample.java new file mode 100644 index 0000000000..443f34265e --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/CheckedExceptionExcample.java @@ -0,0 +1,15 @@ +package com.baeldung.exception.exceptions_vs_errors; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class CheckedExceptionExcample { + public static void main(String[] args) { + try (FileInputStream fis = new FileInputStream(new File("test.txt"))) { + fis.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/ErrorExample.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/ErrorExample.java new file mode 100644 index 0000000000..904877e01e --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/ErrorExample.java @@ -0,0 +1,9 @@ +package com.baeldung.exception.exceptions_vs_errors; + +public class ErrorExample { + + public static void main(String[] args) { + throw new AssertionError(); + } + +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExample.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExample.java new file mode 100644 index 0000000000..3d5728c385 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExample.java @@ -0,0 +1,11 @@ +package com.baeldung.exception.exceptions_vs_errors; + +public class RuntimeExceptionExample { + public static void main(String[] args) { + int[] arr = new int[20]; + + arr[20] = 20; + + System.out.println(arr[20]); + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/Priority.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/Priority.java new file mode 100644 index 0000000000..ff9591b1e0 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/Priority.java @@ -0,0 +1,13 @@ +package com.baeldung.exception.noenumconst; + +public enum Priority { + + HIGH("High"), MEDIUM("Medium"), LOW("Low"); + + private String name; + + Priority(String name) { + this.name = name; + } + +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/PriorityUtils.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/PriorityUtils.java new file mode 100644 index 0000000000..8d7004bf39 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/noenumconst/PriorityUtils.java @@ -0,0 +1,21 @@ +package com.baeldung.exception.noenumconst; + +public class PriorityUtils { + + public static Priority getByName(String name) { + return Priority.valueOf(name); + } + + public static Priority getByUpperCaseName(String name) { + if (name == null || name.isEmpty()) { + return null; + } + + return Priority.valueOf(name.toUpperCase()); + } + + public static void main(String[] args) { + System.out.println(getByName("Low")); + } + +} diff --git a/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/ErrorExampleUnitTest.java b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/ErrorExampleUnitTest.java new file mode 100644 index 0000000000..acbb07be1f --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/ErrorExampleUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.exception.exceptions_vs_errors; + +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class ErrorExampleUnitTest { + + @Test + public void whenMainMethodIsRun_thenStackOverflowError() { + Assertions.assertThrows(AssertionError.class, + () -> ErrorExample.main(null)); + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExampleUnitTest.java b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExampleUnitTest.java new file mode 100644 index 0000000000..9c2c1f478b --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/exceptions_vs_errors/RuntimeExceptionExampleUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.exception.exceptions_vs_errors; + +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +// Unit test for the RuntimeExceptionExample class. +public class RuntimeExceptionExampleUnitTest { + @Test + public void whenMainMethodIsRun_thenArrayIndexOutOfBoundsExceptionIsThrown() { + Assertions.assertThrows(ArrayIndexOutOfBoundsException.class, + () -> RuntimeExceptionExample.main(null)); + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/noenumconst/PriorityUtilsUnitTest.java b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/noenumconst/PriorityUtilsUnitTest.java new file mode 100644 index 0000000000..1ff9c49015 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/noenumconst/PriorityUtilsUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.exception.noenumconst; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class PriorityUtilsUnitTest { + + @Test + void givenCustomName_whenUsingGetByName_thenThrowIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> PriorityUtils.getByName("Low")); + } + + @Test + void givenCustomName_whenUsingGetByUpperCaseName_thenReturnEnumConstant() { + assertEquals(Priority.HIGH, PriorityUtils.getByUpperCaseName("High")); + } + + @Test + void givenInvalidCustomName_whenUsingGetByUpperCaseName_thenThrowIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> PriorityUtils.getByUpperCaseName("invalid")); + } + + @Test + void givenEmptyName_whenUsingGetByUpperCaseName_thenReturnNull() { + assertNull(PriorityUtils.getByUpperCaseName("")); + } + + @Test + void givenNull_whenUsingGetByUpperCaseName_thenReturnNull() { + assertNull(PriorityUtils.getByUpperCaseName(null)); + } + +} diff --git a/core-java-modules/core-java-functional/README.md b/core-java-modules/core-java-functional/README.md index 5891b4a943..addb312542 100644 --- a/core-java-modules/core-java-functional/README.md +++ b/core-java-modules/core-java-functional/README.md @@ -1,3 +1,5 @@ ## Relevant articles: - [Functional Programming in Java](https://www.baeldung.com/java-functional-programming) +- [Functors in Java](https://www.baeldung.com/java-functors) +- [Callback Functions in Java](https://www.baeldung.com/java-callback-functions) diff --git a/core-java-modules/core-java-functional/pom.xml b/core-java-modules/core-java-functional/pom.xml index 52d74035a5..9ad47f8133 100644 --- a/core-java-modules/core-java-functional/pom.xml +++ b/core-java-modules/core-java-functional/pom.xml @@ -14,4 +14,30 @@ 0.0.1-SNAPSHOT + + + org.mockito + mockito-inline + ${mockito-inline.version} + test + + + + + core-java-functional + + + src/main/resources + true + + + + + + 3.8.0 + 3.22.0 + 3.12.0 + 0.10.4 + + \ No newline at end of file diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/ConsumerCallback.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/ConsumerCallback.java new file mode 100644 index 0000000000..f3086b8cef --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/ConsumerCallback.java @@ -0,0 +1,17 @@ +package com.baeldung.callbackfunctions; + +import java.util.function.Consumer; + +public class ConsumerCallback { + public void getAge(int initialAge, Consumer callback) { + callback.accept(initialAge); + } + + public void increaseAge(int initialAge, int ageDifference, Consumer callback) { + System.out.println("===== Increase age ===="); + + int newAge = initialAge + ageDifference; + callback.accept(newAge); + + } +} diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/EventListener.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/EventListener.java new file mode 100644 index 0000000000..dceba7a931 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/EventListener.java @@ -0,0 +1,12 @@ +package com.baeldung.callbackfunctions; + +public interface EventListener { + + String onTrigger(); + + void respondToTrigger(); +} + + + + diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventConsumer.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventConsumer.java new file mode 100644 index 0000000000..d2f3732679 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventConsumer.java @@ -0,0 +1,21 @@ +package com.baeldung.callbackfunctions.asynchronous; + +import com.baeldung.callbackfunctions.EventListener; + +public class AsynchronousEventConsumer{ + + private EventListener listener; + + public AsynchronousEventConsumer(EventListener listener) { + this.listener = listener; + } + + public void doAsynchronousOperation() + { + System.out.println("Performing operation in Asynchronous Task"); + + new Thread(() -> listener.onTrigger()).start(); + } + + +} diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventListenerImpl.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventListenerImpl.java new file mode 100644 index 0000000000..a6e43797f5 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/asynchronous/AsynchronousEventListenerImpl.java @@ -0,0 +1,19 @@ +package com.baeldung.callbackfunctions.asynchronous; + +import com.baeldung.callbackfunctions.EventListener; + +public class AsynchronousEventListenerImpl implements EventListener { + + @Override + public String onTrigger() + { + respondToTrigger(); + return "Asynchronously running callback function"; + } + + @Override + public void respondToTrigger(){ + System.out.println("This is a side effect of the asynchronous trigger."); + } + +} diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventConsumer.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventConsumer.java new file mode 100644 index 0000000000..9b06151854 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventConsumer.java @@ -0,0 +1,22 @@ +package com.baeldung.callbackfunctions.synchronous; + +import com.baeldung.callbackfunctions.EventListener; + +public class SynchronousEventConsumer { + + private final EventListener eventListener; + + public SynchronousEventConsumer(EventListener listener) + { + this.eventListener = listener; + } + + public String doSynchronousOperation() + { + System.out.println("Performing callback before synchronous Task"); + + return eventListener.onTrigger(); + } + + +} diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventListenerImpl.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventListenerImpl.java new file mode 100644 index 0000000000..156f7857c3 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/callbackfunctions/synchronous/SynchronousEventListenerImpl.java @@ -0,0 +1,18 @@ +package com.baeldung.callbackfunctions.synchronous; + +import com.baeldung.callbackfunctions.EventListener; + +public class SynchronousEventListenerImpl implements EventListener { + + @Override + public String onTrigger() + { + return "Synchronously running callback function"; + } + + @Override + public void respondToTrigger(){ + System.out.println("Response to trigger"); + } + +} diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/EnumFunctor.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/EnumFunctor.java new file mode 100644 index 0000000000..380ebf6708 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/EnumFunctor.java @@ -0,0 +1,23 @@ +package com.baeldung.functional.functors; + +public enum EnumFunctor { + PLUS { + public int apply(int a, int b) { + return a + b; + } + }, MINUS { + public int apply(int a, int b) { + return a - b; + } + }, MULTIPLY { + public int apply(int a, int b) { + return a * b; + } + }, DIVIDE { + public int apply(int a, int b) { + return a / b; + } + }; + + public abstract int apply(int a, int b); +} \ No newline at end of file diff --git a/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/Functor.java b/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/Functor.java new file mode 100644 index 0000000000..778d0aacb7 --- /dev/null +++ b/core-java-modules/core-java-functional/src/main/java/com/baeldung/functional/functors/Functor.java @@ -0,0 +1,23 @@ +package com.baeldung.functional.functors; + +import java.util.function.Function; + +public class Functor { + private final T value; + + public Functor(T value) { + this.value = value; + } + + public Functor map(Function mapper) { + return new Functor<>(mapper.apply(value)); + } + + boolean eq(T other) { + return value.equals(other); + } + + public T getValue() { + return value; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/AsynchronousCallbackUnitTest.java b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/AsynchronousCallbackUnitTest.java new file mode 100644 index 0000000000..de9e386395 --- /dev/null +++ b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/AsynchronousCallbackUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.callbackfunctions; + +import org.junit.Test; +import org.mockito.Mockito; +import com.baeldung.callbackfunctions.EventListener; +import com.baeldung.callbackfunctions.asynchronous.AsynchronousEventConsumer; +import com.baeldung.callbackfunctions.asynchronous.AsynchronousEventListenerImpl; + +import static org.mockito.Mockito.*; + +public class AsynchronousCallbackUnitTest { + + @Test + public void whenCallbackIsInvokedAsynchronously_shouldRunAsynchronousOperation(){ + EventListener listener = Mockito.mock(AsynchronousEventListenerImpl.class); + AsynchronousEventConsumer asynchronousEventListenerConsumer = new AsynchronousEventConsumer(listener); + asynchronousEventListenerConsumer.doAsynchronousOperation(); + + verify(listener, timeout(1000).times(1)).onTrigger(); + } +} diff --git a/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/ConsumerCallbackUnitTest.java b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/ConsumerCallbackUnitTest.java new file mode 100644 index 0000000000..9ba5cdb6ef --- /dev/null +++ b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/ConsumerCallbackUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.callbackfunctions; + +import org.junit.jupiter.api.Test; +import com.baeldung.callbackfunctions.ConsumerCallback; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ConsumerCallbackUnitTest { + + @Test + void whenIncreasingInitialAgeByGivenValueThroughCallback_shouldIncreaseAge(){ + ConsumerCallback consumerCallback = new ConsumerCallback(); + int ageDifference = 10; + AtomicInteger newAge1 = new AtomicInteger(); + int initialAge = 20; + consumerCallback.getAge(initialAge, (initialAge1) -> { + consumerCallback.increaseAge(initialAge, ageDifference, (newAge) -> { + System.out.printf("New age ==> %s", newAge); + newAge1.set(newAge); + + }); + }); + assertEquals(initialAge + ageDifference, newAge1.get()); + } +} diff --git a/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/SynchronousCallbackUnitTest.java b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/SynchronousCallbackUnitTest.java new file mode 100644 index 0000000000..0c270524b7 --- /dev/null +++ b/core-java-modules/core-java-functional/src/test/java/com/baeldung/callbackfunctions/SynchronousCallbackUnitTest.java @@ -0,0 +1,22 @@ +package callbackFunctions; + +import org.junit.jupiter.api.Test; +import com.baeldung.callbackfunctions.EventListener; +import com.baeldung.callbackfunctions.synchronous.SynchronousEventConsumer; +import com.baeldung.callbackfunctions.synchronous.SynchronousEventListenerImpl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class SynchronousCallbackUnitTest { + + @Test + public void whenCallbackIsInvokedSynchronously_shouldRunSynchronousOperation(){ + EventListener listener = new SynchronousEventListenerImpl(); + SynchronousEventConsumer synchronousEventConsumer = new SynchronousEventConsumer(listener); + String result = synchronousEventConsumer.doSynchronousOperation(); + + assertNotNull(result); + assertEquals("Synchronously running callback function", result); + } +} diff --git a/core-java-modules/core-java-functional/src/test/java/com/baeldung/functional/functors/FunctorsUnitTest.java b/core-java-modules/core-java-functional/src/test/java/com/baeldung/functional/functors/FunctorsUnitTest.java new file mode 100644 index 0000000000..c29851d9c3 --- /dev/null +++ b/core-java-modules/core-java-functional/src/test/java/com/baeldung/functional/functors/FunctorsUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.functional.functors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +class FunctorsUnitTest { + @Test + public void whenProvideAValue_ShouldMapTheValue() { + Functor functor = new Functor<>(5); + Function addThree = (num) -> num + 3; + Functor mappedFunctor = functor.map(addThree); + assertEquals(8, mappedFunctor.getValue()); + } + + @Test + public void whenApplyAnIdentityToAFunctor_thenResultIsEqualsToInitialValue() { + String value = "baeldung"; + //Identity + Functor identity = new Functor<>(value).map(Function.identity()); + assertTrue(identity.eq(value)); + } + + @Test + public void whenApplyAFunctionToOtherFunction_thenResultIsEqualsBetweenBoth() { + int value = 100; + long expected = 100; + // Composition/Associativity + Function f = Object::toString; + Function g = Long::valueOf; + + Functor left = new Functor<>(value).map(f) + .map(g); + Functor right = new Functor<>(value).map(f.andThen(g)); + + assertTrue(left.eq(expected)); + assertTrue(right.eq(expected)); + } + + @Test + public void whenApplyOperationsToEnumFunctors_thenGetTheProperResult() { + assertEquals(15, EnumFunctor.PLUS.apply(10, 5)); + assertEquals(5, EnumFunctor.MINUS.apply(10, 5)); + assertEquals(50, EnumFunctor.MULTIPLY.apply(10, 5)); + assertEquals(2, EnumFunctor.DIVIDE.apply(10, 5)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-hex/README.md b/core-java-modules/core-java-hex/README.md new file mode 100644 index 0000000000..0ba4d1372f --- /dev/null +++ b/core-java-modules/core-java-hex/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Convert Hex to RGB Using Java](https://www.baeldung.com/java-convert-hex-to-rgb) diff --git a/core-java-modules/core-java-hex/pom.xml b/core-java-modules/core-java-hex/pom.xml new file mode 100644 index 0000000000..afac1c4d66 --- /dev/null +++ b/core-java-modules/core-java-hex/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + core-java-hex + 0.1.0-SNAPSHOT + core-java-hex + 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-hex/src/test/java/com/baeldung/hextorgb/HexToRgbUnitTest.java b/core-java-modules/core-java-hex/src/test/java/com/baeldung/hextorgb/HexToRgbUnitTest.java new file mode 100644 index 0000000000..35e5b87d29 --- /dev/null +++ b/core-java-modules/core-java-hex/src/test/java/com/baeldung/hextorgb/HexToRgbUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.hextorgb; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class HexToRgbUnitTest { + + @Test + public void givenHexCode_whenConvertedToRgb_thenCorrectRgbValuesAreReturned() { + String hexCode = "FF9933"; + int red = 255; + int green = 153; + int blue = 51; + + int resultRed = Integer.valueOf(hexCode.substring(0, 2), 16); + int resultGreen = Integer.valueOf(hexCode.substring(2, 4), 16); + int resultBlue = Integer.valueOf(hexCode.substring(4, 6), 16); + + assertEquals(red, resultRed); + assertEquals(green, resultGreen); + assertEquals(blue, resultBlue); + } + +} diff --git a/core-java-modules/core-java-httpclient/README.md b/core-java-modules/core-java-httpclient/README.md index 68f828e81b..5dbb7a08ef 100644 --- a/core-java-modules/core-java-httpclient/README.md +++ b/core-java-modules/core-java-httpclient/README.md @@ -5,3 +5,4 @@ This module contains articles about Java HttpClient ### Relevant articles - [Posting with Java HttpClient](https://www.baeldung.com/java-httpclient-post) - [Custom HTTP Header With the Java HttpClient](https://www.baeldung.com/java-http-client-custom-header) +- [Java HttpClient Connection Management](https://www.baeldung.com/java-httpclient-connection-management) diff --git a/core-java-modules/core-java-httpclient/pom.xml b/core-java-modules/core-java-httpclient/pom.xml index 57b23e96c1..3df0447ff0 100644 --- a/core-java-modules/core-java-httpclient/pom.xml +++ b/core-java-modules/core-java-httpclient/pom.xml @@ -32,6 +32,12 @@ ${assertj.version} test + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + @@ -53,6 +59,7 @@ 11 3.22.0 5.11.2 + 2.27.2 \ No newline at end of file diff --git a/core-java-modules/core-java-httpclient/src/test/java/com/baeldung/httpclient/HttpClientConnectionManagementUnitTest.java b/core-java-modules/core-java-httpclient/src/test/java/com/baeldung/httpclient/HttpClientConnectionManagementUnitTest.java new file mode 100644 index 0000000000..3b7610276c --- /dev/null +++ b/core-java-modules/core-java-httpclient/src/test/java/com/baeldung/httpclient/HttpClientConnectionManagementUnitTest.java @@ -0,0 +1,147 @@ +package com.baeldung.httpclient.conn; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.List; + +import static java.net.URI.create; + + +public class HttpClientConnectionManagementUnitTest { + + WireMockConfiguration firstConfiguration = WireMockConfiguration + .options() + .dynamicPort(); + WireMockConfiguration secondConfiguration = WireMockConfiguration + .options() + .dynamicPort(); + WireMockServer firstServer = new WireMockServer(firstConfiguration); + WireMockServer secondServer = new WireMockServer(secondConfiguration); + private String firstUrl; + private String secondUrl; + + private HttpClient client = HttpClient.newHttpClient(); + private HttpClient secondClient = HttpClient.newHttpClient(); + + private HttpRequest getRequest; + private HttpRequest secondGet; + + @Before + public void setup() { + firstServer.start(); + secondServer.start(); + + // add some request matchers + firstServer.stubFor(WireMock + .get(WireMock.anyUrl()) + .willReturn(WireMock + .aResponse() + .withStatus(200))); + secondServer.stubFor(WireMock + .get(WireMock.anyUrl()) + .willReturn(WireMock + .aResponse() + .withStatus(200))); + + firstUrl = "http://localhost:" + firstServer.port() + "/first"; + secondUrl = "http://localhost:" + secondServer.port() + "/second"; + + getRequest = HttpRequest + .newBuilder() + .uri(create(firstUrl)) + .version(HttpClient.Version.HTTP_1_1) + .build(); + + secondGet = HttpRequest + .newBuilder() + .uri(create(secondUrl)) + .version(HttpClient.Version.HTTP_1_1) + .build(); + } + + @After + public void tearDown() { + // display all the requests that the WireMock servers handled + List firstWiremockAllServeEvents = firstServer.getAllServeEvents(); + List secondWiremockAllServeEvents = secondServer.getAllServeEvents(); + firstWiremockAllServeEvents + .stream() + .map(event -> event + .getRequest() + .getAbsoluteUrl()) + .forEach(System.out::println); + secondWiremockAllServeEvents + .stream() + .map(event -> event + .getRequest() + .getAbsoluteUrl()) + .forEach(System.out::println); + + // stop the WireMock servers + firstServer.stop(); + secondServer.stop(); + } + + // Example 1. Use an HttpClient to connect to the same endpoint - reuses a connection from the internal pool + @Test + public final void givenAnHttpClient_whenTwoConnectionsToSameEndpointMadeSequentially_thenConnectionReused() throws InterruptedException, IOException { + + // given two requests to the same destination + final HttpResponse firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + final HttpResponse secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + + assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200); + } + + // Example 2. Use separate HttpClients to connect to the same endpoint - creates a connection per client + @Test + public final void givenTwoHttpClients_whenEachClientMakesConnectionSequentially_thenConnectionCreatedForEach() throws InterruptedException, IOException { + + // given requests from two different client to same destination + final HttpResponse firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + final HttpResponse secondResponse = secondClient.send(getRequest, HttpResponse.BodyHandlers.ofString()); + + assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200); + } + + // Example 3. Use an HttpClient to Connect to first, second, then first endpoint again. + // New connections made each time when pool size is 1, or re-used when not restricted. + // Make sure to set the JVM arg when running the test: + // -Djdk.httpclient.connectionPoolSize=1 + @Test + public final void givenAnHttpClientAndAPoolSizeOfOne_whenTwoConnectionsMadeBackToOriginal_thenFirstConnectionPurged() throws InterruptedException, IOException { + + // given 3 requests, two to the first server and one to the second server + final HttpResponse firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + final HttpResponse secondResponse = client.send(secondGet, HttpResponse.BodyHandlers.ofString()); + final HttpResponse thirdResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + + assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200) && (thirdResponse.statusCode() == 200)); + } + + // Example 4. Use an HttpClient to connect, wait for connection keepalive to pass, then connect again. New connection made for both calls. + // Make sure to set the JVM arg when running the test: + // -Djdk.httpclient.keepalive.timeout=2 + @Test + public final void givenAnHttpClientAndConnectionKeepAliveOfTwoSeconds_whenCallMadeAfterKeepaliveExpires_thenNewConnection() throws InterruptedException, IOException { + + // given 2 requests to the same destination with the second call made after the keepalive timeout has passed + final HttpResponse firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + Thread.sleep(3000); // exceeds 2 seconds configured by JVM arg + final HttpResponse secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString()); + + assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200)); + } + +} + diff --git a/core-java-modules/core-java-httpclient/src/test/resources/jetty-logging.properties b/core-java-modules/core-java-httpclient/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..a21bdbcd09 --- /dev/null +++ b/core-java-modules/core-java-httpclient/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog +org.eclipse.jetty.LEVEL=DEBUG +jetty.logs=logs \ No newline at end of file diff --git a/core-java-modules/core-java-io-4/README.md b/core-java-modules/core-java-io-4/README.md index 263077946d..738cbb5895 100644 --- a/core-java-modules/core-java-io-4/README.md +++ b/core-java-modules/core-java-io-4/README.md @@ -13,5 +13,6 @@ This module contains articles about core Java input and output (IO) - [Generate the MD5 Checksum for a File in Java](https://www.baeldung.com/java-md5-checksum-file) - [Getting the Filename From a String Containing an Absolute File Path](https://www.baeldung.com/java-filename-full-path) - [Mocking Java InputStream Object](https://www.baeldung.com/java-mocking-inputstream) +- [PrintStream vs PrintWriter in Java](https://www.baeldung.com/java-printstream-vs-printwriter) - [[<-- Prev]](/core-java-modules/core-java-io-3) diff --git a/core-java-modules/core-java-io-4/src/main/java/com/baeldung/iostreams/DataStream.java b/core-java-modules/core-java-io-4/src/main/java/com/baeldung/iostreams/DataStream.java new file mode 100644 index 0000000000..71c55d31b9 --- /dev/null +++ b/core-java-modules/core-java-io-4/src/main/java/com/baeldung/iostreams/DataStream.java @@ -0,0 +1,37 @@ +package com.baeldung.iostreams; + +import java.io.*; + +public class DataStream { + public static void textDataProcessingByteStream(String fileName, String content) throws IOException { + PrintStream out = new PrintStream(fileName); + out.print(content); + out.flush(); + } + + public static void textDataProcessingCharStream(String fileName, String content) throws IOException { + PrintWriter out = new PrintWriter(fileName); + out.print(content); + out.flush(); + } + + public static void nonTextDataProcessing(String fileName, String streamOutputFile, String writerOutputFile) throws IOException { + FileInputStream inputStream = new FileInputStream(fileName); + PrintStream printStream = new PrintStream(streamOutputFile); + + int b; + while ((b = inputStream.read()) != -1) { + printStream.write(b); + } + printStream.close(); + + FileReader reader = new FileReader(fileName); + PrintWriter writer = new PrintWriter(writerOutputFile); + + int c; + while ((c = reader.read()) != -1) { + writer.write(c); + } + writer.close(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-4/src/test/java/com/baeldung/iostreams/DataStreamUnitTest.java b/core-java-modules/core-java-io-4/src/test/java/com/baeldung/iostreams/DataStreamUnitTest.java new file mode 100644 index 0000000000..a5a53d5a08 --- /dev/null +++ b/core-java-modules/core-java-io-4/src/test/java/com/baeldung/iostreams/DataStreamUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.iostreams; + +import org.apache.commons.io.FileUtils; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class DataStreamUnitTest { + + private static final String dataProcessingTextFile = "src/test/resources/iostreams/TestFile.txt"; + private static final String dataProcessingImageFile = "src/test/resources/iostreams/image.png"; + private static final String dataProcessingByteStreamFile = "src/test/resources/iostreams/ps.png"; + private static final String dataProcessingCharStreamFile = "src/test/resources/iostreams/pw.png"; + + private static final String textFileContent = "Hello, world!"; + + @Test + public void whenUsingByteStream_thenWriteTextToFile() throws IOException { + DataStream dataStream = new DataStream(); + dataStream.textDataProcessingByteStream(dataProcessingTextFile, textFileContent); + + File file = new File(dataProcessingTextFile); + assertTrue(file.exists()); + assertEquals(textFileContent, FileUtils.readFileToString(file, "utf-8")); + + Files.delete(Paths.get(dataProcessingTextFile)); + } + + @Test + public void whenUsingCharStream_thenWriteTextToFile() throws IOException { + DataStream dataStream = new DataStream(); + dataStream.textDataProcessingCharStream(dataProcessingTextFile, textFileContent); + + File file = new File(dataProcessingTextFile); + assertTrue(file.exists()); + assertEquals(textFileContent, FileUtils.readFileToString(file, "utf-8")); + + Files.delete(Paths.get(dataProcessingTextFile)); + } + + @Test + public void whenUsingStreams_thenWriteNonTextData() throws IOException { + DataStream dataStream = new DataStream(); + dataStream.nonTextDataProcessing(dataProcessingImageFile, dataProcessingByteStreamFile, dataProcessingCharStreamFile); + + File file = new File(dataProcessingImageFile); + File byteStreamOutputFile = new File(dataProcessingByteStreamFile); + File charStreamOutputFile = new File(dataProcessingCharStreamFile); + assertTrue(file.exists()); + assertTrue(byteStreamOutputFile.exists()); + assertTrue(charStreamOutputFile.exists()); + + assertTrue(FileUtils.contentEquals(file, byteStreamOutputFile)); + assertFalse(FileUtils.contentEquals(file, charStreamOutputFile)); + + Files.delete(Paths.get(dataProcessingByteStreamFile)); + Files.delete(Paths.get(dataProcessingCharStreamFile)); + } +} diff --git a/core-java-modules/core-java-io-4/src/test/resources/iostreams/image.png b/core-java-modules/core-java-io-4/src/test/resources/iostreams/image.png new file mode 100644 index 0000000000..6ac7f37ece Binary files /dev/null and b/core-java-modules/core-java-io-4/src/test/resources/iostreams/image.png differ diff --git a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java index 7ca0c91925..77f1e52f08 100644 --- a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java +++ b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java @@ -6,6 +6,7 @@ import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NoInitialContextException; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -20,12 +21,13 @@ public class JndiExceptionsUnitTest { @Test @Order(1) + @Disabled void givenNoContext_whenLookupObject_thenThrowNoInitialContext() { assertThrows(NoInitialContextException.class, () -> { JndiTemplate jndiTemplate = new JndiTemplate(); ctx = (InitialContext) jndiTemplate.getContext(); ctx.lookup("java:comp/env/jdbc/datasource"); - ctx.close(); + ctx.close(); }).printStackTrace(); } diff --git a/core-java-modules/core-java-jvm-2/README.md b/core-java-modules/core-java-jvm-2/README.md index 1313a1ce48..b00618a751 100644 --- a/core-java-modules/core-java-jvm-2/README.md +++ b/core-java-modules/core-java-jvm-2/README.md @@ -14,5 +14,4 @@ This module contains articles about working with the Java Virtual Machine (JVM). - [An Introduction to the Constant Pool in the JVM](https://www.baeldung.com/jvm-constant-pool) - [List All the Classes Loaded in the JVM](https://www.baeldung.com/jvm-list-all-classes-loaded) - [Static Fields and Garbage Collection](https://www.baeldung.com/java-static-fields-gc) -- [Difference Between Class.getResource() and ClassLoader.getResource()](https://www.baeldung.com/java-class-vs-classloader-getresource) -- More articles: [[<-- prev]](/core-java-modules/core-java-jvm) +- More articles: [[<-- prev]](/core-java-modules/core-java-jvm) [[next -->]](/core-java-modules/core-java-jvm-3) diff --git a/core-java-modules/core-java-jvm-3/README.md b/core-java-modules/core-java-jvm-3/README.md new file mode 100644 index 0000000000..0c8a325cf2 --- /dev/null +++ b/core-java-modules/core-java-jvm-3/README.md @@ -0,0 +1,9 @@ +## Core Java JVM Cookbooks and Examples + +This module contains articles about working with the Java Virtual Machine (JVM). + +### Relevant Articles: + +- [Difference Between Class.getResource() and ClassLoader.getResource()](https://www.baeldung.com/java-class-vs-classloader-getresource) +- [Compiling and Executing Code From a String in Java](https://www.baeldung.com/java-string-compile-execute-code) +- More articles: [[<-- prev]](/core-java-modules/core-java-jvm-2) diff --git a/core-java-modules/core-java-jvm-3/pom.xml b/core-java-modules/core-java-jvm-3/pom.xml new file mode 100644 index 0000000000..cb2d8b0b85 --- /dev/null +++ b/core-java-modules/core-java-jvm-3/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + core-java-jvm-3 + 0.1.0-SNAPSHOT + core-java-jvm-3 + 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-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClass.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClass.java new file mode 100644 index 0000000000..c61f28bb79 --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClass.java @@ -0,0 +1,6 @@ +package com.baeldung.inmemorycompilation; + +public interface InMemoryClass { + + void runCode(); +} diff --git a/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClassLoader.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClassLoader.java new file mode 100644 index 0000000000..b4951e9d91 --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryClassLoader.java @@ -0,0 +1,30 @@ +package com.baeldung.inmemorycompilation; + +import static java.util.Objects.requireNonNull; + +import java.util.Map; + +public class InMemoryClassLoader extends ClassLoader { + + private final InMemoryFileManager manager; + + public InMemoryClassLoader(ClassLoader parent, InMemoryFileManager manager) { + super(parent); + this.manager = requireNonNull(manager, "manager must not be null"); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + + Map compiledClasses = manager + .getBytesMap(); + + if (compiledClasses.containsKey(name)) { + byte[] bytes = compiledClasses.get(name) + .getBytes(); + return defineClass(name, bytes, 0, bytes.length); + } else { + throw new ClassNotFoundException(); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryFileManager.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryFileManager.java new file mode 100644 index 0000000000..34ad78856a --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/InMemoryFileManager.java @@ -0,0 +1,52 @@ +package com.baeldung.inmemorycompilation; + +import java.util.Hashtable; +import java.util.Map; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardJavaFileManager; + +public class InMemoryFileManager extends ForwardingJavaFileManager { + + private final Map compiledClasses; + private final ClassLoader loader; + + public InMemoryFileManager(StandardJavaFileManager standardManager) { + super(standardManager); + this.compiledClasses = new Hashtable<>(); + this.loader = new InMemoryClassLoader(this.getClass() + .getClassLoader(), + this + ); + } + + /** + * Used to get the class loader for our compiled class. It creates an anonymous class extending + * the SecureClassLoader which uses the byte code created by the compiler and stored in the + * JavaClassObject, and returns the Class for it + * + * @param location where to place or search for file objects. + */ + @Override + public ClassLoader getClassLoader(Location location) { + return loader; + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, + FileObject sibling) { + + JavaClassAsBytes classAsBytes = new JavaClassAsBytes( + className, kind); + compiledClasses.put(className, classAsBytes); + + return classAsBytes; + } + + public Map getBytesMap() { + return compiledClasses; + } +} diff --git a/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaClassAsBytes.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaClassAsBytes.java new file mode 100644 index 0000000000..b7af9a76ba --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaClassAsBytes.java @@ -0,0 +1,27 @@ +package com.baeldung.inmemorycompilation; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.URI; +import javax.tools.SimpleJavaFileObject; + +/** + * Represents a Java class file (compiled byte-code) + */ +public class JavaClassAsBytes extends SimpleJavaFileObject { + + protected final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + public JavaClassAsBytes(String name, Kind kind) { + super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind); + } + + public byte[] getBytes() { + return bos.toByteArray(); + } + + @Override + public OutputStream openOutputStream() { + return bos; + } +} diff --git a/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaSourceFromString.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaSourceFromString.java new file mode 100644 index 0000000000..eaa6c21b54 --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/inmemorycompilation/JavaSourceFromString.java @@ -0,0 +1,26 @@ +package com.baeldung.inmemorycompilation; + +import static java.util.Objects.requireNonNull; + +import java.net.URI; +import javax.tools.SimpleJavaFileObject; + +/** + * Represents a Java source code file + */ +public class JavaSourceFromString extends SimpleJavaFileObject { + + private final String sourceCode; + + public JavaSourceFromString(String name, String sourceCode) { + super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), + Kind.SOURCE + ); + this.sourceCode = requireNonNull(sourceCode, "sourceCode must not be null"); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return sourceCode; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-jvm-2/src/main/java/com/baeldung/resource/ClassGetResourceExample.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/resource/ClassGetResourceExample.java similarity index 100% rename from core-java-modules/core-java-jvm-2/src/main/java/com/baeldung/resource/ClassGetResourceExample.java rename to core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/resource/ClassGetResourceExample.java diff --git a/core-java-modules/core-java-jvm-2/src/main/java/com/baeldung/resource/ClassLoaderGetResourceExample.java b/core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/resource/ClassLoaderGetResourceExample.java similarity index 100% rename from core-java-modules/core-java-jvm-2/src/main/java/com/baeldung/resource/ClassLoaderGetResourceExample.java rename to core-java-modules/core-java-jvm-3/src/main/java/com/baeldung/resource/ClassLoaderGetResourceExample.java diff --git a/core-java-modules/core-java-jvm-2/src/main/resources/com/baeldung/resource/example.txt b/core-java-modules/core-java-jvm-3/src/resources/com/baeldung/resource/example.txt similarity index 100% rename from core-java-modules/core-java-jvm-2/src/main/resources/com/baeldung/resource/example.txt rename to core-java-modules/core-java-jvm-3/src/resources/com/baeldung/resource/example.txt diff --git a/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/inmemorycompilation/InMemoryCompilationUnitTest.java b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/inmemorycompilation/InMemoryCompilationUnitTest.java new file mode 100644 index 0000000000..f1470879eb --- /dev/null +++ b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/inmemorycompilation/InMemoryCompilationUnitTest.java @@ -0,0 +1,57 @@ +package com.baeldung.inmemorycompilation; + +import java.util.Collections; +import java.util.List; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InMemoryCompilationUnitTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryCompilationUnitTest.class); + + final static String QUALIFIED_CLASS_NAME = "com.baeldung.inmemorycompilation.TestClass"; + + final static String SOURCE_CODE = + "package com.baeldung.inmemorycompilation;\n" + + "public class TestClass implements InMemoryClass {\n" + + "@Override\n" + + " public void runCode() {\n" + + " System.out.println(\"code is running...\");\n" + + " }\n" + + "}\n"; + + @Test + public void whenStringIsCompiled_ThenCodeShouldExecute() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + InMemoryFileManager manager = new InMemoryFileManager(compiler.getStandardFileManager(null, null, null)); + + List sourceFiles = Collections.singletonList(new JavaSourceFromString(QUALIFIED_CLASS_NAME, SOURCE_CODE)); + + JavaCompiler.CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, sourceFiles); + + boolean result = task.call(); + + if (!result) { + diagnostics.getDiagnostics() + .forEach(d -> LOGGER.error(String.valueOf(d))); + } else { + ClassLoader classLoader = manager.getClassLoader(null); + Class clazz = classLoader.loadClass(QUALIFIED_CLASS_NAME); + InMemoryClass instanceOfClass = (InMemoryClass) clazz.newInstance(); + + Assertions.assertInstanceOf(InMemoryClass.class, instanceOfClass); + + instanceOfClass.runCode(); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java similarity index 93% rename from core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java rename to core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java index fb0c88f4bb..2fe512384a 100644 --- a/core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java +++ b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassGetResourceUnitTest.java @@ -1,10 +1,12 @@ package com.baeldung.resource; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.net.URL; +@Disabled class ClassGetResourceUnitTest { @Test diff --git a/core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java similarity index 93% rename from core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java rename to core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java index 54025c5404..d2d0600165 100644 --- a/core-java-modules/core-java-jvm-2/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java +++ b/core-java-modules/core-java-jvm-3/src/test/java/com/baeldung/resource/ClassLoaderGetResourceUnitTest.java @@ -1,10 +1,12 @@ package com.baeldung.resource; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.net.URL; +@Disabled class ClassLoaderGetResourceUnitTest { @Test diff --git a/core-java-modules/core-java-lambdas/README.md b/core-java-modules/core-java-lambdas/README.md index 53414eb14c..cad2097673 100644 --- a/core-java-modules/core-java-lambdas/README.md +++ b/core-java-modules/core-java-lambdas/README.md @@ -8,3 +8,5 @@ - [Method References in Java](https://www.baeldung.com/java-method-references) - [The Double Colon Operator in Java 8](https://www.baeldung.com/java-8-double-colon-operator) - [Serialize a Lambda in Java](https://www.baeldung.com/java-serialize-lambda) +- [Convert Anonymous Class into Lambda in Java](https://www.baeldung.com/java-from-anonymous-class-to-lambda) +- [When to Use Callable and Supplier in Java](https://www.baeldung.com/java-callable-vs-supplier) diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/EmailSenderService.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/EmailSenderService.java new file mode 100644 index 0000000000..f0c41b1cc9 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/EmailSenderService.java @@ -0,0 +1,10 @@ +package com.baeldung.anonymousclass; + +public class EmailSenderService implements SenderService { + + @Override + public String callSender(Sender sender) { + return sender.send("Email Notification"); + } + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/Sender.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/Sender.java new file mode 100644 index 0000000000..9e59960c14 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/Sender.java @@ -0,0 +1,7 @@ +package com.baeldung.anonymousclass; + +public interface Sender { + + String send(final String message); + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SenderService.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SenderService.java new file mode 100644 index 0000000000..cbb0977f89 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SenderService.java @@ -0,0 +1,7 @@ +package com.baeldung.anonymousclass; + +public interface SenderService { + + String callSender(Sender sender); + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SmsSenderService.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SmsSenderService.java new file mode 100644 index 0000000000..9c84664ec4 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/anonymousclass/SmsSenderService.java @@ -0,0 +1,10 @@ +package com.baeldung.anonymousclass; + +public class SmsSenderService implements SenderService { + + @Override + public String callSender(Sender sender) { + return sender.send("SMS Notification"); + } + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/data/User.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/data/User.java new file mode 100644 index 0000000000..488f12a099 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/data/User.java @@ -0,0 +1,59 @@ +package com.baeldung.suppliercallable.data; + +import java.time.LocalDate; + +public class User { + + private String name; + private String surname; + private LocalDate birthDate; + private Integer age; + private Boolean canDriveACar = false; + + public User(String name, String surname, LocalDate birthDate) { + this.name = name; + this.surname = surname; + this.birthDate = birthDate; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public LocalDate getBirthDate() { + return birthDate; + } + + public void setBirthDate(LocalDate birthDate) { + this.birthDate = birthDate; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Integer getAge() { + return age; + } + + public Boolean getCanDriveACar() { + return canDriveACar; + } + + public void setCanDriveACar(Boolean canDriveACar) { + this.canDriveACar = canDriveACar; + } + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/Service.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/Service.java new file mode 100644 index 0000000000..cdae828d8a --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/Service.java @@ -0,0 +1,8 @@ +package com.baeldung.suppliercallable.service; + +import com.baeldung.suppliercallable.data.User; + +public interface Service { + + User execute(User user); +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/AgeCalculatorCallable.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/AgeCalculatorCallable.java new file mode 100644 index 0000000000..f42e4922b6 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/AgeCalculatorCallable.java @@ -0,0 +1,20 @@ +package com.baeldung.suppliercallable.service.callable; + +import java.time.LocalDate; +import java.time.Period; +import java.util.concurrent.Callable; + +public class AgeCalculatorCallable implements Callable { + + private final LocalDate birthDate; + + @Override + public Integer call() throws Exception { + return Period.between(birthDate, LocalDate.now()) + .getYears(); + } + + public AgeCalculatorCallable(LocalDate birthDate) { + this.birthDate = birthDate; + } +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CallableServiceImpl.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CallableServiceImpl.java new file mode 100644 index 0000000000..baf6b5bbd9 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CallableServiceImpl.java @@ -0,0 +1,31 @@ +package com.baeldung.suppliercallable.service.callable; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import com.baeldung.suppliercallable.data.User; +import com.baeldung.suppliercallable.service.Service; + +public class CallableServiceImpl implements Service { + + @Override + public User execute(User user) { + ExecutorService executorService = Executors.newCachedThreadPool(); + + try { + Future ageFuture = executorService.submit(new AgeCalculatorCallable(user.getBirthDate())); + Integer age = ageFuture.get(); + Future canDriveACarFuture = executorService.submit(new CarDriverValidatorCallable(age)); + Boolean canDriveACar = canDriveACarFuture.get(); + user.setAge(age); + user.setCanDriveACar(canDriveACar); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e.getCause()); + } + + return user; + } + +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CarDriverValidatorCallable.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CarDriverValidatorCallable.java new file mode 100644 index 0000000000..e282cdd626 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/callable/CarDriverValidatorCallable.java @@ -0,0 +1,17 @@ +package com.baeldung.suppliercallable.service.callable; + +import java.util.concurrent.Callable; + +public class CarDriverValidatorCallable implements Callable { + + private final Integer age; + + @Override + public Boolean call() throws Exception { + return age > 18; + } + + public CarDriverValidatorCallable(Integer age) { + this.age = age; + } +} diff --git a/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/supplier/SupplierServiceImpl.java b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/supplier/SupplierServiceImpl.java new file mode 100644 index 0000000000..9de0b430eb --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/main/java/com/baeldung/suppliercallable/service/supplier/SupplierServiceImpl.java @@ -0,0 +1,26 @@ +package com.baeldung.suppliercallable.service.supplier; + +import java.time.LocalDate; +import java.time.Period; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.baeldung.suppliercallable.data.User; +import com.baeldung.suppliercallable.service.Service; + +public class SupplierServiceImpl implements Service { + @Override + public User execute(User user) { + ExecutorService executorService = Executors.newCachedThreadPool(); + CompletableFuture ageFut = CompletableFuture.supplyAsync(() -> Period.between(user.getBirthDate(), LocalDate.now()) + .getYears(), executorService) + .exceptionally((throwable -> null)); + CompletableFuture canDriveACarFut = ageFut.thenComposeAsync(age -> CompletableFuture.supplyAsync(() -> age > 18, executorService)) + .exceptionally((ex) -> false); + user.setAge(ageFut.join()); + user.setCanDriveACar(canDriveACarFut.join()); + return user; + } + +} diff --git a/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/anonymousclass/AnonymousClassToLambdaIntegrationTest.java b/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/anonymousclass/AnonymousClassToLambdaIntegrationTest.java new file mode 100644 index 0000000000..b329e003f4 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/anonymousclass/AnonymousClassToLambdaIntegrationTest.java @@ -0,0 +1,34 @@ +package com.baeldung.anonymousclass; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class AnonymousClassToLambdaIntegrationTest { + + @Test + public void whenPassingAnonymousClass_thenSuccess() { + final SenderService emailSenderService = new EmailSenderService(); + + final String emailNotif = emailSenderService.callSender(new Sender() { + @Override + public String send(String message) { + return message; + } + }); + + assertEquals(emailNotif, "Email Notification"); + } + + @Test + public void whenPassingLambdaExpression_thenSuccess() { + final SenderService smsSenderService = new SmsSenderService(); + + final String smsNotif = smsSenderService.callSender((String message) -> { + return message; + }); + + assertEquals(smsNotif, "SMS Notification"); + } + +} diff --git a/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/suppliercallable/CallableSupplierUnitTest.java b/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/suppliercallable/CallableSupplierUnitTest.java new file mode 100644 index 0000000000..c9be58c675 --- /dev/null +++ b/core-java-modules/core-java-lambdas/src/test/java/com/baeldung/suppliercallable/CallableSupplierUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.suppliercallable; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.time.LocalDate; +import java.time.Month; +import org.junit.jupiter.api.Test; +import com.baeldung.suppliercallable.data.User; +import com.baeldung.suppliercallable.service.Service; +import com.baeldung.suppliercallable.service.callable.CallableServiceImpl; +import com.baeldung.suppliercallable.service.supplier.SupplierServiceImpl; + +public class CallableSupplierUnitTest { + + @Test + void givenCallableService_whenUserIsAnAdult_thenCanDriveACar() { + User user = new User("Test", "Test", LocalDate.of(2000, Month.JANUARY, 19)); + Service service = new CallableServiceImpl(); + service.execute(user); + assertEquals(true, user.getCanDriveACar()); + } + + @Test + void givenCallableService_whenUserIsNotAnAdult_thenCannotDriveACar() { + User user = new User("Test", "Test", LocalDate.of(2010, Month.JANUARY, 19)); + Service service = new CallableServiceImpl(); + service.execute(user); + assertEquals(false, user.getCanDriveACar()); + } + + @Test + void givenCallableService_whenBirthDateIsNull_thenShouldThrowAnException() { + User user = new User("Test", "Test", null); + Service service = new CallableServiceImpl(); + assertThrows(RuntimeException.class, () -> service.execute(user)); + } + + @Test + void givenSupplierService_whenUserIsAnAdult_thenCanDriveACar() { + User user = new User("Test", "Test", LocalDate.of(2000, Month.JANUARY, 19)); + Service service = new SupplierServiceImpl(); + service.execute(user); + assertEquals(true, user.getCanDriveACar()); + } + + @Test + void givenSupplierService_whenUserIsNotAnAdult_thenCannotDriveACar() { + User user = new User("Test", "Test", LocalDate.of(2010, Month.JANUARY, 19)); + Service service = new SupplierServiceImpl(); + service.execute(user); + assertEquals(false, user.getCanDriveACar()); + } + + @Test + void givenSupplierService_whenBirthDateIsNull_thenCannotDriveACarAndAgeIsNull() { + User user = new User("Test", "Test", null); + Service service = new SupplierServiceImpl(); + service.execute(user); + assertEquals(false, user.getCanDriveACar()); + assertNull(user.getBirthDate()); + } + +} diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/transientkw/Book.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/transientkw/Book.java index 5822d83841..790747ec69 100644 --- a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/transientkw/Book.java +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/transientkw/Book.java @@ -11,6 +11,8 @@ public class Book implements Serializable { private transient int copies; private final transient String bookCategory = "Fiction"; + private final transient String bookCategoryNewOperator = new String("Fiction with new Operator"); + public String getBookName() { return bookName; } @@ -39,4 +41,7 @@ public class Book implements Serializable { return bookCategory; } + public String getBookCategoryNewOperator() { + return bookCategoryNewOperator; + } } diff --git a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/transientkw/TransientUnitTest.java b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/transientkw/TransientUnitTest.java index a3ea77ec86..6c68896651 100644 --- a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/transientkw/TransientUnitTest.java +++ b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/transientkw/TransientUnitTest.java @@ -34,7 +34,17 @@ class TransientUnitTest { assertEquals("Fiction", book2.getBookCategory()); } - + + @Test + void givenFinalTransientWithNewOperator_whenSerDe_thenValuePersisted() throws Exception { + Book book = new Book(); + + BookSerDe.serialize(book); + Book book2 = BookSerDe.deserialize(); + + assertNull(book2.getBookCategoryNewOperator()); + } + @AfterAll public static void cleanup() { File file = new File(BookSerDe.fileName); diff --git a/core-java-modules/core-java-lang-5/README.md b/core-java-modules/core-java-lang-5/README.md index f1408abe96..5ff3e83d2c 100644 --- a/core-java-modules/core-java-lang-5/README.md +++ b/core-java-modules/core-java-lang-5/README.md @@ -10,3 +10,8 @@ This module contains articles about core features in the Java language - [Handle Classes With the Same Name in Java](https://www.baeldung.com/java-classes-same-name) - [Variable Instantiation on Declaration vs. on Constructor in Java](https://www.baeldung.com/java-variable-instantiation-declaration-vs-constructor) - [Infinity in Java](https://www.baeldung.com/java-infinity) +- [Type Parameter vs Wildcard in Java Generics](https://www.baeldung.com/java-generics-type-parameter-vs-wildcard) +- [Convert Between int and char in Java](https://www.baeldung.com/java-convert-int-char) +- [Converting a Number from One Base to Another in Java](https://www.baeldung.com/java-converting-a-number-from-one-base-to-another) +- [Check if Command-Line Arguments Are Null in Java](https://www.baeldung.com/java-check-command-line-args) +- [Determine if a Class Implements an Interface in Java](https://www.baeldung.com/java-check-class-implements-interface) diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithErrorHandling.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithErrorHandling.java new file mode 100644 index 0000000000..e80a2b46d9 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithErrorHandling.java @@ -0,0 +1,12 @@ +package com.baeldung.commandline; + +public class CommandLineWithErrorHandling { + + public static void main(String[] args) { + if (args.length > 0) { + System.out.println(args[0]); + } else { + System.out.println("No command line arguments were provided."); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithoutErrorHandling.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithoutErrorHandling.java new file mode 100644 index 0000000000..d761969bfd --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/commandline/CommandLineWithoutErrorHandling.java @@ -0,0 +1,9 @@ +package com.baeldung.commandline; + +public class CommandLineWithoutErrorHandling { + + public static void main(String[] args) { + + System.out.println(args[0]); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/convertnumberbases/ConvertNumberBases.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/convertnumberbases/ConvertNumberBases.java new file mode 100644 index 0000000000..09b880cd19 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/convertnumberbases/ConvertNumberBases.java @@ -0,0 +1,77 @@ +package com.baeldung.convertnumberbases; + +public class ConvertNumberBases { + + public static String convertNumberToNewBase(String number, int base, int newBase) { + return Integer.toString(Integer.parseInt(number, base), newBase); + } + + public static String convertNumberToNewBaseCustom(String num, int base, int newBase) { + int decimalNumber = convertFromAnyBaseToDecimal(num, base); + String targetBase = ""; + try { + targetBase = convertFromDecimalToBaseX(decimalNumber, newBase); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + return targetBase; + } + + public static String convertFromDecimalToBaseX(int num, int newBase) throws IllegalArgumentException { + if ((newBase < 2 || newBase > 10) && newBase != 16) { + throw new IllegalArgumentException("New base must be from 2 - 10 or 16"); + } + + String result = ""; + int remainder; + while (num > 0) { + remainder = num % newBase; + if (newBase == 16) { + if (remainder == 10) { + result += 'A'; + } else if (remainder == 11) { + result += 'B'; + } else if (remainder == 12) { + result += 'C'; + } else if (remainder == 13) { + result += 'D'; + } else if (remainder == 14) { + result += 'E'; + } else if (remainder == 15) { + result += 'F'; + } else { + result += remainder; + } + } else { + result += remainder; + } + num /= newBase; + } + return new StringBuffer(result).reverse().toString(); + } + + public static int convertFromAnyBaseToDecimal(String num, int base) { + if (base < 2 || (base > 10 && base != 16)) { + return -1; + } + int val = 0; + int power = 1; + for (int i = num.length() - 1; i >= 0; i--) { + int digit = charToDecimal(num.charAt(i)); + if (digit < 0 || digit >= base) { + return -1; + } + val += digit * power; + power = power * base; + } + return val; + } + + public static int charToDecimal(char c) { + if (c >= '0' && c <= '9') { + return (int) c - '0'; + } else { + return (int) c - 'A' + 10; + } + } +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolDeepCopy.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolDeepCopy.java new file mode 100644 index 0000000000..eda88488f9 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolDeepCopy.java @@ -0,0 +1,20 @@ +package com.baeldung.deepshallowcopy; + +public class SchoolDeepCopy implements Cloneable{ + public String name; + public SchoolDeepCopy(String name){ + this.name = name; + } + + protected Object clone() throws CloneNotSupportedException{ + return super.clone(); + } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolShallowCopy.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolShallowCopy.java new file mode 100644 index 0000000000..75258c1505 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/SchoolShallowCopy.java @@ -0,0 +1,16 @@ +package com.baeldung.deepshallowcopy; + +public class SchoolShallowCopy { + public String name; + public SchoolShallowCopy(String name){ + this.name = name; + } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentDeepCopy.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentDeepCopy.java new file mode 100644 index 0000000000..293363b557 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentDeepCopy.java @@ -0,0 +1,55 @@ +package com.baeldung.deepshallowcopy; + +public class StudentDeepCopy implements Cloneable{ + public String firstName; + public String lastName; + public String level; + public SchoolDeepCopy school; + + + public StudentDeepCopy(String firstName, String lastName, String level, SchoolDeepCopy school){ + this.firstName = firstName; + this.lastName = lastName; + this.level = level; + this.school = school; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public SchoolDeepCopy getSchool() { + return school; + } + + public void setSchool(SchoolDeepCopy school) { + this.school = school; + } + @Override + protected Object clone() throws CloneNotSupportedException { + StudentDeepCopy student = (StudentDeepCopy) super.clone(); + student.school = (SchoolDeepCopy) school.clone(); + return student; + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentShallowCopy.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentShallowCopy.java new file mode 100644 index 0000000000..cdb2c4be86 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/deepshallowcopy/StudentShallowCopy.java @@ -0,0 +1,53 @@ +package com.baeldung.deepshallowcopy; + +public class StudentShallowCopy implements Cloneable{ + public String firstName; + public String lastName; + public String level; + public SchoolShallowCopy school; + + + public StudentShallowCopy(String firstName, String lastName, String level, SchoolShallowCopy school){ + this.firstName = firstName; + this.lastName = lastName; + this.level = level; + this.school = school; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public SchoolShallowCopy getSchool() { + return school; + } + + public void setSchool(SchoolShallowCopy school) { + this.school = school; + } + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Animal.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Animal.java new file mode 100644 index 0000000000..fd247a4eff --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Animal.java @@ -0,0 +1,22 @@ +package com.baeldung.generics; + +abstract class Animal { + + protected final String type; + protected final String name; + + protected Animal(String type, String name) { + this.type = type; + this.name = name; + } + + abstract String makeSound(); + + public String getType() { + return type; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/AnimalDemo.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/AnimalDemo.java new file mode 100644 index 0000000000..3d33180fa3 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/AnimalDemo.java @@ -0,0 +1,26 @@ +package com.baeldung.generics; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class AnimalDemo { + + private static final Logger logger = LoggerFactory.getLogger(AnimalDemo.class); + + public static void main(String[] args) { + List cats = new ArrayList<>(); + cats.add(new Cat("Persian", "Bono")); + cats.add(new Cat("Egyptian", "Lulu")); + cats.add(new Cat("Siamese", "Ra")); + + order(cats); + logger.info("Ordered cats: {}", cats); + } + + public static > void order(List list) { + list.sort(Comparable::compareTo); + } +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Cat.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Cat.java new file mode 100644 index 0000000000..bb6f9ba8f0 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Cat.java @@ -0,0 +1,41 @@ +package com.baeldung.generics; + +import java.util.Objects; + +class Cat extends Animal implements Comparable { + public Cat(String type, String name) { + super(type, name); + } + + @Override + public String makeSound() { + return "Meow"; + } + + /** + * Warning: Inconsistent with the equals method. + */ + @Override + public int compareTo(Cat cat) { + return this.getName().length() - cat.getName().length(); + } + + @Override + public String toString() { + return "Cat{" + "type='" + type + '\'' + ", name='" + name + '\'' + '}'; + } + + @Override + public int hashCode() { + return Objects.hash(type, name); + } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof Cat)) return false; + Cat cat = (Cat) o; + return type.equals(cat.type) && name.equals(cat.name); + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtils.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtils.java new file mode 100644 index 0000000000..6d84f5199b --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtils.java @@ -0,0 +1,56 @@ +package com.baeldung.generics; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CollectionUtils { + + private CollectionUtils() { + } + + public static void print(T item) { + System.out.println(item); + } + + public static void swap(List list, int src, int des) { + swapHelper(list, src, des); + } + + private static void swapHelper(List list, int src, int des) { + list.set(src, list.set(des, list.get(src))); + } + + public static List mergeTypeParameter(List listOne, List listTwo) { + return Stream.concat(listOne.stream(), listTwo.stream()) + .collect(Collectors.toList()); + } + + public static List mergeWildcard(List listOne, List listTwo) { + return Stream.concat(listOne.stream(), listTwo.stream()) + .collect(Collectors.toList()); + } + + public static long sum(List numbers) { + return numbers.stream() + .mapToLong(Number::longValue) + .sum(); + } + + public static long sumTypeParameter(List numbers) { + return numbers.stream() + .mapToLong(Number::longValue) + .sum(); + } + + public static long sumWildcard(List numbers) { + return numbers.stream() + .mapToLong(Number::longValue) + .sum(); + } + + public static void addNumber(List list, Integer number) { + list.add(number); + } + +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtilsDemo.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtilsDemo.java new file mode 100644 index 0000000000..012d9a3110 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/CollectionUtilsDemo.java @@ -0,0 +1,48 @@ +package com.baeldung.generics; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class CollectionUtilsDemo { + + private static final Logger logger = LoggerFactory.getLogger(CollectionUtilsDemo.class); + + public static void main(String[] args) { + CollectionUtils.print("Baeldung"); + + List numbers1 = new ArrayList<>(); + numbers1.add(5); + numbers1.add(10L); + + List numbers2 = new ArrayList<>(); + numbers2.add(15f); + numbers2.add(20.0); + + List numbersMerged = CollectionUtils.mergeTypeParameter(numbers1, numbers2); + logger.info("Merged numbers: {}", numbersMerged); + + List numbers = new ArrayList<>(); + numbers.add(5); + numbers.add(10L); + numbers.add(15f); + numbers.add(20.0); + + logger.info("Sum: {}", CollectionUtils.sum(numbers)); + logger.info("Sum (wildcard): {}", CollectionUtils.sumWildcard(numbers)); + logger.info("Sum (type parameter): {}", CollectionUtils.sumTypeParameter(numbers)); + + List integers = new ArrayList<>(); + integers.add(5); + logger.info("Sum integers (wildcard): {}", CollectionUtils.sumWildcard(integers)); + + CollectionUtils.addNumber(numbers, 4); + CollectionUtils.addNumber(integers, 5); + + logger.info("Before swap: {}", numbers); + CollectionUtils.swap(numbers, 0, 1); + logger.info("After swap: {}", numbers); + } +} diff --git a/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Dog.java b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Dog.java new file mode 100644 index 0000000000..cec6f39422 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/main/java/com/baeldung/generics/Dog.java @@ -0,0 +1,14 @@ +package com.baeldung.generics; + +public class Dog extends Animal { + + public Dog(String type, String name) { + super(type, name); + } + + @Override + public String makeSound() { + return "Wuf"; + } + +} diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/commandline/CommandLineWithoutErrorHandlingUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/commandline/CommandLineWithoutErrorHandlingUnitTest.java new file mode 100644 index 0000000000..197818631b --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/commandline/CommandLineWithoutErrorHandlingUnitTest.java @@ -0,0 +1,12 @@ +package com.baeldung.commandline; + +import org.junit.Test; +import static org.junit.Assert.fail; + +public class CommandLineWithoutErrorHandlingUnitTest { + + @Test(expected = NullPointerException.class) + public void givenNullCommandLineArgument_whenPassedToMainFunction_thenExpectNullPointerException() { + CommandLineWithoutErrorHandling.main(null); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertCharToIntUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertCharToIntUnitTest.java new file mode 100644 index 0000000000..75826cd7be --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertCharToIntUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.convertinttochar; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class ConvertCharToIntUnitTest { + + @Test + public void givenAChar_whenUsingGetNumericValue_thenExpectedNumericType() { + //char value + char c = '7'; + // using getNumericValue + int n = Character.getNumericValue(c); + + assertEquals(7, n); + } + + @Test + public void givenAChar_whenSubtracting0_thenExpectedNumericType() { + //char value + char c = '7'; + // subtract '0' from the char + int n = c - '0'; + + assertEquals(7, n); + } + + @Test + public void givenAChar_whenUsingParseInt_thenExpectedNumericType() { + //char value + char c = '7'; + // using parseInt + int n = Integer.parseInt(String.valueOf(c)); + + assertEquals(7, n); + } + + @Test + public void givenAChar_whenCastingFromCharToInt_thenExpectedUnicodeRepresentation() { + //char value + char c = '7'; + //cast to int + assertEquals(55, (int) c); + } + +} diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertIntToCharUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertIntToCharUnitTest.java new file mode 100644 index 0000000000..276bcbc55b --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertinttochar/ConvertIntToCharUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.convertinttochar; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class ConvertIntToCharUnitTest { + + @Test + public void givenAnInt_whenAdding0_thenExpectedCharType() { + int num = 7; + //add '0' to convert int to char + char c = (char) ('0' + num); + + assertEquals('7', c); + } + + @Test + public void givenAnInt_whenUsingForDigit_thenExpectedCharType() { + int num = 7; + // Convert using forDigit() method + char c = Character.forDigit(num, 10); + + assertEquals('7', c); + } + + @Test + public void givenAnInt_whenUsingToString_thenExpectedCharType() { + int num = 7; + //convert int to char using toString() + char c = Integer.toString(num) + .charAt(0); + + assertEquals('7', c); + } +} diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertnumberbases/ConvertNumberBasesUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertnumberbases/ConvertNumberBasesUnitTest.java new file mode 100644 index 0000000000..a666346b1a --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/convertnumberbases/ConvertNumberBasesUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.convertnumberbases; + +import static com.baeldung.convertnumberbases.ConvertNumberBases.convertFromDecimalToBaseX; +import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBase; +import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBaseCustom; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class ConvertNumberBasesUnitTest { + + @Test + void whenConvertingBase10NumberToBase5_ThenResultShouldBeDigitsInBase5() { + assertEquals(convertNumberToNewBase("89", 10, 5), "324"); + } + @Test + void whenConvertingBase2NumberToBase8_ThenResultShouldBeDigitsInBase8() { + assertEquals(convertNumberToNewBaseCustom("11001000", 2, 8), "310"); + } + + @Test + void whenInputIsOutOfRange_thenIllegalArgumentExceptionIsThrown() { + Exception exception = assertThrows(IllegalArgumentException.class, ()-> { + convertFromDecimalToBaseX(100, 12); + }); + String expectedMessage = "New base must be from 2 - 10 or 16"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentDeepCopyUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentDeepCopyUnitTest.java new file mode 100644 index 0000000000..ce40898821 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentDeepCopyUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.deepshallowcopy; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class StudentDeepCopyUnitTest { + + + @Test + void whenDeepCopying_thenCopyObjectMakesCopyOfReferencedObjectInSourceObject(){ + SchoolDeepCopy ug = new SchoolDeepCopy("University of Ghana"); + StudentDeepCopy studentOne = new StudentDeepCopy("Abena", "Kojo","200L", ug ); + StudentDeepCopy studentTwo = null; + + try{ + studentTwo = (StudentDeepCopy) studentOne.clone(); + } catch (CloneNotSupportedException e){ + e.printStackTrace(); + } + + assertNotSame(studentOne.getSchool(),studentTwo.getSchool()); + studentTwo.getSchool().setName("University of Nigeria"); + assertNotEquals(studentOne.getSchool().getName(), studentTwo.getSchool().getName()); + + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentShallowCopyUnitTest.java b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentShallowCopyUnitTest.java new file mode 100644 index 0000000000..6c8c9d4992 --- /dev/null +++ b/core-java-modules/core-java-lang-5/src/test/java/com/baeldung/deepshallowcopy/StudentShallowCopyUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.deepshallowcopy; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class StudentShallowCopyUnitTest { + + @Test + void whenShallowCopying_thenCopyObjectAndSourceObjectShareSameReferencedObject(){ + SchoolShallowCopy ug = new SchoolShallowCopy("University of Ghana"); + StudentShallowCopy studentOne = new StudentShallowCopy("Abena", "Kojo","200L", ug ); + StudentShallowCopy studentTwo = null; + + try{ + studentTwo = (StudentShallowCopy) studentOne.clone(); + } catch (CloneNotSupportedException e){ + e.printStackTrace(); + } + + assertSame(studentOne.getSchool(),studentTwo.getSchool()); + studentTwo.getSchool().setName("University of Nigeria"); + assertEquals(studentOne.getSchool().getName(), studentTwo.getSchool().getName()); + } + +} \ No newline at end of file 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 180cd48830..89adc23100 100644 --- a/core-java-modules/core-java-lang-math-3/README.md +++ b/core-java-modules/core-java-lang-math-3/README.md @@ -9,4 +9,5 @@ - [Java Program to Find the Roots of a Quadratic Equation](https://www.baeldung.com/roots-quadratic-equation) - [Create a BMI Calculator in Java](https://www.baeldung.com/java-body-mass-index-calculator) - [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) - 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/math/pascaltriangle/PascalTriangle.java b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/math/pascaltriangle/PascalTriangle.java new file mode 100644 index 0000000000..ae47a48375 --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/math/pascaltriangle/PascalTriangle.java @@ -0,0 +1,48 @@ +package com.baeldung.math.pascaltriangle; + +public class PascalTriangle { + + public static int factorial(int i) { + if (i == 0) { + return 1; + } + return i * factorial(i - 1); + } + + private static void printUseRecursion(int n) { + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n - i; j++) { + System.out.print(" "); + } + + for (int k = 0; k <= i; k++) { + System.out.print(" " + factorial(i) / (factorial(i - k) * factorial(k))); + } + + System.out.println(); + } + } + +public static void printUseBinomialExpansion(int n) { + for (int line = 1; line <= n; line++) { + for (int j = 0; j <= n - line; j++) { + System.out.print(" "); + } + + int k = 1; + for (int i = 1; i <= line; i++) { + System.out.print(k + " "); + k = k * (line - i) / i; + } + + System.out.println(); + } +} + + public static void main(String[] args) { + int n = 5; + printUseRecursion(n); +// printUseBinomialExpansion(n); + } + +} diff --git a/core-java-modules/core-java-lang-oop-constructors/README.md b/core-java-modules/core-java-lang-oop-constructors/README.md index a552a79721..2f414c6bf5 100644 --- a/core-java-modules/core-java-lang-oop-constructors/README.md +++ b/core-java-modules/core-java-lang-oop-constructors/README.md @@ -12,3 +12,4 @@ This module contains article about constructors in Java - [Java Implicit Super Constructor is Undefined Error](https://www.baeldung.com/java-implicit-super-constructor-is-undefined-error) - [Constructor Specification in Java](https://www.baeldung.com/java-constructor-specification) - [Static vs. Instance Initializer Block in Java](https://www.baeldung.com/java-static-instance-initializer-blocks) +- [Accessing Private Constructor in Java](https://www.baeldung.com/java-private-constructor-access) diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/ClonableRabbit.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/ClonableRabbit.java new file mode 100644 index 0000000000..0d97e010fb --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/ClonableRabbit.java @@ -0,0 +1,18 @@ +package com.baeldung.objectcreation.objects; + +public class ClonableRabbit implements Cloneable { + + String name = ""; + + public ClonableRabbit(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/Rabbit.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/Rabbit.java new file mode 100644 index 0000000000..c8a8159544 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/Rabbit.java @@ -0,0 +1,17 @@ +package com.baeldung.objectcreation.objects; + +public class Rabbit { + + String name = ""; + + public Rabbit() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/RabbitType.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/RabbitType.java new file mode 100644 index 0000000000..b7afe5fe2f --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/RabbitType.java @@ -0,0 +1,7 @@ +package com.baeldung.objectcreation.objects; + +public enum RabbitType { + PET, + TAME, + WILD +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/SerializableRabbit.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/SerializableRabbit.java new file mode 100644 index 0000000000..cb5f2d0b71 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/objects/SerializableRabbit.java @@ -0,0 +1,21 @@ +package com.baeldung.objectcreation.objects; + +import java.io.Serializable; + +public class SerializableRabbit implements Serializable { + + private static final long serialVersionUID = 2589844379773087465L; + + String name = ""; + + public SerializableRabbit() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/utils/CreateRabbits.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/utils/CreateRabbits.java new file mode 100644 index 0000000000..8b3c84e89c --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/objectcreation/utils/CreateRabbits.java @@ -0,0 +1,71 @@ +package com.baeldung.objectcreation.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.function.Supplier; + +import com.baeldung.objectcreation.objects.ClonableRabbit; +import com.baeldung.objectcreation.objects.Rabbit; +import com.baeldung.objectcreation.objects.RabbitType; +import com.baeldung.objectcreation.objects.SerializableRabbit; + +public final class CreateRabbits { + + public static Rabbit createRabbitUsingNewOperator() { + Rabbit rabbit = new Rabbit(); + + return rabbit; + } + + public static Rabbit createRabbitUsingClassForName() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + Rabbit rabbit = (Rabbit) Class.forName("com.baeldung.objectcreation.objects.Rabbit").newInstance(); + + return rabbit; + } + + public static Rabbit createRabbitUsingClassNewInstance() throws InstantiationException, IllegalAccessException { + Rabbit rabbit = Rabbit.class.newInstance(); + + return rabbit; + } + + public static Rabbit createRabbitUsingConstructorNewInstance() throws InstantiationException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException, NoSuchMethodException, SecurityException { + Rabbit rabbit = Rabbit.class.getConstructor().newInstance(); + + return rabbit; + } + + public static ClonableRabbit createRabbitUsingClone(ClonableRabbit originalRabbit) throws CloneNotSupportedException { + ClonableRabbit clonedRabbit = (ClonableRabbit) originalRabbit.clone(); + + return clonedRabbit; + } + + public static SerializableRabbit createRabbitUsingDeserialization(File file) throws IOException, ClassNotFoundException { + try (FileInputStream fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis);) { + return (SerializableRabbit) ois.readObject(); + } + } + + public static Rabbit createRabbitUsingSupplier() { + Supplier rabbitSupplier = Rabbit::new; + Rabbit rabbit = rabbitSupplier.get(); + + return rabbit; + } + + public static Rabbit[] createRabbitArray() { + Rabbit[] rabbitArray = new Rabbit[10]; + + return rabbitArray; + } + + public static RabbitType createRabbitTypeEnum() { + return RabbitType.PET; //any RabbitType could be returned here, PET is just an example. + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java new file mode 100644 index 0000000000..24e7d435c7 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java @@ -0,0 +1,8 @@ +package com.baeldung.reflection; + +public class PrivateConstructorClass { + + private PrivateConstructorClass() { + System.out.println("Used the private constructor!"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/objectcreation/CreateRabbitsUnitTest.java b/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/objectcreation/CreateRabbitsUnitTest.java new file mode 100644 index 0000000000..653beba096 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/objectcreation/CreateRabbitsUnitTest.java @@ -0,0 +1,100 @@ +package com.baeldung.objectcreation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationTargetException; + +import org.junit.Test; + +import com.baeldung.objectcreation.objects.ClonableRabbit; +import com.baeldung.objectcreation.objects.Rabbit; +import com.baeldung.objectcreation.objects.RabbitType; +import com.baeldung.objectcreation.objects.SerializableRabbit; +import com.baeldung.objectcreation.utils.CreateRabbits; + +public class CreateRabbitsUnitTest { + + @Test + public void whenUsingNewOperator_thenRabbitIsReturned() { + assertTrue(CreateRabbits.createRabbitUsingNewOperator() instanceof Rabbit); + } + + @Test + public void whenUsingClassForName_thenRabbitIsReturned() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + assertTrue(CreateRabbits.createRabbitUsingClassForName() instanceof Rabbit); + } + + @Test + public void whenUsingClassNewInstance_thenRabbitIsReturned() throws InstantiationException, IllegalAccessException { + assertTrue(CreateRabbits.createRabbitUsingClassNewInstance() instanceof Rabbit); + } + + @Test + public void whenUsingConstructorNewInstance_thenRabbitIsReturned() throws InstantiationException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException, NoSuchMethodException, SecurityException { + assertTrue(CreateRabbits.createRabbitUsingConstructorNewInstance() instanceof Rabbit); + } + + @Test + public void givenClonableRabbit_whenUsingCloneMethod_thenClonedRabbitIsReturned() throws CloneNotSupportedException { + //given + ClonableRabbit originalRabbit = new ClonableRabbit("Peter"); + + //when + ClonableRabbit clonedRabbit = CreateRabbits.createRabbitUsingClone(originalRabbit); + + //then + assertTrue(clonedRabbit instanceof ClonableRabbit); + assertNotEquals(originalRabbit, clonedRabbit); + assertEquals("Peter", clonedRabbit.getName()); + } + + @Test + public void givenSerializedRabbit_whenDeserializing_thenNewRabbitIsReturned() throws IOException, ClassNotFoundException { + //given + SerializableRabbit originalRabbit = new SerializableRabbit(); + originalRabbit.setName("Peter"); + + File resourcesFolder = new File("src/test/resources"); + resourcesFolder.mkdirs(); //creates the directory in case it doesn't exist + + File file = new File(resourcesFolder, "rabbit.ser"); + + try (FileOutputStream fileOutputStream = new FileOutputStream(file); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);) { + objectOutputStream.writeObject(originalRabbit); + } + + //when + SerializableRabbit newRabbit = CreateRabbits.createRabbitUsingDeserialization(file); + + //then + assertTrue(newRabbit instanceof SerializableRabbit); + assertNotEquals(originalRabbit, newRabbit); + assertEquals("Peter", newRabbit.getName()); + + //clean up + file.delete(); + } + + @Test + public void whenUsingSupplier_thenRabbitIsReturned() { + assertTrue(CreateRabbits.createRabbitUsingSupplier() instanceof Rabbit); + } + + @Test + public void whenUsingArrays_thenRabbitArrayIsReturned() { + assertTrue(CreateRabbits.createRabbitArray() instanceof Rabbit[]); + } + + @Test + public void whenUsingEnums_thenRabbitTypeIsReturned() { + assertTrue(CreateRabbits.createRabbitTypeEnum() instanceof RabbitType); + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java b/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java new file mode 100644 index 0000000000..cd1f48d720 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.reflection; + +import java.lang.reflect.Constructor; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PrivateConstructorUnitTest { + + @Test + public void whenConstructorIsPrivate_thenInstanceSuccess() throws Exception { + Constructor pcc = PrivateConstructorClass.class.getDeclaredConstructor(); + pcc.setAccessible(true); + PrivateConstructorClass privateConstructorInstance = pcc.newInstance(); + Assertions.assertTrue(privateConstructorInstance instanceof PrivateConstructorClass); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Car.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Car.java index 6ec6507e59..92dbec07e7 100644 --- a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Car.java +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Car.java @@ -22,4 +22,9 @@ public class Car implements Vehicle { public String slowDown() { return "The car is slowing down."; } + + @Override + public double getSpeed() { + return 0; + } } \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Motorbike.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Motorbike.java index b1de93059a..c3e17f63d5 100644 --- a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Motorbike.java +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Motorbike.java @@ -22,4 +22,9 @@ public class Motorbike implements Vehicle { public String slowDown() { return "The motorbike is slowing down."; } + + @Override + public double getSpeed() { + return 0; + } } \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/MultiAlarmCar.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/MultiAlarmCar.java index abf329fafd..85398ec488 100644 --- a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/MultiAlarmCar.java +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/MultiAlarmCar.java @@ -32,4 +32,9 @@ public class MultiAlarmCar implements Vehicle, Alarm { public String turnAlarmOff() { return Vehicle.super.turnAlarmOff() + " " + Alarm.super.turnAlarmOff(); } + + @Override + public double getSpeed() { + return 0; + } } \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Vehicle.java b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Vehicle.java index b0bdd63c2c..c91d76345d 100644 --- a/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Vehicle.java +++ b/core-java-modules/core-java-lang-oop-modifiers/src/main/java/com/baeldung/defaultstaticinterfacemethods/model/Vehicle.java @@ -19,4 +19,10 @@ public interface Vehicle { static int getHorsePower(int rpm, int torque) { return (rpm * torque) / 5252; } + + double getSpeed(); + + default double getSpeedInKMH(double speed) { + return speed * 1.60934; + } } \ No newline at end of file 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 d3909c0014..b482669508 100644 --- a/core-java-modules/core-java-lang-oop-others/README.md +++ b/core-java-modules/core-java-lang-oop-others/README.md @@ -6,3 +6,4 @@ This module contains articles about Object Oriented Programming (OOP) in Java - [Object-Oriented-Programming Concepts in Java](https://www.baeldung.com/java-oop) - [Static and Dynamic Binding in Java](https://www.baeldung.com/java-static-dynamic-binding) - [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) diff --git a/core-java-modules/core-java-lang-oop-others/pom.xml b/core-java-modules/core-java-lang-oop-others/pom.xml index d9d147f34a..dea92067f2 100644 --- a/core-java-modules/core-java-lang-oop-others/pom.xml +++ b/core-java-modules/core-java-lang-oop-others/pom.xml @@ -13,4 +13,12 @@ 0.0.1-SNAPSHOT + + + org.apache.commons + commons-lang3 + 3.12.0 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/Car.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/Car.java new file mode 100644 index 0000000000..975006d8df --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/Car.java @@ -0,0 +1,30 @@ +package com.baeldung.nullchecking; + +import java.util.Objects; +import java.util.stream.Stream; + +public class Car { + + Integer power; + + Integer year; + + public boolean allNull() { + + if (power != null) { + return false; + } + + if (year != null) { + return false; + } + + return true; + } + + public boolean allNullV2() { + + return Stream.of(power, year) + .allMatch(Objects::isNull); + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/NullChecker.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/NullChecker.java new file mode 100644 index 0000000000..5630577cdf --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/nullchecking/NullChecker.java @@ -0,0 +1,25 @@ +package com.baeldung.nullchecking; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Objects; + +public class NullChecker { + + public static boolean allNull(Object target) { + + return Arrays.stream(target.getClass() + .getDeclaredFields()) + .peek(f -> f.setAccessible(true)) + .map(f -> getFieldValue(f, target)) + .allMatch(Objects::isNull); + } + + private static Object getFieldValue(Field field, Object target) { + try { + return field.get(target); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/nullchecking/NullCheckUnitTest.java b/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/nullchecking/NullCheckUnitTest.java new file mode 100644 index 0000000000..db8aab8193 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/test/java/com/baeldung/nullchecking/NullCheckUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.nullchecking; + +import org.apache.commons.lang3.ObjectUtils; +import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class NullCheckUnitTest { + + @Test + public void givenNullFields_whenCheckForNullsUsingIfs_thenReturnCorrectValue(){ + Car car = new Car(); + + boolean result = car.allNull(); + + assertTrue(result); + } + + @Test + public void givenNullFields_whenCheckForNullsUsingStreams_thenReturnCorrectValue(){ + Car car = new Car(); + + boolean result = car.allNullV2(); + + assertTrue(result); + } + + @Test + public void givenNullFields_whenCheckForNullsUsingApacheCommons_thenReturnCorrectValue(){ + Car car = new Car(); + + boolean result = ObjectUtils.allNull(car.power, car.year); + + assertTrue(result); + } + + @Test + public void givenNullFields_whenCheckForNullsUsingReflection_thenReturnCorrectValue(){ + Car car = new Car(); + + boolean result = NullChecker.allNull(car); + + assertTrue(result); + } +} diff --git a/core-java-modules/core-java-lang-oop-types-2/README.md b/core-java-modules/core-java-lang-oop-types-2/README.md index 474d0c8a22..ca8742d6c0 100644 --- a/core-java-modules/core-java-lang-oop-types-2/README.md +++ b/core-java-modules/core-java-lang-oop-types-2/README.md @@ -7,3 +7,5 @@ This module contains articles about types in Java - [Convert an Array of Primitives to an Array of Objects](https://www.baeldung.com/java-primitive-array-to-object-array) - [Check if an Enum Value Exists in Java](https://www.baeldung.com/java-search-enum-values) - [Generate a Random Value From an Enum](https://www.baeldung.com/java-enum-random-value) +- [Filling a List With All Enum Values in Java](https://www.baeldung.com/java-enum-values-to-list) +- [Comparing a String to an Enum Value in Java](https://www.baeldung.com/java-comparing-string-to-enum) diff --git a/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood1.java b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood1.java new file mode 100644 index 0000000000..26338fe46c --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood1.java @@ -0,0 +1,25 @@ +package com.baeldung.enumtostring; + +public enum FastFood1 { + PIZZA, + BURGER, + TACO, + CHICKEN, + ; + + @Override + public String toString() { + switch (this) { + case PIZZA: + return "Pizza Pie"; + case BURGER: + return "Cheese Burger"; + case TACO: + return "Crunchy Taco"; + case CHICKEN: + return "Fried Chicken"; + default: + return ""; + } + } +} diff --git a/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood2.java b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood2.java new file mode 100644 index 0000000000..8ca7166dec --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood2.java @@ -0,0 +1,28 @@ +package com.baeldung.enumtostring; + +public enum FastFood2 { + PIZZA { + @Override + public String toString() { + return "Pizza Pie"; + } + }, + BURGER { + @Override + public String toString() { + return "Cheese Burger"; + } + }, + TACO { + @Override + public String toString() { + return "Crunchy Taco"; + } + }, + CHICKEN { + @Override + public String toString() { + return "Fried Chicken"; + } + } +} diff --git a/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood3.java b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood3.java new file mode 100644 index 0000000000..f6db8f4095 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types-2/src/main/java/com/baeldung/enumtostring/FastFood3.java @@ -0,0 +1,29 @@ +package com.baeldung.enumtostring; + +public enum FastFood3 { + PIZZA("Pizza Pie"), + BURGER("Cheese Burger"), + TACO("Crunchy Taco"), + CHICKEN("Fried Chicken"), + ; + + private final String prettyName; + + FastFood3(String prettyName) { + this.prettyName = prettyName; + } + + FastFood3 fromString(String prettyName) { + for (FastFood3 f : values()) { + if (f.prettyName.equals(prettyName)) { + return f; + } + } + return null; + } + + @Override + public String toString() { + return prettyName; + } +} diff --git a/core-java-modules/core-java-lang-oop-types-2/src/test/java/com/baeldung/enums/comparestrenum/CompareStringAndEnumUnitTest.java b/core-java-modules/core-java-lang-oop-types-2/src/test/java/com/baeldung/enums/comparestrenum/CompareStringAndEnumUnitTest.java new file mode 100644 index 0000000000..6ce3bc7bdc --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types-2/src/test/java/com/baeldung/enums/comparestrenum/CompareStringAndEnumUnitTest.java @@ -0,0 +1,78 @@ +package com.baeldung.enums.comparestrenum; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Optional; + +import static com.baeldung.enums.comparestrenum.Weekday.Fri; +import static com.baeldung.enums.comparestrenum.Weekday.Sat; +import static org.junit.jupiter.api.Assertions.*; + +enum Weekday { + Mon("Monday"), + Tue("Tuesday"), + Wed("Wednesday"), + Thu("Thursday"), + Fri("Friday"), + Sat("Saturday"); + + private String fullName; + + Weekday(String fullName) { + this.fullName = fullName; + } + + public String getFullName() { + return fullName; + } + + + static Optional byFullNameIgnoreCase(String givenFullName) { + return Arrays.stream(values()).filter(it -> it.fullName.equalsIgnoreCase(givenFullName)).findAny(); + } + + static Optional byNameIgnoreCase(String givenName) { + return Arrays.stream(values()).filter(it -> it.name().equalsIgnoreCase(givenName)).findAny(); + } +} + +public class CompareStringAndEnumUnitTest { + private static final String SAT = "sAt"; + private static final String SATURDAY = "sAtuRdAy"; + private static final String TYPO_FRI = "ffri"; + private static final String TYPO_FRIDAY = "ffriday"; + + @Test + void givenAString_whenCompareEnumWithName_thenGetExpectedResult() { + assertTrue(SAT.equalsIgnoreCase(Sat.name())); + assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.name())); + } + + @Test + void givenAString_whenCompareEnumWithProperty_thenGetExpectedResult() { + assertTrue(SATURDAY.equalsIgnoreCase(Sat.getFullName())); + assertFalse(TYPO_FRI.equalsIgnoreCase(Fri.getFullName())); + } + + @Test + void givenAString_whenFindEnumByName_thenGetExpectedResult() { + Optional optResult = Weekday.byNameIgnoreCase(SAT); + assertTrue(optResult.isPresent()); + assertEquals(Sat, optResult.get()); + + Optional optResult2 = Weekday.byNameIgnoreCase(TYPO_FRI); + assertFalse(optResult2.isPresent()); + } + + @Test + void givenAString_whenFindEnumByProperty_thenGetExpectedResult() { + Optional optResult = Weekday.byFullNameIgnoreCase(SATURDAY); + assertTrue(optResult.isPresent()); + assertEquals(Sat, optResult.get()); + + Optional optResult2 = Weekday.byFullNameIgnoreCase(TYPO_FRIDAY); + assertFalse(optResult2.isPresent()); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java index bad134bf00..a97f9eac57 100644 --- a/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java +++ b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/enums/Pizza.java @@ -84,5 +84,14 @@ public class Pizza { this.setStatus(PizzaStatusEnum.DELIVERED); } } + + public int getDeliveryTimeInDays() { + switch (status) { + case ORDERED: return 5; + case READY: return 2; + case DELIVERED: return 0; + } + return 0; + } } \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java index 70bfe168dd..e1f99e2173 100644 --- a/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java +++ b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/enums/PizzaUnitTest.java @@ -70,7 +70,7 @@ public class PizzaUnitTest { } @Test - public void whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() { + public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() { Pizza pz = new Pizza(); pz.setStatus(Pizza.PizzaStatusEnum.READY); pz.deliver(); 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 0cc0a77605..86e17a678f 100644 --- a/core-java-modules/core-java-lang-operators-2/README.md +++ b/core-java-modules/core-java-lang-operators-2/README.md @@ -8,3 +8,4 @@ This module contains articles about Java operators - [Bitmasking in Java with Bitwise Operators](https://www.baeldung.com/java-bitmasking) - [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) diff --git a/core-java-modules/core-java-lang-operators-2/pom.xml b/core-java-modules/core-java-lang-operators-2/pom.xml index c36250f1ae..9d925c553a 100644 --- a/core-java-modules/core-java-lang-operators-2/pom.xml +++ b/core-java-modules/core-java-lang-operators-2/pom.xml @@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/keyword/InstanceOfUnitTest.java b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/keyword/InstanceOfUnitTest.java index 0e082b69d3..6ba8ed024c 100644 --- a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/keyword/InstanceOfUnitTest.java +++ b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/keyword/InstanceOfUnitTest.java @@ -1,55 +1,67 @@ package com.baeldung.keyword; -import org.junit.Assert; import org.junit.jupiter.api.Test; -import com.baeldung.keyword.Circle; -import com.baeldung.keyword.Ring; -import com.baeldung.keyword.Round; -import com.baeldung.keyword.Shape; -import com.baeldung.keyword.Triangle; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; public class InstanceOfUnitTest { @Test - public void giveWhenInstanceIsCorrect_thenReturnTrue() { + void giveWhenInstanceIsCorrect_thenReturnTrue() { Ring ring = new Ring(); - Assert.assertTrue("ring is instance of Round ", ring instanceof Round); + assertTrue(ring instanceof Round); } @Test - public void giveWhenObjectIsInstanceOfType_thenReturnTrue() { + void giveWhenObjectIsInstanceOfType_thenReturnTrue() { Circle circle = new Circle(); - Assert.assertTrue("circle is instance of Circle ", circle instanceof Circle); + assertTrue(circle instanceof Circle); } - + @Test - public void giveWhenInstanceIsOfSubtype_thenReturnTrue() { + void giveWhenInstanceIsOfSubtype_thenReturnTrue() { Circle circle = new Circle(); - Assert.assertTrue("circle is instance of Round", circle instanceof Round); + assertTrue(circle instanceof Round); } @Test - public void giveWhenTypeIsInterface_thenReturnTrue() { + void giveWhenTypeIsInterface_thenReturnTrue() { Circle circle = new Circle(); - Assert.assertTrue("circle is instance of Shape", circle instanceof Shape); + assertTrue(circle instanceof Shape); } - + @Test - public void giveWhenTypeIsOfObjectType_thenReturnTrue() { + void giveWhenTypeIsOfObjectType_thenReturnTrue() { Thread thread = new Thread(); - Assert.assertTrue("thread is instance of Object", thread instanceof Object); + assertTrue(thread instanceof Object); } @Test - public void giveWhenInstanceValueIsNull_thenReturnFalse() { + void giveWhenInstanceValueIsNull_thenReturnFalse() { Circle circle = null; - Assert.assertFalse("circle is instance of Round", circle instanceof Round); + assertFalse(circle instanceof Round); } @Test - public void giveWhenComparingClassInDiffHierarchy_thenCompilationError() { - // Assert.assertFalse("circle is instance of Triangle", circle instanceof Triangle); + void giveWhenComparingClassInDiffHierarchy_thenCompilationError() { + //assertFalse( circle instanceof Triangle); } -} + + @Test + void giveWhenStream_whenCastWithoutInstanceOfChk_thenGetException() { + Stream roundStream = Stream.of(new Ring(), new Ring(), new Circle()); + assertThrows(ClassCastException.class, () -> roundStream.map(it -> (Ring) it).collect(Collectors.toList())); + } + + @Test + void giveWhenStream_whenCastAfterInstanceOfChk_thenGetExpectedResult() { + Stream roundStream = Stream.of(new Ring(), new Ring(), new Circle()); + List ringList = roundStream.filter(it -> it instanceof Ring).map(it -> (Ring) it).collect(Collectors.toList()); + assertEquals(2, ringList.size()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-networking-2/pom.xml b/core-java-modules/core-java-networking-2/pom.xml index 77f23be97c..982f4fa346 100644 --- a/core-java-modules/core-java-networking-2/pom.xml +++ b/core-java-modules/core-java-networking-2/pom.xml @@ -25,15 +25,20 @@ ${commons-lang3.version} - javax.mail - mail - ${javax.mail.version} + org.eclipse.angus + angus-mail + ${angus.mail.version} org.asynchttpclient async-http-client ${async-http-client.version} + + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.bind.version} + com.icegreen greenmail @@ -48,9 +53,10 @@ 4.5.9 - 1.5.0-b01 + 2.0.1 2.4.5 - 1.5.8 + 2.3.3 + 2.0.0-alpha-3 \ No newline at end of file diff --git a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java index 3e40cf53f7..b2d8e6b710 100644 --- a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java +++ b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/EmailService.java @@ -1,19 +1,20 @@ package com.baeldung.mail; -import javax.mail.Authenticator; -import javax.mail.Message; -import javax.mail.Multipart; -import javax.mail.PasswordAuthentication; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; import java.io.File; import java.net.URI; import java.util.Properties; +import jakarta.mail.Authenticator; +import jakarta.mail.Message; +import jakarta.mail.Multipart; +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeBodyPart; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; + public class EmailService { private String username; diff --git a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentService.java b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentService.java index fbe8a54bbe..66e1372ac1 100644 --- a/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentService.java +++ b/core-java-modules/core-java-networking-2/src/main/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentService.java @@ -1,21 +1,23 @@ package com.baeldung.mail.mailwithattachment; -import javax.mail.BodyPart; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.PasswordAuthentication; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.Properties; +import jakarta.mail.Authenticator; +import jakarta.mail.BodyPart; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Multipart; +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeBodyPart; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; + public class MailWithAttachmentService { private final String username; @@ -37,7 +39,7 @@ public class MailWithAttachmentService { props.put("mail.smtp.host", this.host); props.put("mail.smtp.port", this.port); - return Session.getInstance(props, new javax.mail.Authenticator() { + return Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java index 8fe50efd69..a8670bb01e 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java @@ -1,10 +1,7 @@ package com.baeldung.download; -import org.junit.After; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.junit.Assert.assertTrue; -import javax.xml.bind.DatatypeConverter; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; @@ -13,7 +10,11 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutionException; -import static org.junit.Assert.assertTrue; +import javax.xml.bind.DatatypeConverter; + +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; public class FileDownloadIntegrationTest { diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java index cec4cfcb55..184df8428a 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/EmailServiceLiveTest.java @@ -1,17 +1,19 @@ package com.baeldung.mail; -import com.icegreen.greenmail.junit.GreenMailRule; -import com.icegreen.greenmail.util.ServerSetupTest; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import java.io.IOException; +import com.icegreen.greenmail.junit.GreenMailRule; +import com.icegreen.greenmail.util.ServerSetupTest; -import static org.junit.Assert.assertEquals; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; public class EmailServiceLiveTest { diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentServiceLiveTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentServiceLiveTest.java index 04ad47875f..c6850461ae 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentServiceLiveTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/mail/mailwithattachment/MailWithAttachmentServiceLiveTest.java @@ -1,20 +1,20 @@ package com.baeldung.mail.mailwithattachment; +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + import com.icegreen.greenmail.configuration.GreenMailConfiguration; import com.icegreen.greenmail.junit.GreenMailRule; import com.icegreen.greenmail.util.GreenMailUtil; import com.icegreen.greenmail.util.ServerSetupTest; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import javax.annotation.Resource; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; - -import static org.junit.Assert.assertEquals; +import jakarta.mail.MessagingException; +import jakarta.mail.Session; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; public class MailWithAttachmentServiceLiveTest { @@ -29,7 +29,6 @@ public class MailWithAttachmentServiceLiveTest { .withUser(USERNAME, PASSWORD) ); - @Resource private MailWithAttachmentService emailService; @Before @@ -73,5 +72,4 @@ public class MailWithAttachmentServiceLiveTest { return GreenMailUtil.getBody(((MimeMultipart) receivedMessage.getContent()) .getBodyPart(2)); } - } diff --git a/core-java-modules/core-java-networking-3/pom.xml b/core-java-modules/core-java-networking-3/pom.xml index 4f373238ee..6d0374c598 100644 --- a/core-java-modules/core-java-networking-3/pom.xml +++ b/core-java-modules/core-java-networking-3/pom.xml @@ -30,9 +30,9 @@ ${tomcat.embeded.version} - com.sun.mail - javax.mail - ${javax.mail.version} + org.eclipse.angus + angus-mail + ${angus.mail.version} @@ -95,7 +95,7 @@ 5.3.3 1.32 0.17 - 1.6.2 + 2.0.1 1.7 diff --git a/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/downloadattachments/DownloadEmailAttachments.java b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/downloadattachments/DownloadEmailAttachments.java index 4030f3b983..de726f6cbf 100644 --- a/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/downloadattachments/DownloadEmailAttachments.java +++ b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/downloadattachments/DownloadEmailAttachments.java @@ -6,16 +6,16 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import javax.mail.Address; -import javax.mail.Folder; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.NoSuchProviderException; -import javax.mail.Part; -import javax.mail.Session; -import javax.mail.Store; -import javax.mail.internet.MimeBodyPart; +import jakarta.mail.Address; +import jakarta.mail.Folder; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Multipart; +import jakarta.mail.NoSuchProviderException; +import jakarta.mail.Part; +import jakarta.mail.Session; +import jakarta.mail.Store; +import jakarta.mail.internet.MimeBodyPart; public class DownloadEmailAttachments { private String downloadDirectory; @@ -24,7 +24,7 @@ public class DownloadEmailAttachments { this.downloadDirectory = dir; } - public void downloadEmailAttachments(String host, String port, String userName, String password) throws NoSuchProviderException, MessagingException, IOException { + public void downloadEmailAttachments(String host, String port, String userName, String password) throws MessagingException, IOException { Properties properties = setMailServerProperties(host, port); Store store = setSessionStoreProperties(userName, password, properties); Folder inbox = store.getFolder("INBOX"); @@ -67,7 +67,7 @@ public class DownloadEmailAttachments { return downloadedAttachments; } - public Store setSessionStoreProperties(String userName, String password, Properties properties) throws NoSuchProviderException, MessagingException { + public Store setSessionStoreProperties(String userName, String password, Properties properties) throws MessagingException { Session session = Session.getDefaultInstance(properties); Store store = session.getStore("pop3"); diff --git a/core-java-modules/core-java-networking-4/README.md b/core-java-modules/core-java-networking-4/README.md index 5f0958fae0..e614801468 100644 --- a/core-java-modules/core-java-networking-4/README.md +++ b/core-java-modules/core-java-networking-4/README.md @@ -1,3 +1,5 @@ ## Relevant Articles: - [Difference Between URI.create() and new URI()](https://www.baeldung.com/java-uri-create-and-new-uri) -- [Validating URL in Java](https://www.baeldung.com/java-validate-url) \ No newline at end of file +- [Validating URL in Java](https://www.baeldung.com/java-validate-url) +- [Validating IPv4 Address in Java](https://www.baeldung.com/java-validate-ipv4-address) +- [Download a Webpage in Java](https://www.baeldung.com/java-download-webpage) diff --git a/core-java-modules/core-java-networking-4/pom.xml b/core-java-modules/core-java-networking-4/pom.xml index 29531a5767..a3694cfea8 100644 --- a/core-java-modules/core-java-networking-4/pom.xml +++ b/core-java-modules/core-java-networking-4/pom.xml @@ -20,6 +20,12 @@ commons-validator ${apache.commons-validator.version} + + org.jsoup + jsoup + ${jsoup.version} + + @@ -28,6 +34,7 @@ 1.7 + 1.15.4 \ No newline at end of file diff --git a/core-java-modules/core-java-networking-4/src/main/java/com/baeldung/urlvalidation/IPv4Validation.java b/core-java-modules/core-java-networking-4/src/main/java/com/baeldung/urlvalidation/IPv4Validation.java new file mode 100644 index 0000000000..5d72873745 --- /dev/null +++ b/core-java-modules/core-java-networking-4/src/main/java/com/baeldung/urlvalidation/IPv4Validation.java @@ -0,0 +1,27 @@ +package com.baeldung.urlvalidation; + +import com.google.common.net.InetAddresses; +import org.apache.commons.validator.routines.InetAddressValidator; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class IPv4Validation { + + public static boolean validateWithApacheCommons(String ip) { + InetAddressValidator validator = InetAddressValidator.getInstance(); + return validator.isValid(ip); + } + + public static boolean validateWithGuava(String ip) { + return InetAddresses.isInetAddress(ip); + } + + public static boolean validateWithRegex(String ip) { + String regex = "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(ip); + return matcher.matches(); + } + +} diff --git a/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/downloadwebpage/DownloadWebpageUnitTest.java b/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/downloadwebpage/DownloadWebpageUnitTest.java new file mode 100644 index 0000000000..23b8928ecb --- /dev/null +++ b/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/downloadwebpage/DownloadWebpageUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.downloadwebpage; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.junit.jupiter.api.Test; + +class DownloadWebpageUnitTest { + + @Test + public void givenURLConnection_whenRetrieveWebpage_thenWebpageIsNotNullAndContainsHtmlTag() throws IOException { + URL url = new URL("https://example.com"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + StringBuilder responseBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + responseBuilder.append(line); + } + + assertNotNull(responseBuilder); + assertTrue(responseBuilder.toString() + .contains("")); + } + + } + + @Test + public void givenJsoup_whenRetrievingWebpage_thenWebpageDocumentIsNotNullAndContainsHtmlTag() throws IOException { + + Document document = Jsoup.connect("https://example.com") + .get(); + String webpage = document.html(); + + assertNotNull(webpage); + assertTrue(webpage.contains("")); + + } + +} diff --git a/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/ipv4validation/IPv4ValidationUnitTest.java b/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/ipv4validation/IPv4ValidationUnitTest.java new file mode 100644 index 0000000000..367d70117a --- /dev/null +++ b/core-java-modules/core-java-networking-4/src/test/java/com/baeldung/ipv4validation/IPv4ValidationUnitTest.java @@ -0,0 +1,121 @@ +package com.baeldung.ipv4validation; + +import org.junit.Test; + +import static com.baeldung.urlvalidation.IPv4Validation.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class IPv4ValidationUnitTest { + + @Test + public void givenValidIPv4_whenValidate_thenReturnsTrue() { + String ip = "192.168.0.1"; + assertTrue(validateWithApacheCommons(ip)); + assertTrue(validateWithGuava(ip)); + assertTrue(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithThreeOctets_whenValidate_thenReturnsFalse() { + String ip = "192.168.0"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithLeadingZero_whenValidate_thenReturnsFalse() { + String ip = "192.168.0.01"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithInvalidCharacter_whenValidate_thenReturnsFalse() { + String ip = "a.168.0.01"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4HaveValueAbove255_whenValidate_thenReturnsFalse() { + String ip = "192.168.256.1"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenValidIPv4WithTwoDigitOctet_whenValidate_thenReturnsTrue() { + String ip = "192.168.42.1"; + assertTrue(validateWithApacheCommons(ip)); + assertTrue(validateWithGuava(ip)); + assertTrue(validateWithRegex(ip)); + } + @Test + public void givenValidIPv4WithNumberInRange200And249_whenValidate_thenReturnsTrue() { + String ip = "192.168.42.222"; + assertTrue(validateWithApacheCommons(ip)); + assertTrue(validateWithGuava(ip)); + assertTrue(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithFourDigitOctet_whenValidate_thenReturnsFalse() { + String ip = "1921.168.42.222"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithFiveOctets_whenValidate_thenReturnsFalse() { + String ip = "192.168.42.222.10"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4WithTwoConsecutiveDots_whenValidate_thenReturnsFalse() { + String ip = "192.168..1"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenOnlyDots_whenValidate_thenReturnsFalse() { + String ip = "..."; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenBlankString_whenValidate_thenReturnsFalse() { + String ip = " "; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + + @Test + public void givenIPv4StartWithDot_whenValidate_thenReturnsFalse() { + String ip = ".192.168.0.1"; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + @Test + public void givenIPv4EndWithDot_whenValidate_thenReturnsFalse() { + String ip = "192.168.0.1."; + assertFalse(validateWithApacheCommons(ip)); + assertFalse(validateWithGuava(ip)); + assertFalse(validateWithRegex(ip)); + } + +} diff --git a/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/path/DesktopPathUnitTest.java b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/path/DesktopPathUnitTest.java new file mode 100644 index 0000000000..fe21d0a72f --- /dev/null +++ b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/path/DesktopPathUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.path; + +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +import javax.swing.filechooser.FileSystemView; + +public class DesktopPathUnitTest { + // Adapt DESKTOP_PATH variable to your own system path + // private static final String DESKTOP_PATH = "C:\\Users\\HRAF\\Desktop"; + + @Test + public void whenUsingGetUserHomeProperty_thenShouldEqualDesktopPath() { + String desktopPath = System.getProperty("user.home") + File.separator + "Desktop"; + // assertEquals(DESKTOP_PATH, desktopPath); + } + + @Test + public void whenUsingFileSystemViewGetHomeDirectory_thenShouldEqualDesktopPath() { + FileSystemView view = FileSystemView.getFileSystemView(); + File file = view.getHomeDirectory(); + String path = file.getPath(); + // assertEquals(DESKTOP_PATH, path); + } + +} diff --git a/core-java-modules/core-java-numbers-5/README.md b/core-java-modules/core-java-numbers-5/README.md index 714e808239..fcc3d55dd9 100644 --- a/core-java-modules/core-java-numbers-5/README.md +++ b/core-java-modules/core-java-numbers-5/README.md @@ -6,3 +6,6 @@ - [List All Factors of a Number in Java](https://www.baeldung.com/java-list-factors-integer) - [Make Division of Two Integers Result in a Float](https://www.baeldung.com/java-integer-division-float-result) - [Creating Random Numbers With No Duplicates in Java](https://www.baeldung.com/java-unique-random-numbers) +- [Multiply a BigDecimal by an Integer in Java](https://www.baeldung.com/java-bigdecimal-multiply-integer) +- [Check if an Integer Value is null or Zero in Java](https://www.baeldung.com/java-check-integer-null-or-zero) +- [Return Absolute Difference of Two Integers in Java](https://www.baeldung.com/java-absolute-difference-of-two-integers) diff --git a/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/IntegerNullOrZero.java b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/IntegerNullOrZero.java new file mode 100644 index 0000000000..5fbc428b90 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/IntegerNullOrZero.java @@ -0,0 +1,26 @@ +package com.baeldung; + +import java.util.Optional; +import org.apache.commons.lang3.ObjectUtils; + +public class IntegerNullOrZero { + private IntegerNullOrZero() { + throw new RuntimeException("This class cannot be instantiated."); + } + + public static boolean usingStandardWay(Integer num) { + return num == null || num == 0; + } + + public static boolean usingTernaryOperator(Integer num) { + return 0 == (num == null ? 0 : num); + } + + public static boolean usingOptional(Integer num) { + return Optional.ofNullable(num).orElse(0) == 0; + } + + public static boolean usingObjectUtils(Integer num) { + return ObjectUtils.defaultIfNull(num, 0) == 0; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/absintdiff/AbsoluteDifferenceOfTwoIntUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/absintdiff/AbsoluteDifferenceOfTwoIntUnitTest.java new file mode 100644 index 0000000000..eec3924202 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/absintdiff/AbsoluteDifferenceOfTwoIntUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.absintdiff; + +import static com.baeldung.absintdiff.IntDiffUtil.absDiff; +import static com.baeldung.absintdiff.IntDiffUtil.absDiff2; +import static com.baeldung.absintdiff.IntDiffUtil.absDiffAsLong; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class IntDiffUtil { + static int absDiff(int num1, int num2) { + int result = Math.abs(num1 - num2); + System.out.println("Absolute diff: " + result); + return result; + } + + static int absDiff2(int num1, int num2) { + return Math.abs(Math.subtractExact(num1, num2)); + } + + static long absDiffAsLong(int num1, int num2) { + return Math.abs((long) num1 - num2); + } +} + +public class AbsoluteDifferenceOfTwoIntUnitTest { + + @Test + void givenTwoIntegers_whenCallingAbsDiff_shouldGetExpectedResult() { + int diff1 = absDiff(100, -200); + assertEquals(300, diff1); + + int diff2 = absDiff(100, 200); + assertEquals(100, diff2); + + //integer overflow! output: Absolute diff: 2147483449 + //absDiff(Integer.MAX_VALUE, -200); + } + + @Test + void givenTwoIntegers_whenCallingAbsDiff2_shouldThrowException() { + int diff1 = absDiff2(100, -200); + assertEquals(300, diff1); + + int diff2 = absDiff2(100, 200); + assertEquals(100, diff2); + + //overflow -> exception + assertThrows(ArithmeticException.class, () -> absDiff2(Integer.MAX_VALUE, -200)); + } + + @Test + void givenTwoIntegers_whenCallingAbsDiffAsLong_shouldThrowException() { + long diff = absDiffAsLong(Integer.MAX_VALUE, -200); + assertEquals(Integer.MAX_VALUE + 200L, diff); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/bigdecimaltimesint/BigDecimalxIntegerUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/bigdecimaltimesint/BigDecimalxIntegerUnitTest.java new file mode 100644 index 0000000000..afdf095f4e --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/bigdecimaltimesint/BigDecimalxIntegerUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.bigdecimaltimesint; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +public class BigDecimalxIntegerUnitTest { + private static final BigDecimal BIG = new BigDecimal("42.42"); + private static final int INT = 10; + private static final BigDecimal EXPECTED = new BigDecimal("424.2"); + + @Test + void givenBigDecimalAndInt_whenTimes_thenGetExpectedResult() { + BigDecimal result = BIG.multiply(BigDecimal.valueOf(INT)); + + assertEquals(0, EXPECTED.compareTo(result)); + assertThat(result).isEqualByComparingTo(EXPECTED); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intnullorzero/IntegerNullOrZeroUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intnullorzero/IntegerNullOrZeroUnitTest.java new file mode 100644 index 0000000000..6926289536 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intnullorzero/IntegerNullOrZeroUnitTest.java @@ -0,0 +1,69 @@ +package com.baeldung.intnullorzero; + +import static com.baeldung.IntegerNullOrZero.usingObjectUtils; +import static com.baeldung.IntegerNullOrZero.usingOptional; +import static com.baeldung.IntegerNullOrZero.usingStandardWay; +import static com.baeldung.IntegerNullOrZero.usingTernaryOperator; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class IntegerNullOrZeroUnitTest { + + @Test + void givenInts_whenUsingStandardWay_thenGetExpectedResult() { + int n0 = 0; + boolean result0 = usingStandardWay(n0); + assertTrue(result0); + + boolean resultNull = usingStandardWay(null); + assertTrue(resultNull); + + int n42 = 42; + boolean result42 = usingStandardWay(n42); + assertFalse(result42); + } + + @Test + void givenInts_whenUsingTernaryOperator_thenGetExpectedResult() { + int n0 = 0; + boolean result0 = usingTernaryOperator(n0); + assertTrue(result0); + + boolean resultNull = usingTernaryOperator(null); + assertTrue(resultNull); + + int n42 = 42; + boolean result42 = usingTernaryOperator(n42); + assertFalse(result42); + } + + @Test + void givenInts_whenUsingOptional_thenGetExpectedResult() { + int n0 = 0; + boolean result0 = usingOptional(n0); + assertTrue(result0); + + boolean resultNull = usingOptional(null); + assertTrue(resultNull); + + int n42 = 42; + boolean result42 = usingOptional(n42); + assertFalse(result42); + } + + @Test + void givenInts_whenUsingObjectUtils_thenGetExpectedResult() { + int n0 = 0; + boolean result0 = usingObjectUtils(n0); + assertTrue(result0); + + boolean resultNull = usingObjectUtils(null); + assertTrue(resultNull); + + int n42 = 42; + boolean result42 = usingObjectUtils(n42); + assertFalse(result42); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-optional/README.md b/core-java-modules/core-java-optional/README.md index 6c83003ea2..674ab5a7cd 100644 --- a/core-java-modules/core-java-optional/README.md +++ b/core-java-modules/core-java-optional/README.md @@ -10,3 +10,4 @@ This module contains articles about Java Optional. - [Java 9 Optional API Additions](https://www.baeldung.com/java-9-optional) - [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception) - [Optional orElse Optional](https://www.baeldung.com/java-optional-or-else-optional) +- [Uses for Optional in Java](https://www.baeldung.com/java-optional-uses) diff --git a/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/User.java b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/User.java new file mode 100644 index 0000000000..99a8810d5b --- /dev/null +++ b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/User.java @@ -0,0 +1,21 @@ +package com.baeldung.optionaluses; + +public class User { + + public User(String id, String name) { + this.id = id; + this.name = name; + } + + private String id; + + private String name; + + public String getName() { + return name; + } + + public String getId() { + return id; + } +} diff --git a/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserFoundException.java b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserFoundException.java new file mode 100644 index 0000000000..d9dab9f05f --- /dev/null +++ b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserFoundException.java @@ -0,0 +1,11 @@ +package com.baeldung.optionaluses; + +public class UserFoundException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public UserFoundException(String message) { + super(message); + } + +} diff --git a/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithNull.java b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithNull.java new file mode 100644 index 0000000000..c41de1b5f5 --- /dev/null +++ b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithNull.java @@ -0,0 +1,20 @@ +package com.baeldung.optionaluses; + +import java.util.Arrays; +import java.util.List; + +public class UserRepositoryWithNull { + + private final List dbUsers = Arrays.asList(new User("1", "John"), new User("2", "Maria"), new User("3", "Daniel")); + + public User findById(String id) { + + for (User u : dbUsers) { + if (u.getId().equals(id)) { + return u; + } + } + + return null; + } +} diff --git a/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithOptional.java b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithOptional.java new file mode 100644 index 0000000000..ee43addec7 --- /dev/null +++ b/core-java-modules/core-java-optional/src/main/java/com/baeldung/optionaluses/UserRepositoryWithOptional.java @@ -0,0 +1,30 @@ +package com.baeldung.optionaluses; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class UserRepositoryWithOptional { + + private final List dbUsers = Arrays.asList(new User("1", "John"), new User("2", "Maria"), new User("3", "Daniel")); + + public Optional findById(String id) { + + for (User u : dbUsers) { + if (u.getId().equals(id)) { + return Optional.of(u); + } + } + + return Optional.empty(); + } + + public void throwExceptionWhenUserIsPresent(String id) { + + this.findById(id) + .ifPresent(user -> { + throw new UserFoundException("User with ID : " + user.getId() + " is found"); + }); + + } +} diff --git a/core-java-modules/core-java-optional/src/test/java/com/baeldung/optionaluses/UsesForOptionalUnitTest.java b/core-java-modules/core-java-optional/src/test/java/com/baeldung/optionaluses/UsesForOptionalUnitTest.java new file mode 100644 index 0000000000..5c63987193 --- /dev/null +++ b/core-java-modules/core-java-optional/src/test/java/com/baeldung/optionaluses/UsesForOptionalUnitTest.java @@ -0,0 +1,83 @@ +package com.baeldung.optionaluses; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class UsesForOptionalUnitTest { + + @Test + void givenNonExistentUserId_whenSearchForUser_andNoNullCheck_thenThrowException() { + + UserRepositoryWithNull userRepositoryWithNull = new UserRepositoryWithNull(); + String nonExistentUserId = "4"; + + assertThrows(NullPointerException.class, () -> System.out.println("User name: " + userRepositoryWithNull.findById(nonExistentUserId).getName())); + } + + @Test + void givenNonExistentUserId_whenSearchForUser_thenOptionalShouldBeTreatedProperly() { + + UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional(); + String nonExistentUserId = "4"; + + String userName = userRepositoryWithOptional.findById(nonExistentUserId) + .orElse(new User("0", "admin")) + .getName(); + + assertEquals("admin", userName); + } + + @Test + void givenExistentUserId_whenFoundUserWithNameStartingWithMInRepositoryUsingNull_thenNameShouldBeUpperCased() { + + UserRepositoryWithNull userRepositoryWithNull = new UserRepositoryWithNull(); + + User user = userRepositoryWithNull.findById("2"); + String upperCasedName = ""; + + if (user != null) { + if (user.getName().startsWith("M")) { + upperCasedName = user.getName().toUpperCase(); + } + } + + assertEquals("MARIA", upperCasedName); + } + + @Test + void givenExistentUserId_whenFoundUserWithNameStartingWithMInRepositoryUsingOptional_thenNameShouldBeUpperCased() { + + UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional(); + + String upperCasedName = userRepositoryWithOptional.findById("2") + .filter(u -> u.getName().startsWith("M")) + .map(u -> u.getName().toUpperCase()) + .orElse(""); + + assertEquals("MARIA", upperCasedName); + } + + @Test + void givenExistentUserId_whenSearchForUser_thenThrowException() { + + final UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional(); + String existentUserId = "2"; + + assertThrows(UserFoundException.class, () -> userRepositoryWithOptional.throwExceptionWhenUserIsPresent(existentUserId)); + + } + + @Test + void givenNonExistentUserId_whenSearchForUser_thenDoNotThrowException() { + + final UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional(); + String nonExistentUserId = "8"; + + assertDoesNotThrow(() -> userRepositoryWithOptional.throwExceptionWhenUserIsPresent(nonExistentUserId)); + + } + +} diff --git a/core-java-modules/core-java-perf/README.md b/core-java-modules/core-java-perf/README.md index e09f8bb6fc..c018ec9927 100644 --- a/core-java-modules/core-java-perf/README.md +++ b/core-java-modules/core-java-perf/README.md @@ -12,3 +12,4 @@ This module contains articles about performance of Java applications - [Branch Prediction in Java](https://www.baeldung.com/java-branch-prediction) - [Capturing a Java Thread Dump](https://www.baeldung.com/java-thread-dump) - [JMX Ports](https://www.baeldung.com/jmx-ports) +- [Calling JMX MBean Method From a Shell Script](https://www.baeldung.com/jmx-mbean-shell-access) diff --git a/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/JmxCalculatorMain.java b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/JmxCalculatorMain.java new file mode 100644 index 0000000000..1201f2551f --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/JmxCalculatorMain.java @@ -0,0 +1,25 @@ +package com.baeldung.jmxshell; + +import java.lang.management.ManagementFactory; +import java.util.Scanner; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import com.baeldung.jmxshell.bean.Calculator; + +public class JmxCalculatorMain { + + public static void main(String[] args) throws Exception { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + server.registerMBean(new Calculator(), new ObjectName("com.baeldung.jxmshell:type=basic,name=calculator")); + + System.out.printf("mbean registered. pid: %s\n", ManagementFactory.getRuntimeMXBean() + .getName()); + + try (Scanner scanner = new Scanner(System.in)) { + System.out.println(""); + scanner.nextLine(); + } + } +} diff --git a/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/Calculator.java b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/Calculator.java new file mode 100644 index 0000000000..cb57a5e154 --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/Calculator.java @@ -0,0 +1,32 @@ +package com.baeldung.jmxshell.bean; + +public class Calculator implements CalculatorMBean { + + private Integer a = 0; + private Integer b = 0; + + @Override + public Integer sum() { + return a + b; + } + + @Override + public Integer getA() { + return a; + } + + @Override + public void setA(Integer a) { + this.a = a; + } + + @Override + public Integer getB() { + return b; + } + + @Override + public void setB(Integer b) { + this.b = b; + } +} diff --git a/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/CalculatorMBean.java b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/CalculatorMBean.java new file mode 100644 index 0000000000..16e104295a --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/bean/CalculatorMBean.java @@ -0,0 +1,14 @@ +package com.baeldung.jmxshell.bean; + +public interface CalculatorMBean { + + Integer sum(); + + Integer getA(); + + void setA(Integer a); + + Integer getB(); + + void setB(Integer b); +} diff --git a/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxConnectionWrapper.java b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxConnectionWrapper.java new file mode 100644 index 0000000000..ea70fa3c96 --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxConnectionWrapper.java @@ -0,0 +1,68 @@ +package com.baeldung.jmxshell.custom; + +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.management.Attribute; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +public class JmxConnectionWrapper { + + private final Map attributeMap; + private final MBeanServerConnection connection; + private final ObjectName objectName; + + public JmxConnectionWrapper(String url, String beanName) throws Exception { + objectName = new ObjectName(beanName); + + connection = JMXConnectorFactory.connect(new JMXServiceURL(url)) + .getMBeanServerConnection(); + + MBeanInfo bean = connection.getMBeanInfo(objectName); + MBeanAttributeInfo[] attributes = bean.getAttributes(); + + this.attributeMap = Stream.of(attributes) + .peek(System.out::println) + .collect(Collectors.toMap(MBeanAttributeInfo::getName, Function.identity())); + } + + public boolean hasAttribute(String attributeName) { + return attributeMap.containsKey(attributeName); + } + + public Object attributeValue(String name, String value) throws Exception { + if (value != null) { + connection.setAttribute(objectName, new Attribute(name, parse(value))); + } + return connection.getAttribute(objectName, name); + } + + public Object invoke(String operation) throws Exception { + String[] signature = new String[] {}; + Object[] params = new Object[] {}; + + return connection.invoke(objectName, operation, params, signature); + } + + private static Object parse(String value) { + if (value == null) + return null; + + if (value.matches("\\d+")) { + return Integer.valueOf(value); + } else if (value.trim() + .toLowerCase() + .matches("true|false")) { + return Boolean.valueOf(value); + } + + return value.equals("null") ? null : value; + } +} diff --git a/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxInvoker.java b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxInvoker.java new file mode 100644 index 0000000000..dda765289e --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/java/com/baeldung/jmxshell/custom/JmxInvoker.java @@ -0,0 +1,34 @@ +package com.baeldung.jmxshell.custom; + +public class JmxInvoker { + + public static void main(String... args) throws Exception { + String serviceURL = args[0]; + String name = args[1]; + String operation = args[2]; + String attributeValue = null; + if (args.length > 3) { + attributeValue = args[3]; + } + + String result = execute(serviceURL, name, operation, attributeValue); + System.out.println(result); + } + + public static String execute(String url, String mBeanName, String operation, String attributeValue) { + try { + JmxConnectionWrapper connection = new JmxConnectionWrapper(url, mBeanName); + + if (connection.hasAttribute(operation)) { + Object value = connection.attributeValue(operation, attributeValue); + return operation + "=" + value; + } else { + Object result = connection.invoke(operation); + return operation + "(): " + result; + } + } catch (Exception e) { + e.printStackTrace(); + return e.getClass() + ": " + e.getMessage(); + } + } +} diff --git a/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmx-invoker.sh b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmx-invoker.sh new file mode 100755 index 0000000000..cf9fa1621d --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmx-invoker.sh @@ -0,0 +1,45 @@ +#!/bin/sh +jar='/tmp/core-java-perf.jar' +address='localhost:11234' +mbean='com.baeldung.jxmshell:name=calculator,type=basic' +operation='sum' + +while test $# -gt 0 +do + case "$1" in + --jar) + shift + jar="$1" + ;; + --address) + shift + address="$1" + ;; + --mbean) + shift + mbean="$1" + ;; + --run|-x) + shift + operation="$1" + ;; + --get) + shift + operation="$1" + ;; + --set) + shift + operation="$1 $2" + ;; + -*) + echo "bad option '$1'" + exit 1 + ;; + esac + shift +done + +java -cp "$jar" com.baeldung.jmxshell.custom.JmxInvoker \ + "service:jmx:rmi:///jndi/rmi://$address/jmxrmi" \ + "$mbean" \ + "$operation" diff --git a/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxclient.sh b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxclient.sh new file mode 100755 index 0000000000..72214ed181 --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxclient.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +jar='/tmp/cmdline-jmxclient-0.10.3.jar' +address='localhost:11234' + +mbean='com.baeldung.jxmshell:name=calculator,type=basic' +operation='sum' +command="$mbean" + +while test $# -gt 0 +do + case "$1" in + --jar) + shift + jar="$1" + ;; + --address) + shift + address="$1" + ;; + --mbean) + shift + mbean="$1" + ;; + --run|-x) + shift + operation="$1" + + command="${mbean} ${operation}" + ;; + --set) + shift + operation="$1" + + shift + attribute_value="$1" + + command="${mbean} ${operation}=${attribute_value}" + ;; + --get) + shift + operation="$1" + + command="${mbean} ${operation}" + ;; + -*) + echo "bad option '$1'" + exit 1 + ;; + esac + shift +done + +java -jar "$jar" - "$address" "$command" diff --git a/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.pl b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.pl new file mode 100755 index 0000000000..af199a4113 --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +$jar = "/tmp/jmxterm-1.0.4-uber.jar"; + +$host = "localhost"; +$port = 11234; + +$mbean = $ARGV[0] || "com.baeldung.jxmshell:name=calculator,type=basic"; +$operation = $ARGV[1] || "sum"; + +open JMX, "| java -jar $jar -n"; + +print JMX "open $host:$port\n"; +$attribute_value = $ARGV[2]; +if (defined $attribute_value) { + print JMX "set -b ${mbean} ${operation} ${attribute_value}\n"; +} else { + print JMX "run -b ${mbean} ${operation}\n"; +} +print JMX "close\n"; + +close JMX; diff --git a/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.sh b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.sh new file mode 100755 index 0000000000..f81d0be920 --- /dev/null +++ b/core-java-modules/core-java-perf/src/main/resources/jmxshell/jmxterm.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +jar='/tmp/jmxterm-1.0.4-uber.jar' +address='localhost:11234' + +mbean='com.baeldung.jxmshell:name=calculator,type=basic' +operation='sum' +command="info -b $mbean" + +while test $# -gt 0 +do + case "$1" in + --jar|-j) + shift; jar="$1" + ;; + --address|-l) + shift; address="$1" + ;; + --mbean|-b) + shift; mbean="$1" + ;; + --run|-x) + shift; operation="$1" + + command="run -b ${mbean} ${operation}" + ;; + --set) + shift; operation="$1" + shift; attribute_value="$1" + + command="set -b ${mbean} ${operation} ${attribute_value}" + ;; + --get) + shift; operation="$1" + + command="get -b ${mbean} ${operation}" + ;; + -*) + echo "bad option '$1'" + exit 1 + ;; + esac + shift +done + +echo "$command" | java -jar "$jar" -l "$address" -n -v silent diff --git a/core-java-modules/core-java-perf/src/test/java/com/baeldung/jmxshell/custom/JmxInvokerLiveTest.java b/core-java-modules/core-java-perf/src/test/java/com/baeldung/jmxshell/custom/JmxInvokerLiveTest.java new file mode 100644 index 0000000000..2177e0a5ea --- /dev/null +++ b/core-java-modules/core-java-perf/src/test/java/com/baeldung/jmxshell/custom/JmxInvokerLiveTest.java @@ -0,0 +1,47 @@ +package com.baeldung.jmxshell.custom; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(OrderAnnotation.class) +class JmxInvokerLiveTest { + + private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:11234/jmxrmi"; + private static final String JMX_MBEAN_NAME = "com.baeldung.jxmshell:name=calculator,type=basic"; + private static final String ATTRIBUTE_A = "A"; + private static final String ATTRIBUTE_B = "B"; + private static final String SUM_OPERATION = "sum"; + private static final Integer ATTRIBUTE_VALUE = 1; + + @Test + @Order(1) + void givenAttributeValue_whenSetAttributeA_thenResultMatches() { + String attributeValue = ATTRIBUTE_VALUE.toString(); + + String result = JmxInvoker.execute(JMX_URL, JMX_MBEAN_NAME, ATTRIBUTE_A, attributeValue); + + assertEquals(ATTRIBUTE_A + "=" + attributeValue, result); + } + + @Test + @Order(2) + void givenAttributeValue_whenSetAttributeB_thenResultMatches() { + String attributeValue = ATTRIBUTE_VALUE.toString(); + + String result = JmxInvoker.execute(JMX_URL, JMX_MBEAN_NAME, ATTRIBUTE_B, attributeValue); + + assertEquals(ATTRIBUTE_B + "=" + attributeValue, result); + } + + @Test + @Order(3) + void whenSumOperation_thenSumIsCorrect() { + String result = JmxInvoker.execute(JMX_URL, JMX_MBEAN_NAME, SUM_OPERATION, null); + + assertEquals(SUM_OPERATION + "(): " + (ATTRIBUTE_VALUE + ATTRIBUTE_VALUE), result); + } +} diff --git a/core-java-modules/core-java-reflection-private-constructor/README.md b/core-java-modules/core-java-reflection-private-constructor/README.md new file mode 100644 index 0000000000..a3c9d00b0a --- /dev/null +++ b/core-java-modules/core-java-reflection-private-constructor/README.md @@ -0,0 +1,10 @@ +### Relevant Articles: + +- [Reading the Value of ‘private’ Fields from a Different Class in Java](https://www.baeldung.com/java-reflection-read-private-field-value) +- [Set Field Value With Reflection](https://www.baeldung.com/java-set-private-field-value) +- [Checking If a Method is Static Using Reflection in Java](https://www.baeldung.com/java-check-method-is-static) +- [Checking if a Java Class is ‘abstract’ Using Reflection](https://www.baeldung.com/java-reflection-is-class-abstract) +- [Invoking a Private Method in Java](https://www.baeldung.com/java-call-private-method) +- [Finding All Classes in a Java Package](https://www.baeldung.com/java-find-all-classes-in-package) +- [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) diff --git a/core-java-modules/core-java-reflection-private-constructor/pom.xml b/core-java-modules/core-java-reflection-private-constructor/pom.xml new file mode 100644 index 0000000000..b53aa2c61b --- /dev/null +++ b/core-java-modules/core-java-reflection-private-constructor/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + core-java-reflection-private-constructor + 0.1.0-SNAPSHOT + core-java-reflection-private-constructor + 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-private-constructor + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${source.version} + ${target.version} + -parameters + + + + + + + 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-private-constructor/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java b/core-java-modules/core-java-reflection-private-constructor/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java new file mode 100644 index 0000000000..24e7d435c7 --- /dev/null +++ b/core-java-modules/core-java-reflection-private-constructor/src/main/java/com/baeldung/reflection/PrivateConstructorClass.java @@ -0,0 +1,8 @@ +package com.baeldung.reflection; + +public class PrivateConstructorClass { + + private PrivateConstructorClass() { + System.out.println("Used the private constructor!"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-private-constructor/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java b/core-java-modules/core-java-reflection-private-constructor/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java new file mode 100644 index 0000000000..cd1f48d720 --- /dev/null +++ b/core-java-modules/core-java-reflection-private-constructor/src/test/java/com/baeldung/reflection/PrivateConstructorUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.reflection; + +import java.lang.reflect.Constructor; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PrivateConstructorUnitTest { + + @Test + public void whenConstructorIsPrivate_thenInstanceSuccess() throws Exception { + Constructor pcc = PrivateConstructorClass.class.getDeclaredConstructor(); + pcc.setAccessible(true); + PrivateConstructorClass privateConstructorInstance = pcc.newInstance(); + Assertions.assertTrue(privateConstructorInstance instanceof PrivateConstructorClass); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-reflection/README.md b/core-java-modules/core-java-reflection/README.md index 7c3ef69012..f68362611e 100644 --- a/core-java-modules/core-java-reflection/README.md +++ b/core-java-modules/core-java-reflection/README.md @@ -7,3 +7,4 @@ - [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies) - [What Causes java.lang.reflect.InvocationTargetException?](https://www.baeldung.com/java-lang-reflect-invocationtargetexception) - [How to Get a Name of a Method Being Executed?](http://www.baeldung.com/java-name-of-executing-method) +- [Getting Class Type From a String in Java](https://www.baeldung.com/java-get-class-object-from-string) diff --git a/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java new file mode 100644 index 0000000000..c329421208 --- /dev/null +++ b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java @@ -0,0 +1,7 @@ +package com.baeldung.getclassfromstr; + +public class MyNiceClass { + public String greeting(){ + return "Hi there, I wish you all the best!"; + } +} diff --git a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java new file mode 100644 index 0000000000..f0e8022c02 --- /dev/null +++ b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.getclassfromstr; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class GetClassObjectFromStringUnitTest { + @Test + void givenQualifiedClsName_whenUsingClassForName_shouldGetExpectedClassObject() throws ReflectiveOperationException { + Class cls = Class.forName("com.baeldung.getclassfromstr.MyNiceClass"); + assertNotNull(cls); + + MyNiceClass myNiceObject = (MyNiceClass) cls.getDeclaredConstructor().newInstance(); + assertNotNull(myNiceObject); + assertEquals("Hi there, I wish you all the best!", myNiceObject.greeting()); + } + + @Test + void givenSimpleName_whenUsingClassForName_shouldGetExpectedException() { + assertThrows(ClassNotFoundException.class, () -> Class.forName("MyNiceClass")); + } +} diff --git a/core-java-modules/core-java-security-2/README.md b/core-java-modules/core-java-security-2/README.md index 31404d24a5..7128c39713 100644 --- a/core-java-modules/core-java-security-2/README.md +++ b/core-java-modules/core-java-security-2/README.md @@ -13,4 +13,4 @@ This module contains articles about core Java Security - [Get a List of Trusted Certificates in Java](https://www.baeldung.com/java-list-trusted-certificates) - [Security Context Basics: User, Subject and Principal](https://www.baeldung.com/security-context-basics) - [The java.security.egd JVM Option](https://www.baeldung.com/java-security-egd) -- More articles: [[<-- prev]](/core-java-modules/core-java-security) +- More articles: [[<-- prev]](/core-java-modules/core-java-security) [[next -->]](/core-java-modules/core-java-security-3) diff --git a/core-java-modules/core-java-security-3/README.md b/core-java-modules/core-java-security-3/README.md index 9d82e829e2..a5cfa5bdca 100644 --- a/core-java-modules/core-java-security-3/README.md +++ b/core-java-modules/core-java-security-3/README.md @@ -11,4 +11,5 @@ This module contains articles about core Java Security - [Generating a Secure AES Key in Java](https://www.baeldung.com/java-secure-aes-key) - [Computing an X509 Certificate’s Thumbprint in Java](https://www.baeldung.com/java-x509-certificate-thumbprint) - [Error: “trustAnchors parameter must be non-empty”](https://www.baeldung.com/java-trustanchors-parameter-must-be-non-empty) +- [Common Exceptions of Crypto APIs in Java](https://www.baeldung.com/java-crypto-apis-exceptions) - More articles: [[<-- prev]](/core-java-modules/core-java-security-2) diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java index 552bd5d474..f0d2f62109 100644 --- a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/CryptoDriver.java @@ -1,12 +1,11 @@ package com.baeldung.crypto; +import java.security.GeneralSecurityException; + import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; -import java.security.GeneralSecurityException; - -import com.baeldung.crypto.utils.CryptoUtils; public class CryptoDriver { diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/BadPaddingExamples.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/BadPaddingExamples.java new file mode 100644 index 0000000000..135510785f --- /dev/null +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/BadPaddingExamples.java @@ -0,0 +1,66 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class BadPaddingExamples { + + public static byte[] encryptAndDecryptUsingDifferentKeys(byte[] plainTextBytes) + throws InvalidKeyException, GeneralSecurityException { + SecretKey encryptionKey = CryptoUtils.getKeyForText("BaeldungIsASuperCoolSite"); + SecretKey differentKey = CryptoUtils.getKeyForText("ThisGivesUsAnAlternative"); + + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + + cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); + byte[] cipherTextBytes = cipher.doFinal(plainTextBytes); + + cipher.init(Cipher.DECRYPT_MODE, differentKey); + + return cipher.doFinal(cipherTextBytes); + } + + public static byte[] encryptAndDecryptUsingDifferentAlgorithms(SecretKey key, IvParameterSpec ivParameterSpec, + byte[] plainTextBytes) throws InvalidKeyException, GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + + cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); + byte[] cipherTextBytes = cipher.doFinal(plainTextBytes); + + cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + + cipher.init(Cipher.DECRYPT_MODE, key); + + return cipher.doFinal(cipherTextBytes); + } + + public static byte[] encryptAndDecryptUsingDifferentPaddings(SecretKey key, byte[] plainTextBytes) + throws InvalidKeyException, GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES/ECB/ISO10126Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] cipherTextBytes = cipher.doFinal(plainTextBytes); + + cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key); + + return cipher.doFinal(cipherTextBytes); + } + + public static byte[] encryptAndDecryptUsingSamePaddingKeyAndAlgorithm(SecretKey key, byte[] plainTextBytes) + throws InvalidKeyException, GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] cipherTextBytes = cipher.doFinal(plainTextBytes); + + cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key); + + return cipher.doFinal(cipherTextBytes); + } +} diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/IllegalBlockSizeExamples.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/IllegalBlockSizeExamples.java new file mode 100644 index 0000000000..ef6732ebb5 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/IllegalBlockSizeExamples.java @@ -0,0 +1,32 @@ +package com.baeldung.crypto.exception; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class IllegalBlockSizeExamples { + + public static byte[] encryptWithoutPadding(SecretKey key, byte[] plainTextBytes) throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + + return cipher.doFinal(plainTextBytes); + } + + public static byte[] decryptTextThatIsNotEncrypted(SecretKey key) throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + // note that this text is not encrypted at any point in this method. + String sampleText = "https://www.baeldung.com/"; + byte[] unencryptedCipherTextBytes = sampleText.getBytes(); + + return CryptoUtils.decryptWithPadding(key, unencryptedCipherTextBytes); + } +} diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamples.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamples.java new file mode 100644 index 0000000000..9a11a0e11e --- /dev/null +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamples.java @@ -0,0 +1,23 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +public class InvalidAlgorithmParameterExamples { + + public static byte[] encryptUsingIv(SecretKey key, byte[] ivBytes, String plainText) + throws InvalidKeyException, GeneralSecurityException { + IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); + + byte[] bytes = plainText.getBytes(); + + return cipher.doFinal(bytes); + } +} diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidKeyExamples.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidKeyExamples.java new file mode 100644 index 0000000000..d367f5bb24 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/InvalidKeyExamples.java @@ -0,0 +1,56 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class InvalidKeyExamples { + + public static byte[] decryptUsingCBCWithNoIV(SecretKey key, byte[] cipherTextBytes) + throws InvalidKeyException, GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key); + + return cipher.doFinal(cipherTextBytes); + } + + public static byte[] decryptUsingCBCWithIV(SecretKey key, byte[] cipherTextBytes) + throws InvalidKeyException, GeneralSecurityException { + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' }; + IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); + + return cipher.doFinal(cipherTextBytes); + } + + public static byte[] encryptWithKeyTooShort() throws InvalidKeyException, GeneralSecurityException { + SecretKey encryptionKey = CryptoUtils.getKeyForText("ThisIsTooShort"); + + String plainText = "https://www.baeldung.com/"; + byte[] bytes = plainText.getBytes(); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + + cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); + return cipher.doFinal(bytes); + } + + public static byte[] encryptWithKeyTooLong() throws InvalidKeyException, GeneralSecurityException { + SecretKey encryptionKey = CryptoUtils.getKeyForText("ThisTextIsTooLong"); + + String plainText = "https://www.baeldung.com/"; + byte[] bytes = plainText.getBytes(); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + + cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); + return cipher.doFinal(bytes); + } +} diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamples.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamples.java new file mode 100644 index 0000000000..b7bbd082e8 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamples.java @@ -0,0 +1,29 @@ +package com.baeldung.crypto.exception; + +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; + +public class NoSuchAlgorithmExamples { + + public static Cipher getCipherInstanceWithBadAlgorithm() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance("ABC"); + } + + public static Cipher getCipherInstanceWithBadAlgorithmMode() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance("AES/ABC"); + } + + public static Cipher getCipherInstanceWithBadPadding() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance("AES/CBC/ABC"); + } + + public static Cipher getCipherInstanceWithValidAlgorithm() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance("AES/CBC/PKCS5Padding"); + } +} diff --git a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java index 2d3df231ff..b48d3eec70 100644 --- a/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java +++ b/core-java-modules/core-java-security-3/src/main/java/com/baeldung/crypto/utils/CryptoUtils.java @@ -1,16 +1,21 @@ package com.baeldung.crypto.utils; +import java.nio.charset.StandardCharsets; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidParameterSpecException; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; public class CryptoUtils { @@ -20,6 +25,21 @@ public class CryptoUtils { return keyGenerator.generateKey(); } + public static SecretKey getKeyForText(String secretText) throws GeneralSecurityException { + byte[] keyBytes = secretText.getBytes(StandardCharsets.UTF_8); + return new SecretKeySpec(keyBytes, "AES"); + } + + /* + * Allows us to generate a deterministic key, for the purposes of producing + * reliable and consistent demo code & tests! For a random key, consider using + * the generateKey method above. + */ + public static SecretKey getFixedKey() throws GeneralSecurityException { + String secretText = "BaeldungIsASuperCoolSite"; + return getKeyForText(secretText); + } + public static IvParameterSpec getIV() { SecureRandom secureRandom = new SecureRandom(); byte[] iv = new byte[128 / 8]; @@ -29,18 +49,17 @@ public class CryptoUtils { return new IvParameterSpec(nonce); } - public static IvParameterSpec getIVSecureRandom(String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException { + public static IvParameterSpec getIVSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchPaddingException { SecureRandom random = SecureRandom.getInstanceStrong(); - byte[] iv = new byte[Cipher.getInstance(algorithm) - .getBlockSize()]; + byte[] iv = new byte[Cipher.getInstance(algorithm).getBlockSize()]; random.nextBytes(iv); return new IvParameterSpec(iv); } public static IvParameterSpec getIVInternal(Cipher cipher) throws InvalidParameterSpecException { AlgorithmParameters params = cipher.getParameters(); - byte[] iv = params.getParameterSpec(IvParameterSpec.class) - .getIV(); + byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); return new IvParameterSpec(iv); } @@ -50,4 +69,20 @@ public class CryptoUtils { return nonce; } + public static byte[] encryptWithPadding(SecretKey key, byte[] bytes) throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + + byte[] cipherTextBytes = cipher.doFinal(bytes); + return cipherTextBytes; + } + + public static byte[] decryptWithPadding(SecretKey key, byte[] cipherTextBytes) throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key); + + return cipher.doFinal(cipherTextBytes); + } } \ No newline at end of file diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/BadPaddingExamplesUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/BadPaddingExamplesUnitTest.java new file mode 100644 index 0000000000..f3f5c87b3a --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/BadPaddingExamplesUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; + +import javax.crypto.BadPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class BadPaddingExamplesUnitTest { + + private SecretKey key; + private IvParameterSpec ivParameterSpec; + private String plainText; + private byte[] plainTextBytes; + + @Before + public void before() throws GeneralSecurityException { + key = CryptoUtils.getFixedKey(); + + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' }; + ivParameterSpec = new IvParameterSpec(ivBytes); + + plainText = "https://www.baeldung.com/"; + plainTextBytes = plainText.getBytes(); + } + + @Test + public void givenTwoDifferentAlgorithmPaddings_whenDecrypting_thenBadPaddingExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(BadPaddingException.class, + () -> BadPaddingExamples.encryptAndDecryptUsingDifferentPaddings(key, plainTextBytes)); + } + + @Test + public void givenTwoDifferentKeys_whenDecrypting_thenBadPaddingExceptionIsThrown() throws GeneralSecurityException { + Assert.assertThrows(BadPaddingException.class, + () -> BadPaddingExamples.encryptAndDecryptUsingDifferentKeys(plainTextBytes)); + } + + @Test + public void givenTwoDifferentAlgorithms_whenDecrypting_thenBadPaddingExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(BadPaddingException.class, () -> BadPaddingExamples + .encryptAndDecryptUsingDifferentAlgorithms(key, ivParameterSpec, plainTextBytes)); + } + + @Test + public void givenSameVariablesUsedForEncryptingAndDecrypting_whenDecrypting_thenNoExceptionIsThrown() + throws GeneralSecurityException { + byte[] decryptedBytes = BadPaddingExamples.encryptAndDecryptUsingSamePaddingKeyAndAlgorithm(key, + plainTextBytes); + + Assert.assertEquals(plainText, new String(decryptedBytes)); + } +} diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/IllegalBlockSizeExamplesUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/IllegalBlockSizeExamplesUnitTest.java new file mode 100644 index 0000000000..6337b4da26 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/IllegalBlockSizeExamplesUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class IllegalBlockSizeExamplesUnitTest { + + private SecretKey key; + private byte[] plainTextBytes; + private String plainText; + + @Before + public void before() throws GeneralSecurityException { + key = CryptoUtils.getFixedKey(); + + plainText = "https://www.baeldung.com/"; + plainTextBytes = plainText.getBytes(); + } + + @Test + public void whenEncryptingPlainTextWithoutPadding_thenIllegalBlockSizeExceptionIsThrown() + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, + BadPaddingException { + Assert.assertThrows(IllegalBlockSizeException.class, + () -> IllegalBlockSizeExamples.encryptWithoutPadding(key, plainTextBytes)); + } + + @Test + public void whenDecryptingCipherTextThatWasNotEncrypted_thenIllegalBlockSizeExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(IllegalBlockSizeException.class, + () -> IllegalBlockSizeExamples.decryptTextThatIsNotEncrypted(key)); + } + + @Test + public void whenEncryptingAndDecryptingWithPadding_thenNoExceptionThrown() throws NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + byte[] cipherTextBytes = CryptoUtils.encryptWithPadding(key, plainTextBytes); + + byte[] decryptedBytes = CryptoUtils.decryptWithPadding(key, cipherTextBytes); + + Assert.assertEquals(plainText, new String(decryptedBytes)); + } +} diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamplesUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamplesUnitTest.java new file mode 100644 index 0000000000..688f53e70b --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidAlgorithmParameterExamplesUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class InvalidAlgorithmParameterExamplesUnitTest { + + private SecretKey key; + private String plainText; + + @Before + public void before() throws GeneralSecurityException { + key = CryptoUtils.getFixedKey(); + + plainText = "https://www.baeldung.com/"; + } + + @Test + public void givenIvIsTooShort_whenEncryptingUsingCBC_thenInvalidAlgorithmParameterExceptionIsThrown() + throws GeneralSecurityException { + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't' }; + Assert.assertThrows(InvalidAlgorithmParameterException.class, + () -> InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText)); + } + + @Test + public void givenIvIsTooLong_whenEncryptingUsingCBC_thenInvalidAlgorithmParameterExceptionIsThrown() + throws GeneralSecurityException { + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!', + '?' }; + Assert.assertThrows(InvalidAlgorithmParameterException.class, + () -> InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText)); + } + + @Test + public void givenIvIsCorrectSize_whenEncryptingUsingCBC_thenNoExceptionIsThrown() throws GeneralSecurityException { + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' }; + byte[] cipherTextBytes = InvalidAlgorithmParameterExamples.encryptUsingIv(key, ivBytes, plainText); + + IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); + + byte[] decryptedBytes = cipher.doFinal(cipherTextBytes); + + Assert.assertEquals(plainText, new String(decryptedBytes)); + } +} diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidKeyExamplesUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidKeyExamplesUnitTest.java new file mode 100644 index 0000000000..bee7f70632 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/InvalidKeyExamplesUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.crypto.utils.CryptoUtils; + +public class InvalidKeyExamplesUnitTest { + + private SecretKey key; + private String plainText; + private byte[] cipherTextBytes; + + @Before + public void before() throws GeneralSecurityException { + key = CryptoUtils.getFixedKey(); + + byte[] ivBytes = new byte[] { 'B', 'a', 'e', 'l', 'd', 'u', 'n', 'g', 'I', 's', 'G', 'r', 'e', 'a', 't', '!' }; + IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); + + plainText = "https://www.baeldung.com/"; + byte[] plainTextBytes = plainText.getBytes(); + + cipherTextBytes = cipher.doFinal(plainTextBytes); + } + + @Test + public void givenTextEncryptedWithCBC_whenDecryptingWithNoIv_thenInvalidKeyExceptionIsThrown() { + Assert.assertThrows(InvalidKeyException.class, + () -> InvalidKeyExamples.decryptUsingCBCWithNoIV(key, cipherTextBytes)); + } + + @Test + public void givenTextEncryptedWithCBC_whenDecryptingWithIv_thenTextIsDecrypted() + throws InvalidKeyException, GeneralSecurityException { + byte[] decryptedBytes = InvalidKeyExamples.decryptUsingCBCWithIV(key, cipherTextBytes); + + Assert.assertEquals(plainText, new String(decryptedBytes)); + } + + @Test + public void whenKeyIsTooShort_thenInvalidKeyExceptionIsThrown() { + Assert.assertThrows(InvalidKeyException.class, () -> InvalidKeyExamples.encryptWithKeyTooShort()); + } + + @Test + public void whenKeyIsTooLong_thenInvalidKeyExceptionIsThrown() { + Assert.assertThrows(InvalidKeyException.class, () -> InvalidKeyExamples.encryptWithKeyTooLong()); + } + +} diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamplesUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamplesUnitTest.java new file mode 100644 index 0000000000..b9622f6144 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/crypto/exception/NoSuchAlgorithmExamplesUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.crypto.exception; + +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; + +import org.junit.Assert; +import org.junit.Test; + +public class NoSuchAlgorithmExamplesUnitTest { + + @Test + public void whenInitingCipherWithUnknownAlgorithm_thenNoSuchAlgorithmExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(NoSuchAlgorithmException.class, + () -> NoSuchAlgorithmExamples.getCipherInstanceWithBadAlgorithm()); + } + + @Test + public void whenInitingCipherWithUnknownAlgorithmMode_thenNoSuchAlgorithmExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(NoSuchAlgorithmException.class, + () -> NoSuchAlgorithmExamples.getCipherInstanceWithBadAlgorithmMode()); + } + + @Test + public void whenInitingCipherWithUnknownPadding_thenNoSuchAlgorithmExceptionIsThrown() + throws GeneralSecurityException { + Assert.assertThrows(NoSuchAlgorithmException.class, + () -> NoSuchAlgorithmExamples.getCipherInstanceWithBadPadding()); + } + + @Test + public void whenInitingCipherWithValidAlgorithm_thenCipherInstanceIsReturned() throws GeneralSecurityException { + Assert.assertTrue(NoSuchAlgorithmExamples.getCipherInstanceWithValidAlgorithm() instanceof Cipher); + } +} diff --git a/core-java-modules/core-java-security-algorithms/src/test/java/com/baeldung/aes/AESUtilUnitTest.java b/core-java-modules/core-java-security-algorithms/src/test/java/com/baeldung/aes/AESUtilUnitTest.java index 531c20ca79..04499a4fed 100644 --- a/core-java-modules/core-java-security-algorithms/src/test/java/com/baeldung/aes/AESUtilUnitTest.java +++ b/core-java-modules/core-java-security-algorithms/src/test/java/com/baeldung/aes/AESUtilUnitTest.java @@ -48,7 +48,7 @@ class AESUtilUnitTest implements WithAssertions { IvParameterSpec ivParameterSpec = AESUtil.generateIv(); File inputFile = Paths.get("src/test/resources/baeldung.txt") .toFile(); - File encryptedFile = new File("classpath:baeldung.encrypted"); + File encryptedFile = new File("baeldung.encrypted"); File decryptedFile = new File("document.decrypted"); // when @@ -57,8 +57,8 @@ class AESUtilUnitTest implements WithAssertions { // then assertThat(inputFile).hasSameTextualContentAs(decryptedFile); - encryptedFile.delete(); - decryptedFile.delete(); + encryptedFile.deleteOnExit(); + decryptedFile.deleteOnExit(); } @Test 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-2/src/main/java/com/baeldung/reduce/entities/Rating.java new file mode 100644 index 0000000000..566691d442 --- /dev/null +++ b/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Rating.java @@ -0,0 +1,39 @@ +package com.baeldung.reduce.entities; + +import java.util.ArrayList; +import java.util.List; + +public class Rating { + + double points; + List reviews = new ArrayList<>(); + + public Rating() {} + + public void add(Review review) { + reviews.add(review); + computeRating(); + } + + private double computeRating() { + double totalPoints = reviews.stream().map(Review::getPoints).reduce(0, Integer::sum); + this.points = totalPoints / reviews.size(); + return this.points; + } + + public static Rating average(Rating r1, Rating r2) { + Rating combined = new Rating(); + combined.reviews = new ArrayList<>(r1.reviews); + combined.reviews.addAll(r2.reviews); + combined.computeRating(); + return combined; + } + + public double getPoints() { + return points; + } + + public List getReviews() { + return reviews; + } +} 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-2/src/main/java/com/baeldung/reduce/entities/Review.java new file mode 100644 index 0000000000..b889a5f154 --- /dev/null +++ b/core-java-modules/core-java-streams-2/src/main/java/com/baeldung/reduce/entities/Review.java @@ -0,0 +1,28 @@ +package com.baeldung.reduce.entities; + +public class Review { + + int points; + String review; + + public Review(int points, String review) { + this.points = points; + this.review = review; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } + + public String getReview() { + return review; + } + + public void setReview(String review) { + this.review = review; + } +} diff --git a/core-java-modules/core-java-streams-4/README.md b/core-java-modules/core-java-streams-4/README.md index 187117d5d3..c6717ec5fe 100644 --- a/core-java-modules/core-java-streams-4/README.md +++ b/core-java-modules/core-java-streams-4/README.md @@ -5,3 +5,8 @@ - [Filter Java Stream to 1 and Only 1 Element](https://www.baeldung.com/java-filter-stream-unique-element) - [Java 8 Streams: Multiple Filters vs. Complex Condition](https://www.baeldung.com/java-streams-multiple-filters-vs-condition) - [Finding Max Date in List Using Streams](https://www.baeldung.com/java-max-date-list-streams) +- [Batch Processing of Stream Data in Java](https://www.baeldung.com/java-stream-batch-processing) +- [Stream to Iterable in Java](https://www.baeldung.com/java-stream-to-iterable) +- [Understanding the Difference Between Stream.of() and IntStream.range()](https://www.baeldung.com/java-stream-of-and-intstream-range) +- [Check if Object Is an Array in Java](https://www.baeldung.com/java-check-if-object-is-an-array) +- [Mapping an Array of Integers to Strings Using Java Streams](https://www.baeldung.com/java-stream-integer-array-to-strings) diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index ed4603796d..46c0f3f7e1 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -59,6 +59,36 @@ 3.12.0 test + + io.reactivex.rxjava3 + rxjava + ${rx.java3.version} + + + io.vavr + vavr + ${io.varv.version} + + + io.projectreactor + reactor-core + ${io.reactor3.version} + + + org.apache.commons + commons-collections4 + ${apache.commons.collection4.version} + + + com.google.guava + guava + ${google.guava.version} + + + com.oath.cyclops + cyclops + ${cyclops.version} + @@ -90,6 +120,12 @@ 12 1.2.5 2.2.2 + 3.1.5 + 1.0.0-alpha-4 + 3.5.1 + 4.4 + 31.1-jre + 10.4.1 \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/intarraytostrings/ArrayConversionUtils.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/intarraytostrings/ArrayConversionUtils.java new file mode 100644 index 0000000000..3bb58b43d2 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/intarraytostrings/ArrayConversionUtils.java @@ -0,0 +1,43 @@ +package com.baeldung.streams.intarraytostrings; + +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class ArrayConversionUtils { + + public static void createStreamExample() { + int[] intArray = { 1, 2, 3, 4, 5 }; + IntStream intStream = Arrays.stream(intArray); + + Integer[] integerArray = { 1, 2, 3, 4, 5 }; + Stream integerStream = Arrays.stream(integerArray); + } + + public static String[] convertToStringArray(Integer[] input) { + return Arrays.stream(input) + .map(Object::toString) + .toArray(String[]::new); + } + + public static String[] convertToStringArray(int[] input) { + return Arrays.stream(input) + .mapToObj(Integer::toString) + .toArray(String[]::new); + } + + public static String[] convertToStringArrayWithBoxing(int[] input) { + return Arrays.stream(input) + .boxed() + .map(Object::toString) + .toArray(String[]::new); + } + + public static String convertToString(int[] input){ + return Arrays.stream(input) + .mapToObj(Integer::toString) + .collect(Collectors.joining(", ")); + } + +} diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/processing/CustomBatchIterator.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/processing/CustomBatchIterator.java new file mode 100644 index 0000000000..bfc7ffae3b --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/processing/CustomBatchIterator.java @@ -0,0 +1,47 @@ +package com.baeldung.streams.processing; + +import static java.util.Spliterator.ORDERED; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class CustomBatchIterator implements Iterator> { + private final int batchSize; + private List currentBatch; + private final Iterator iterator; + + private CustomBatchIterator(Iterator sourceIterator, int batchSize) { + this.batchSize = batchSize; + this.iterator = sourceIterator; + } + + @Override + public List next() { + prepareNextBatch(); + return currentBatch; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + public static Stream> batchStreamOf(Stream stream, int batchSize) { + return stream(new CustomBatchIterator<>(stream.iterator(), batchSize)); + } + + private static Stream stream(Iterator iterator) { + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, ORDERED), false); + } + + private void prepareNextBatch() { + currentBatch = new ArrayList<>(batchSize); + while (iterator.hasNext() && currentBatch.size() < batchSize) { + currentBatch.add(iterator.next()); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/streamtoiterable/StreamToIterable.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/streamtoiterable/StreamToIterable.java new file mode 100644 index 0000000000..cdba5ea91f --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/streamtoiterable/StreamToIterable.java @@ -0,0 +1,42 @@ +package com.baeldung.streams.streamtoiterable; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import joptsimple.internal.Strings; + +public class StreamToIterable { + public String streamToIterableLambda(List listOfStrings) { + Stream stringStream = listOfStrings.stream(); + StringBuilder sentence = new StringBuilder(); + for (String eachString : (Iterable) () -> stringStream.iterator()) { + doSomethingOnString(eachString, sentence); + } + return sentence.toString(); + } + + public String streamToIterableMethodReference(List listOfStrings) { + Stream stringStream = listOfStrings.stream(); + StringBuilder sentence = new StringBuilder(); + for (String eachString : (Iterable) stringStream::iterator) { + doSomethingOnString(eachString, sentence); + } + return sentence.toString(); + } + + public String streamToList(List listOfStrings) { + Stream stringStream = listOfStrings.stream(); + StringBuilder sentence = new StringBuilder(); + for (String eachString : stringStream.collect(Collectors.toList())) { + doSomethingOnString(eachString, sentence); + } + return sentence.toString(); + } + + private void doSomethingOnString(String s, StringBuilder sentence) { + if (!Strings.isNullOrEmpty(s)) { + sentence.append(s); + } + } +} diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/intarraytostrings/IntArrayToStringUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/intarraytostrings/IntArrayToStringUnitTest.java new file mode 100644 index 0000000000..3f6fb0be8e --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/intarraytostrings/IntArrayToStringUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.streams.intarraytostrings; + +import static com.baeldung.streams.intarraytostrings.ArrayConversionUtils.convertToString; +import static com.baeldung.streams.intarraytostrings.ArrayConversionUtils.convertToStringArray; +import static com.baeldung.streams.intarraytostrings.ArrayConversionUtils.convertToStringArrayWithBoxing; + +import org.junit.Assert; +import org.junit.Test; + +public class IntArrayToStringUnitTest { + + @Test + public void whenConvertingIntegers_thenHandleStreamOfIntegers() { + Integer[] integerNumbers = { 1, 2, 3, 4, 5 }; + String[] expectedOutput = { "1", "2", "3", "4", "5" }; + + String[] strings = convertToStringArray(integerNumbers); + + Assert.assertArrayEquals(expectedOutput, strings); + } + + @Test + public void whenConvertingInts_thenHandleIntStream() { + int[] intNumbers = { 1, 2, 3, 4, 5 }; + String[] expectedOutput = { "1", "2", "3", "4", "5" }; + + String[] strings = convertToStringArray(intNumbers); + + Assert.assertArrayEquals(expectedOutput, strings); + } + + @Test + public void givenAnIntArray_whenBoxingToInteger_thenHandleStreamOfIntegers() { + int[] intNumbers = { 1, 2, 3, 4, 5 }; + String[] expectedOutput = { "1", "2", "3", "4", "5" }; + + String[] strings = convertToStringArrayWithBoxing(intNumbers); + + Assert.assertArrayEquals(expectedOutput, strings); + } + + @Test + public void givenAnIntArray_whenUsingCollectorsJoining_thenReturnCommaSeparatedString(){ + int[] intNumbers = { 1, 2, 3, 4, 5 }; + String expectedOutput = "1, 2, 3, 4, 5"; + + String string = convertToString(intNumbers); + + Assert.assertEquals(expectedOutput, string); + } + +} diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/StreamProcessingUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/StreamProcessingUnitTest.java new file mode 100644 index 0000000000..f8f88387d5 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/StreamProcessingUnitTest.java @@ -0,0 +1,141 @@ +package com.baeldung.streams.processing; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.apache.commons.collections4.ListUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Iterators; + +import cyclops.data.LazySeq; +import cyclops.reactive.ReactiveSeq; +import io.reactivex.rxjava3.core.Observable; +import reactor.core.publisher.Flux; + +public class StreamProcessingUnitTest { + public final int BATCH_SIZE = 10; + + private final List firstBatch = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + private final List secondBatch = List.of(10, 11, 12, 13, 14, 15, 16, 17, 18, 19); + private final List thirdBatch = List.of(20, 21, 22, 23, 24, 25, 26, 27, 28, 29); + private final List fourthBatch = List.of(30, 31, 32, 33); + + public Stream data; + + @BeforeEach + public void setUp() { + data = IntStream.range(0, 34) + .boxed(); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingSpliterator_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(); + CustomBatchIterator.batchStreamOf(data, BATCH_SIZE) + .forEach(result::add); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingCollectionAPI_thenFourBatchesAreObtained() { + Collection> result = data.collect(Collectors.groupingBy(it -> it / BATCH_SIZE)) + .values(); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchParallelUsingCollectionAPI_thenFourBatchesAreObtained() { + Collection> result = data.parallel() + .collect(Collectors.groupingBy(it -> it / BATCH_SIZE)) + .values(); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingRxJavaV3_thenFourBatchesAreObtained() { + // RxJava v3 + Collection> result = new ArrayList<>(); + Observable.fromStream(data) + .buffer(BATCH_SIZE) + .subscribe(result::add); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingReactor_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(); + Flux.fromStream(data) + .buffer(BATCH_SIZE) + .subscribe(result::add); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingApacheCommon_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(ListUtils.partition(data.collect(Collectors.toList()), BATCH_SIZE)); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingGuava_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(); + Iterators.partition(data.iterator(), BATCH_SIZE) + .forEachRemaining(result::add); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingCyclops_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(); + ReactiveSeq.fromStream(data) + .grouped(BATCH_SIZE) + .toList() + .forEach(value -> result.add(value.collect(Collectors.toList()))); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingCyclopsLazy_thenFourBatchesAreObtained() { + Collection> result = new ArrayList<>(); + LazySeq.fromStream(data) + .grouped(BATCH_SIZE) + .toList() + .forEach(value -> result.add(value.collect(Collectors.toList()))); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/vavr/StreamProcessingWithVavrUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/vavr/StreamProcessingWithVavrUnitTest.java new file mode 100644 index 0000000000..859b059889 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/processing/vavr/StreamProcessingWithVavrUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.streams.processing.vavr; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +import com.baeldung.streams.processing.StreamProcessingUnitTest; + +import io.vavr.collection.List; +import io.vavr.collection.Stream; + +public class StreamProcessingWithVavrUnitTest extends StreamProcessingUnitTest { + + private final List firstBatch = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + private final List secondBatch = List.of(10, 11, 12, 13, 14, 15, 16, 17, 18, 19); + private final List thirdBatch = List.of(20, 21, 22, 23, 24, 25, 26, 27, 28, 29); + private final List fourthBatch = List.of(30, 31, 32, 33); + + @Test + public void givenAStreamOfData_whenIsProcessingInBatchUsingVavr_thenFourBatchesAreObtained() { + List> result = Stream.ofAll(data) + .toList() + .grouped(BATCH_SIZE) + .toList(); + assertTrue(result.contains(firstBatch)); + assertTrue(result.contains(secondBatch)); + assertTrue(result.contains(thirdBatch)); + assertTrue(result.contains(fourthBatch)); + } +} diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamofvsintstream/DiffBetweenStreamOfAndIntStreamRangeUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamofvsintstream/DiffBetweenStreamOfAndIntStreamRangeUnitTest.java new file mode 100644 index 0000000000..23957fe2c6 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamofvsintstream/DiffBetweenStreamOfAndIntStreamRangeUnitTest.java @@ -0,0 +1,66 @@ +package com.baeldung.streams.streamofvsintstream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.TreeSet; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class DiffBetweenStreamOfAndIntStreamRangeUnitTest { + @Test + void givenStreamOfAndIntStreamRange_whenPeekSortAndFirst_shouldResultDifferent() { + Stream normalStream = Stream.of(1, 2, 3, 4, 5); + IntStream intStreamByRange = IntStream.range(1, 6); + List normalStreamPeekResult = new ArrayList<>(); + List intStreamPeekResult = new ArrayList<>(); + + // First, the regular Stream + normalStream.peek(normalStreamPeekResult::add) + .sorted() + .findFirst(); + assertEquals(Arrays.asList(1, 2, 3, 4, 5), normalStreamPeekResult); + + // Then, the IntStream + intStreamByRange.peek(intStreamPeekResult::add) + .sorted() + .findFirst(); + assertEquals(Arrays.asList(1), intStreamPeekResult); + } + + @Test + void givenStream_whenPeekAndFirst_shouldHaveOnlyFirstElement() { + Stream normalStream = Stream.of(1, 2, 3, 4, 5); + IntStream intStreamByRange = IntStream.range(1, 6); + List normalStreamPeekResult = new ArrayList<>(); + List intStreamPeekResult = new ArrayList<>(); + + // First, the regular Stream + normalStream.peek(normalStreamPeekResult::add) + .findFirst(); + assertEquals(Arrays.asList(1), normalStreamPeekResult); + + // Then, the IntStream + intStreamByRange.peek(intStreamPeekResult::add) + .findFirst(); + assertEquals(Arrays.asList(1), intStreamPeekResult); + } + + @Test + void givenSortedStream_whenPeekSortAndFirst_shouldOnlyHaveOneElement() { + List peekResult = new ArrayList<>(); + + TreeSet treeSet = new TreeSet<>(Arrays.asList("CCC", "BBB", "AAA", "DDD", "KKK")); + + treeSet.stream() + .peek(peekResult::add) + .sorted() + .findFirst(); + + assertEquals(Arrays.asList("AAA"), peekResult); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamtoiterable/StreamToIterableUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamtoiterable/StreamToIterableUnitTest.java new file mode 100644 index 0000000000..6715477cc3 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/streamtoiterable/StreamToIterableUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.streams.streamtoiterable; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class StreamToIterableUnitTest { + + @Test + public void givenList_whenLambdaIsUsed_ThenStreamAsIterable(){ + StreamToIterable streamToIterable = new StreamToIterable(); + String actualString = streamToIterable.streamToIterableLambda(getListOfStrings()); + String expectedString = "Thisisasentencewithnospaces"; + Assert.assertEquals(expectedString, actualString); + } + + @Test + public void givenList_whenMethodReferenceIsUsed_ThenStreamAsIterable(){ + StreamToIterable streamToIterable = new StreamToIterable(); + String actualString = streamToIterable.streamToIterableMethodReference(getListOfStrings()); + String expectedString = "Thisisasentencewithnospaces"; + Assert.assertEquals(expectedString, actualString); + } + + @Test + public void givenList_whenCollectedToList_ThenStreamAsIterable(){ + StreamToIterable streamToIterable = new StreamToIterable(); + String actualString = streamToIterable.streamToList(getListOfStrings()); + String expectedString = "Thisisasentencewithnospaces"; + Assert.assertEquals(expectedString, actualString); + } + + private List getListOfStrings(){ + List listOfStrings = new ArrayList<>(); + listOfStrings.add("This"); + listOfStrings.add("is"); + listOfStrings.add("a"); + listOfStrings.add(null); + listOfStrings.add("sentence"); + listOfStrings.add("with"); + listOfStrings.add("no"); + listOfStrings.add(null); + listOfStrings.add("spaces"); + return listOfStrings; + } +} 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 ba8509306e..d2863be8e5 100644 --- a/core-java-modules/core-java-string-algorithms-3/README.md +++ b/core-java-modules/core-java-string-algorithms-3/README.md @@ -8,3 +8,5 @@ This module contains articles about string-related algorithms. - [Check if Two Strings are Anagrams in Java](https://www.baeldung.com/java-strings-anagrams) - [Email Validation in Java](https://www.baeldung.com/java-email-validation-regex) - [Check if the First Letter of a String is Uppercase](https://www.baeldung.com/java-check-first-letter-uppercase) +- [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) diff --git a/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacter.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacter.java new file mode 100644 index 0000000000..e3ac0ea2f3 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacter.java @@ -0,0 +1,72 @@ +package com.baeldung.firstnonrepeatingcharacter; + +import java.util.HashMap; +import java.util.Map; + +public class FirstNonRepeatingCharacter { + public Character firstNonRepeatingCharBruteForce(String inputString) { + if (null == inputString || inputString.isEmpty()) { + return null; + } + for (Character c : inputString.toCharArray()) { + int indexOfC = inputString.indexOf(c); + if (indexOfC == inputString.lastIndexOf(c)) { + return c; + } + } + return null; + } + + public Character firstNonRepeatingCharBruteForceNaive(String inputString) { + if (null == inputString || inputString.isEmpty()) { + return null; + } + for (int outer = 0; outer < inputString.length(); outer++) { + boolean repeat = false; + for (int inner = 0; inner < inputString.length(); inner++) { + if (inner != outer && inputString.charAt(outer) == inputString.charAt(inner)) { + repeat = true; + break; + } + } + if (!repeat) { + return inputString.charAt(outer); + } + } + return null; + } + + public Character firstNonRepeatingCharWithMap(String inputString) { + if (null == inputString || inputString.isEmpty()) { + return null; + } + Map frequency = new HashMap<>(); + for (int outer = 0; outer < inputString.length(); outer++) { + char character = inputString.charAt(outer); + frequency.put(character, frequency.getOrDefault(character, 0) + 1); + } + for (Character c : inputString.toCharArray()) { + if (frequency.get(c) == 1) { + return c; + } + } + return null; + } + + public Character firstNonRepeatingCharWithArray(String inputString) { + if (null == inputString || inputString.isEmpty()) { + return null; + } + int[] frequency = new int[26]; + for (int outer = 0; outer < inputString.length(); outer++) { + char character = inputString.charAt(outer); + frequency[character - 'a']++; + } + for (Character c : inputString.toCharArray()) { + if (frequency[c - 'a'] == 1) { + return c; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnInteger.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnInteger.java new file mode 100644 index 0000000000..ca86208e59 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnInteger.java @@ -0,0 +1,18 @@ +package com.baeldung.firstocurrenceofaninteger; + +public class FirstOccurrenceOfAnInteger { + + static Integer findFirstInteger(String s) { + int i = 0; + while (i < s.length() && !Character.isDigit(s.charAt(i))) { + i++; + } + int j = i; + while (j < s.length() && Character.isDigit(s.charAt(j))) { + j++; + } + return Integer.parseInt(s.substring(i, j)); + } + +} + diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacterUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacterUnitTest.java new file mode 100644 index 0000000000..6fca176fa0 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstnonrepeatingcharacter/FirstNonRepeatingCharacterUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.firstnonrepeatingcharacter; + +import org.junit.Assert; +import org.junit.Test; + +public class FirstNonRepeatingCharacterUnitTest { + + @Test + public void testNonRepeatingCharacterBruteForce() { + FirstNonRepeatingCharacter program = new FirstNonRepeatingCharacter(); + + Assert.assertEquals(program.firstNonRepeatingCharBruteForce("baeldung"), Character.valueOf('b')); + Assert.assertEquals(program.firstNonRepeatingCharBruteForce("lullaby"), Character.valueOf('u')); + Assert.assertEquals(program.firstNonRepeatingCharBruteForce("hello"), Character.valueOf('h')); + Assert.assertNull(program.firstNonRepeatingCharBruteForce("mahimahi")); + Assert.assertNull(program.firstNonRepeatingCharBruteForce("")); + Assert.assertNull(program.firstNonRepeatingCharBruteForce(null)); + } + + @Test + public void testNonRepeatingCharacterBruteForceNaive() { + FirstNonRepeatingCharacter program = new FirstNonRepeatingCharacter(); + Assert.assertEquals(program.firstNonRepeatingCharBruteForceNaive("baeldung"), Character.valueOf('b')); + Assert.assertEquals(program.firstNonRepeatingCharBruteForceNaive("lullaby"), Character.valueOf('u')); + Assert.assertEquals(program.firstNonRepeatingCharBruteForceNaive("hello"), Character.valueOf('h')); + Assert.assertNull(program.firstNonRepeatingCharBruteForceNaive("mahimahi")); + Assert.assertNull(program.firstNonRepeatingCharBruteForceNaive("")); + Assert.assertNull(program.firstNonRepeatingCharBruteForceNaive(null)); + } + + @Test + public void testNonRepeatingCharacterWithMap() { + FirstNonRepeatingCharacter program = new FirstNonRepeatingCharacter(); + Assert.assertEquals(program.firstNonRepeatingCharWithMap("baeldung"), Character.valueOf('b')); + Assert.assertEquals(program.firstNonRepeatingCharWithMap("lullaby"), Character.valueOf('u')); + Assert.assertEquals(program.firstNonRepeatingCharWithMap("hello"), Character.valueOf('h')); + Assert.assertNull(program.firstNonRepeatingCharWithMap("mahimahi")); + Assert.assertNull(program.firstNonRepeatingCharWithMap("")); + Assert.assertNull(program.firstNonRepeatingCharWithMap(null)); + } + + @Test + public void testNonRepeatingCharacterWithArray() { + FirstNonRepeatingCharacter program = new FirstNonRepeatingCharacter(); + Assert.assertEquals(program.firstNonRepeatingCharWithArray("baeldung"), Character.valueOf('b')); + Assert.assertEquals(program.firstNonRepeatingCharWithArray("lullaby"), Character.valueOf('u')); + Assert.assertEquals(program.firstNonRepeatingCharWithArray("hello"), Character.valueOf('h')); + Assert.assertNull(program.firstNonRepeatingCharWithArray("mahimahi")); + Assert.assertNull(program.firstNonRepeatingCharWithArray("")); + Assert.assertNull(program.firstNonRepeatingCharWithArray(null)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnIntegerUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnIntegerUnitTest.java new file mode 100644 index 0000000000..ab40316708 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/firstocurrenceofaninteger/FirstOccurrenceOfAnIntegerUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.firstocurrenceofaninteger; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +class FirstOccurrenceOfAnIntegerUnitTest { + + @Test + void whenUsingPatternMatcher_findFirstInteger() { + String s = "ba31dung123"; + Matcher matcher = Pattern.compile("\\d+").matcher(s); + matcher.find(); + int i = Integer.parseInt(matcher.group()); + Assertions.assertEquals(31, i); + } + + @Test + void whenUsingScanner_findFirstInteger() { + int i = new Scanner("ba31dung123").useDelimiter("\\D+").nextInt(); + Assertions.assertEquals(31, i); + } + + @Test + void whenUsingSplit_findFirstInteger() { + String str = "ba31dung123"; + List tokens = Arrays.stream(str.split("\\D+")) + .filter(s -> s.length() > 0).collect(Collectors.toList()); + Assertions.assertEquals(31, Integer.parseInt(tokens.get(0))); + } + + @Test + void whenUsingCustomMethod_findFirstInteger() { + String str = "ba31dung123"; + Integer i = FirstOccurrenceOfAnInteger.findFirstInteger(str); + Assertions.assertEquals(31, i); + } + + +} 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 79e13e3ba5..ba983d7593 100644 --- a/core-java-modules/core-java-string-apis-2/pom.xml +++ b/core-java-modules/core-java-string-apis-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 core-java-string-apis-2 0.0.1-SNAPSHOT @@ -41,4 +41,5 @@ 3.12.0 31.1-jre - + + \ No newline at end of file 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 671ba0077c..94fb7e855e 100644 --- a/core-java-modules/core-java-string-operations-5/README.md +++ b/core-java-modules/core-java-string-operations-5/README.md @@ -6,3 +6,5 @@ - [Capitalize the First Letter of a String in Java](https://www.baeldung.com/java-string-uppercase-first-letter) - [Convert String to char in Java](https://www.baeldung.com/java-convert-string-to-char) - [Convert String to String Array](https://www.baeldung.com/java-convert-string-to-string-array) +- [String Interpolation in Java](https://www.baeldung.com/java-string-interpolation) +- [Guide to Splitting a String by Whitespace in Java](https://www.baeldung.com/java-splitting-a-string-by-whitespace) diff --git a/core-java-modules/core-java-string-operations-5/pom.xml b/core-java-modules/core-java-string-operations-5/pom.xml index d7eade0145..efb32c73b9 100644 --- a/core-java-modules/core-java-string-operations-5/pom.xml +++ b/core-java-modules/core-java-string-operations-5/pom.xml @@ -20,6 +20,11 @@ commons-lang3 ${apache.commons.lang3.version} + + org.apache.commons + commons-text + ${commons-text.version} + @@ -39,6 +44,7 @@ 11 11 3.12.0 + 1.10.0 \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/splitstring/SplitStringUnitTest.java b/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/splitstring/SplitStringUnitTest.java new file mode 100644 index 0000000000..5be8a1dacd --- /dev/null +++ b/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/splitstring/SplitStringUnitTest.java @@ -0,0 +1,104 @@ +package com.baeldung.splitstring; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.StringTokenizer; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +public class SplitStringUnitTest { + private static final String SPACE = " "; + private static final String TAB = " "; + private static final String NEW_LINE = "\n"; + + private static final String FRUITS_TAB_SEPARATED = "Apple" + TAB + "Banana" + TAB + "Mango" + TAB + "Orange"; + private static final String FRUITS_SPACE_SEPARATED = "Apple" + SPACE + "Banana" + SPACE + "Mango" + SPACE + "Orange"; + private static final String FRUITS_NEWLINE_SEPARATED = "Apple" + NEW_LINE + "Banana" + NEW_LINE + "Mango" + NEW_LINE + "Orange"; + + @Test + public void givenSpaceSeparatedString_whenSplitUsingSpace_shouldGetExpectedResult() { + String fruits = FRUITS_SPACE_SEPARATED; + String[] fruitArray = fruits.split(SPACE); + verifySplit(fruitArray); + } + + @Test + public void givenTabSeparatedString_whenSplitUsingTab_shouldGetExpectedResult() { + String fruits = FRUITS_TAB_SEPARATED; + String[] fruitArray = fruits.split(TAB); + verifySplit(fruitArray); + } + + @Test + public void givenNewlineSeparatedString_whenSplitUsingNewline_shouldGetExpectedResult() { + String fruits = FRUITS_NEWLINE_SEPARATED; + String[] fruitArray = fruits.split(NEW_LINE); + verifySplit(fruitArray); + } + + @Test + public void givenTabSeparatedString_whenSplitUsingSpace_shouldNowSplit() { + String fruits = FRUITS_TAB_SEPARATED; + String[] fruitArray = fruits.split(" "); + assertEquals(1, fruitArray.length); + assertEquals(fruits, fruitArray[0]); + } + + @Test + public void givenWhiteSpaceSeparatedString_whenSplitUsingWhiteSpaceRegex_shouldGetExpectedResult() { + String whitespaceRegex = SPACE + "|" + TAB + "|" + NEW_LINE; + String[] allSamples = new String[] { FRUITS_SPACE_SEPARATED, FRUITS_TAB_SEPARATED, FRUITS_NEWLINE_SEPARATED }; + for (String fruits : allSamples) { + String[] fruitArray = fruits.split(whitespaceRegex); + verifySplit(fruitArray); + } + } + + @Test + public void givenNewlineSeparatedString_whenSplitUsingWhiteSpaceMetaChar_shouldGetExpectedResult() { + String whitespaceMetaChar = "\\s"; + String[] allSamples = new String[] { FRUITS_SPACE_SEPARATED, FRUITS_TAB_SEPARATED, FRUITS_NEWLINE_SEPARATED }; + for (String fruits : allSamples) { + String[] fruitArray = fruits.split(whitespaceMetaChar); + verifySplit(fruitArray); + } + } + + @Test + public void givenSpaceSeparatedString_whenSplitUsingStringTokenizer_shouldGetExpectedResult() { + String fruits = FRUITS_SPACE_SEPARATED; + StringTokenizer tokenizer = new StringTokenizer(fruits); + String[] fruitArray = new String[tokenizer.countTokens()]; + int index = 0; + while (tokenizer.hasMoreTokens()) { + fruitArray[index++] = tokenizer.nextToken(); + } + verifySplit(fruitArray); + } + + @Test + public void givenWhiteSpaceSeparatedString_whenSplitUsingStringUtils_shouldGetExpectedResult() { + String[] allSamples = new String[] { FRUITS_SPACE_SEPARATED, FRUITS_TAB_SEPARATED, FRUITS_NEWLINE_SEPARATED }; + for (String fruits : allSamples) { + String[] fruitArray = StringUtils.split(fruits); + verifySplit(fruitArray); + } + } + + @Test + public void givenNullString_whenSplitUsingStringUtils_shouldReturnNull() { + String fruits = null; + String[] fruitArray = StringUtils.split(fruits); + assertNull(fruitArray); + } + + private void verifySplit(String[] fruitArray) { + assertEquals(4, fruitArray.length); + assertEquals("Apple", fruitArray[0]); + assertEquals("Banana", fruitArray[1]); + assertEquals("Mango", fruitArray[2]); + assertEquals("Orange", fruitArray[3]); + } +} diff --git a/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/string_interpolation/StringInterpolationUnitTest.java b/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/string_interpolation/StringInterpolationUnitTest.java new file mode 100644 index 0000000000..7b2fa2ce97 --- /dev/null +++ b/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/string_interpolation/StringInterpolationUnitTest.java @@ -0,0 +1,84 @@ +package com.baeldung.string_interpolation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.text.StringSubstitutor; +import org.junit.jupiter.api.Test; + +public class StringInterpolationUnitTest { + private final String EXPECTED_STRING = "String Interpolation in Java with some Java examples."; + + @Test + public void givenTwoString_thenInterpolateWithPlusSign() { + String EXPECTED_STRING = "String Interpolation in Java with some Java examples."; + String first = "Interpolation"; + String second = "Java"; + String result = "String " + first + " in " + second + " with some " + second + " examples."; + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithFormat() { + String first = "Interpolation"; + String second = "Java"; + String result = String.format("String %s in %s with some %s examples.", first, second, second); + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithFormatted() { + String first = "Interpolation"; + String second = "Java"; + String result = String.format("String %s in %s with some %s examples.", first, second, second); + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithFormatStringReference() { + String first = "Interpolation"; + String second = "Java"; + String result = String.format("String %1$s in %2$s with some %2$s examples.", first, second); + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithStringBuilder() { + String first = "Interpolation"; + String second = "Java"; + StringBuilder builder = new StringBuilder(); + builder.append("String ") + .append(first) + .append(" in ") + .append(second) + .append(" with some ") + .append(second) + .append(" examples."); + String result = builder.toString(); + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithMessageFormat() { + String first = "Interpolation"; + String second = "Java"; + String result = MessageFormat.format("String {0} in {1} with some {1} examples.", first, second); + assertEquals(EXPECTED_STRING, result); + } + + @Test + public void givenTwoString_thenInterpolateWithStringSubstitutor() { + String baseString = "String ${first} in ${second} with some ${second} examples."; + String first = "Interpolation"; + String second = "Java"; + Map parameters = new HashMap<>(); + parameters.put("first", first); + parameters.put("second", second); + StringSubstitutor substitutor = new StringSubstitutor(parameters); + String result = substitutor.replace(baseString); + assertEquals(EXPECTED_STRING, result); + } +} diff --git a/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java b/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java index 16dd6c12ff..d99f7acea7 100644 --- a/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java +++ b/core-java-modules/core-java-time-measurements/src/main/java/com/baeldung/timer/NewsletterTask.java @@ -3,12 +3,24 @@ package com.baeldung.timer; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.util.Random; import java.util.TimerTask; +import java.util.concurrent.TimeUnit; public class NewsletterTask extends TimerTask { @Override public void run() { System.out.println("Email sent at: " + LocalDateTime.ofInstant(Instant.ofEpochMilli(scheduledExecutionTime()), ZoneId.systemDefault())); + Random random = new Random(); + int value = random.ints(1, 7) + .findFirst() + .getAsInt(); + System.out.println("The duration of sending the mail will took: " + value); + try { + TimeUnit.SECONDS.sleep(value); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } diff --git a/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitManualTest.java similarity index 76% rename from core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java rename to core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitManualTest.java index ffbe39c2bc..049fc3bf6d 100644 --- a/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitTest.java +++ b/core-java-modules/core-java-time-measurements/src/test/java/com/baeldung/timer/NewsletterTaskUnitManualTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; import java.util.Timer; -class NewsletterTaskUnitTest { +class NewsletterTaskUnitManualTest { private final Timer timer = new Timer(); @AfterEach @@ -17,17 +17,13 @@ class NewsletterTaskUnitTest { void givenNewsletterTask_whenTimerScheduledEachSecondFixedDelay_thenNewsletterSentEachSecond() throws Exception { timer.schedule(new NewsletterTask(), 0, 1000); - for (int i = 0; i < 3; i++) { - Thread.sleep(1000); - } + Thread.sleep(20000); } @Test void givenNewsletterTask_whenTimerScheduledEachSecondFixedRate_thenNewsletterSentEachSecond() throws Exception { timer.scheduleAtFixedRate(new NewsletterTask(), 0, 1000); - for (int i = 0; i < 3; i++) { - Thread.sleep(1000); - } + Thread.sleep(20000); } } \ No newline at end of file diff --git a/core-java-modules/core-java-uuid/src/main/java/com/baeldung/uuid/UUIDGenerator.java b/core-java-modules/core-java-uuid/src/main/java/com/baeldung/uuid/UUIDGenerator.java index 2170a72644..68ff9ce1d4 100644 --- a/core-java-modules/core-java-uuid/src/main/java/com/baeldung/uuid/UUIDGenerator.java +++ b/core-java-modules/core-java-uuid/src/main/java/com/baeldung/uuid/UUIDGenerator.java @@ -27,17 +27,17 @@ public final class UUIDGenerator { private static long get64LeastSignificantBitsForVersion1() { final long random63BitLong = new Random().nextLong() & 0x3FFFFFFFFFFFFFFFL; - final long variant3BitFlag = 0x8000000000000000L; - return random63BitLong + variant3BitFlag; + long variant3BitFlag = 0x8000000000000000L; + return random63BitLong | variant3BitFlag; } private static long get64MostSignificantBitsForVersion1() { - final long timeForUuidIn100Nanos = System.currentTimeMillis(); - final long time_low = (timeForUuidIn100Nanos & 0x0000_0000_FFFF_FFFFL) << 32; - final long time_mid = ((timeForUuidIn100Nanos >> 32) & 0xFFFF) << 16; + final long currentTimeMillis = System.currentTimeMillis(); + final long time_low = (currentTimeMillis & 0x0000_0000_FFFF_FFFFL) << 32; + final long time_mid = ((currentTimeMillis >> 32) & 0xFFFF) << 16; final long version = 1 << 12; - final long time_hi = ((timeForUuidIn100Nanos >> 48) & 0x0FFF); - return time_low + time_mid + version + time_hi; + final long time_high = ((currentTimeMillis >> 48) & 0x0FFF); + return time_low | time_mid | version | time_high; } /** diff --git a/core-java-modules/core-java/README.md b/core-java-modules/core-java/README.md index 087c5d356e..6d9bbe03c2 100644 --- a/core-java-modules/core-java/README.md +++ b/core-java-modules/core-java/README.md @@ -9,3 +9,5 @@ - [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) - [Illegal Character Compilation Error](https://www.baeldung.com/java-illegal-character-error) +- [Lambda Expression vs. Anonymous Inner Class](https://www.baeldung.com/java-lambdas-vs-anonymous-class) +- [Difference Between Class.forName() and Class.forName().newInstance()](https://www.baeldung.com/java-class-forname-vs-class-forname-newinstance) diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/anonymousclass/AnonymousClassExample.java b/core-java-modules/core-java/src/main/java/com/baeldung/anonymousclass/AnonymousClassExample.java new file mode 100644 index 0000000000..1ea85942ee --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/anonymousclass/AnonymousClassExample.java @@ -0,0 +1,14 @@ +package com.baeldung.anonymousclass; + +public class AnonymousClassExample{ + + public static void main(String[] args){ + Thread t1 = new Thread(new Runnable(){ + @Override + public void run() { + System.out.println("Thread: "+Thread.currentThread().getName()+" started"); + } + }); + t1.start(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/lambdaexpression/LambdaExpressionExample.java b/core-java-modules/core-java/src/main/java/com/baeldung/lambdaexpression/LambdaExpressionExample.java new file mode 100644 index 0000000000..95128b934c --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/lambdaexpression/LambdaExpressionExample.java @@ -0,0 +1,9 @@ +package com.baeldung.lambdaexpression; + +public class LambdaExpressionExample{ + + public static void main(String[] args){ + Thread t1 = new Thread(()->System.out.println("Thread: "+Thread.currentThread().getName()+" started")); + t1.start(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/loadclass/MyClassForLoad.java b/core-java-modules/core-java/src/main/java/com/baeldung/loadclass/MyClassForLoad.java new file mode 100644 index 0000000000..e97848fb1f --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/loadclass/MyClassForLoad.java @@ -0,0 +1,8 @@ +package com.baeldung.loadclass; + + +public class MyClassForLoad { + + private String data = "some data"; + +} diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/loadclass/LoadClassUnitTest.java b/core-java-modules/core-java/src/test/java/com/baeldung/loadclass/LoadClassUnitTest.java new file mode 100644 index 0000000000..1f7eb139a2 --- /dev/null +++ b/core-java-modules/core-java/src/test/java/com/baeldung/loadclass/LoadClassUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.loadclass; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InvocationTargetException; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + + +public class LoadClassUnitTest { + + @Test + public void whenUseClassForName_createdInstanceOfClassClass() throws ClassNotFoundException { + Class instance = Class.forName("com.baeldung.loadclass.MyClassForLoad"); + assertInstanceOf(Class.class, instance, "instance should be of Class.class"); + } + + @Test + public void whenUseClassForNameWithNewInstance_createdInstanceOfTargetClas() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + Object instance = Class.forName("com.baeldung.loadclass.MyClassForLoad").newInstance(); + assertInstanceOf(MyClassForLoad.class, instance, "instance should be of MyClassForLoad class"); + } + + @Test + public void whenUseClassForNameWithDeclaredConstructor_newInstanceCreatedInstanceOfTargetClas() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + Object instance = Class.forName("com.baeldung.loadclass.MyClassForLoad").getDeclaredConstructor().newInstance(); + assertInstanceOf(MyClassForLoad.class, instance, "instance should be of MyClassForLoad class"); + } + +} diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 74bf4c662c..a96489ec6f 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -31,7 +31,7 @@ core-java-collections-2 core-java-collections-3 core-java-collections-4 - core-java-collections-array-list + core-java-collections-5 core-java-collections-conversions core-java-collections-conversions-2 core-java-collections-set-2 @@ -41,7 +41,6 @@ core-java-collections-maps core-java-collections-maps-2 core-java-collections-maps-3 - core-java-collections-maps-5 core-java-concurrency-2 core-java-concurrency-advanced core-java-concurrency-advanced-2 @@ -54,6 +53,7 @@ core-java-concurrency-collections-2 core-java-console core-java-8-datetime-2 + core-java-datetime-string-2 core-java-date-operations-2 core-java-date-operations-3 core-java-8-datetime @@ -63,6 +63,7 @@ core-java-exceptions-4 core-java-function core-java-functional + core-java-hex core-java-io core-java-io-2 core-java-io-3 @@ -74,6 +75,7 @@ core-java-jndi core-java-jvm core-java-jvm-2 + core-java-jvm-3 core-java-lambdas core-java-lang core-java-lang-2 @@ -131,6 +133,7 @@ core-java-regex-2 core-java-uuid pre-jpms + core-java-collections-maps-6 @@ -150,4 +153,4 @@ - \ No newline at end of file + diff --git a/couchbase/pom.xml b/couchbase/pom.xml index e87975a53c..095bda3610 100644 --- a/couchbase/pom.xml +++ b/couchbase/pom.xml @@ -64,11 +64,16 @@ ${commons-lang3.version} test + + javax.annotation + javax.annotation-api + 1.3.2 + - 2.5.0 - 4.3.5.RELEASE + 2.7.2 + 5.3.25 \ No newline at end of file diff --git a/custom-pmd/pom.xml b/custom-pmd/pom.xml index 550f96de33..38a5e30404 100644 --- a/custom-pmd/pom.xml +++ b/custom-pmd/pom.xml @@ -44,10 +44,10 @@ - 3.7.0 - 6.0.1 - 1.8 - 1.8 + 3.10.0 + 6.53.0 + 11 + 11 \ No newline at end of file diff --git a/custom-pmd/src/main/java/com/baeldung/pmd/UnitTestNamingConventionRule.java b/custom-pmd/src/main/java/com/baeldung/pmd/UnitTestNamingConventionRule.java index e30164ac4f..a652bd1bfa 100644 --- a/custom-pmd/src/main/java/com/baeldung/pmd/UnitTestNamingConventionRule.java +++ b/custom-pmd/src/main/java/com/baeldung/pmd/UnitTestNamingConventionRule.java @@ -18,8 +18,9 @@ public class UnitTestNamingConventionRule extends AbstractJavaRule { "UnitTest", "jmhTest"); + @Override public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - String className = node.getImage(); + String className = node.getSimpleName(); Objects.requireNonNull(className); if (className.endsWith("SpringContextTest")) { diff --git a/ddd-contexts/infrastructure/pom.xml b/ddd-contexts/ddd-contexts-infrastructure/pom.xml similarity index 86% rename from ddd-contexts/infrastructure/pom.xml rename to ddd-contexts/ddd-contexts-infrastructure/pom.xml index 6107991ceb..beceaa7fb2 100644 --- a/ddd-contexts/infrastructure/pom.xml +++ b/ddd-contexts/ddd-contexts-infrastructure/pom.xml @@ -4,7 +4,7 @@ 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.dddcontexts.infrastructure - infrastructure + ddd-contexts-infrastructure 1.0 jar @@ -18,17 +18,17 @@ com.baeldung.dddcontexts.shippingcontext - shippingcontext + ddd-contexts-shippingcontext ${appmodules.version} com.baeldung.dddcontexts.ordercontext - ordercontext + ddd-contexts-ordercontext ${appmodules.version} com.baeldung.dddcontexts.sharedkernel - sharedkernel + ddd-contexts-sharedkernel ${appmodules.version} diff --git a/ddd-contexts/infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java b/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java similarity index 100% rename from ddd-contexts/infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java rename to ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/db/InMemoryOrderStore.java diff --git a/ddd-contexts/infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java b/ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java similarity index 100% rename from ddd-contexts/infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java rename to ddd-contexts/ddd-contexts-infrastructure/src/main/java/com/baeldung/dddcontexts/infrastructure/events/SimpleEventBus.java diff --git a/ddd-contexts/infrastructure/src/main/java/module-info.java b/ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/infrastructure/src/main/java/module-info.java rename to ddd-contexts/ddd-contexts-infrastructure/src/main/java/module-info.java diff --git a/ddd-contexts/mainapp/pom.xml b/ddd-contexts/ddd-contexts-mainapp/pom.xml similarity index 93% rename from ddd-contexts/mainapp/pom.xml rename to ddd-contexts/ddd-contexts-mainapp/pom.xml index 8046ae4e7d..6f7461e15b 100644 --- a/ddd-contexts/mainapp/pom.xml +++ b/ddd-contexts/ddd-contexts-mainapp/pom.xml @@ -4,7 +4,7 @@ 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.dddcontexts.mainapp - mainapp + ddd-contexts-mainapp 1.0 jar @@ -18,7 +18,7 @@ com.baeldung.dddcontexts.infrastructure - infrastructure + ddd-contexts-infrastructure ${appmodules.version} diff --git a/ddd-contexts/mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java b/ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java similarity index 100% rename from ddd-contexts/mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java rename to ddd-contexts/ddd-contexts-mainapp/src/main/java/com/baeldung/dddcontexts/mainapp/Application.java diff --git a/ddd-contexts/mainapp/src/main/java/module-info.java b/ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/mainapp/src/main/java/module-info.java rename to ddd-contexts/ddd-contexts-mainapp/src/main/java/module-info.java diff --git a/ddd-contexts/ordercontext/pom.xml b/ddd-contexts/ddd-contexts-ordercontext/pom.xml similarity index 91% rename from ddd-contexts/ordercontext/pom.xml rename to ddd-contexts/ddd-contexts-ordercontext/pom.xml index e29f109b71..d6e5811357 100644 --- a/ddd-contexts/ordercontext/pom.xml +++ b/ddd-contexts/ddd-contexts-ordercontext/pom.xml @@ -4,7 +4,7 @@ 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.dddcontexts.ordercontext - ordercontext + ddd-contexts-ordercontext 1.0 jar @@ -17,7 +17,7 @@ com.baeldung.dddcontexts.sharedkernel - sharedkernel + ddd-contexts-sharedkernel ${appmodules.version} diff --git a/ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/CustomerOrder.java diff --git a/ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/model/OrderItem.java diff --git a/ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/repository/CustomerOrderRepository.java diff --git a/ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/CustomerOrderService.java diff --git a/ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/com/baeldung/dddcontexts/ordercontext/service/OrderService.java diff --git a/ddd-contexts/ordercontext/src/main/java/module-info.java b/ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/ordercontext/src/main/java/module-info.java rename to ddd-contexts/ddd-contexts-ordercontext/src/main/java/module-info.java diff --git a/ddd-contexts/sharedkernel/pom.xml b/ddd-contexts/ddd-contexts-sharedkernel/pom.xml similarity index 94% rename from ddd-contexts/sharedkernel/pom.xml rename to ddd-contexts/ddd-contexts-sharedkernel/pom.xml index 5d31973c92..7c159dc741 100644 --- a/ddd-contexts/sharedkernel/pom.xml +++ b/ddd-contexts/ddd-contexts-sharedkernel/pom.xml @@ -4,7 +4,7 @@ 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.dddcontexts.sharedkernel - sharedkernel + ddd-contexts-sharedkernel 1.0 jar diff --git a/ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java b/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java similarity index 100% rename from ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java rename to ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/ApplicationEvent.java diff --git a/ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java b/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java similarity index 100% rename from ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java rename to ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventBus.java diff --git a/ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java b/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java similarity index 100% rename from ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java rename to ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/events/EventSubscriber.java diff --git a/ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java b/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java similarity index 100% rename from ddd-contexts/sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java rename to ddd-contexts/ddd-contexts-sharedkernel/src/main/java/com/baeldung/dddcontexts/sharedkernel/service/ApplicationService.java diff --git a/ddd-contexts/sharedkernel/src/main/java/module-info.java b/ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/sharedkernel/src/main/java/module-info.java rename to ddd-contexts/ddd-contexts-sharedkernel/src/main/java/module-info.java diff --git a/ddd-contexts/shippingcontext/pom.xml b/ddd-contexts/ddd-contexts-shippingcontext/pom.xml similarity index 90% rename from ddd-contexts/shippingcontext/pom.xml rename to ddd-contexts/ddd-contexts-shippingcontext/pom.xml index 2fb9e83645..5abdf70948 100644 --- a/ddd-contexts/shippingcontext/pom.xml +++ b/ddd-contexts/ddd-contexts-shippingcontext/pom.xml @@ -4,7 +4,7 @@ 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.dddcontexts.shippingcontext - shippingcontext + ddd-contexts-shippingcontext 1.0 jar @@ -17,7 +17,7 @@ com.baeldung.dddcontexts.sharedkernel - sharedkernel + ddd-contexts-sharedkernel ${appmodules.version} diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/PackageItem.java diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/Parcel.java diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/model/ShippableOrder.java diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/repository/ShippingOrderRepository.java diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ParcelShippingService.java diff --git a/ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/com/baeldung/dddcontexts/shippingcontext/service/ShippingService.java diff --git a/ddd-contexts/shippingcontext/src/main/java/module-info.java b/ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java similarity index 100% rename from ddd-contexts/shippingcontext/src/main/java/module-info.java rename to ddd-contexts/ddd-contexts-shippingcontext/src/main/java/module-info.java diff --git a/ddd-contexts/pom.xml b/ddd-contexts/pom.xml index 1a764a65b9..961a1d1624 100644 --- a/ddd-contexts/pom.xml +++ b/ddd-contexts/pom.xml @@ -16,11 +16,11 @@ - sharedkernel - infrastructure - shippingcontext - ordercontext - mainapp + ddd-contexts-sharedkernel + ddd-contexts-infrastructure + ddd-contexts-shippingcontext + ddd-contexts-ordercontext + ddd-contexts-mainapp diff --git a/ddd/pom.xml b/ddd/pom.xml index 3beb43bb35..6128bb1cd9 100644 --- a/ddd/pom.xml +++ b/ddd/pom.xml @@ -59,8 +59,8 @@ runtime - mysql - mysql-connector-java + com.mysql + mysql-connector-j runtime diff --git a/deeplearning4j/pom.xml b/deeplearning4j/pom.xml index c63e67d573..01bac93214 100644 --- a/deeplearning4j/pom.xml +++ b/deeplearning4j/pom.xml @@ -57,11 +57,20 @@ httpclient ${httpclient.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + 0.9.1 4.3.5 + 1.18.20 \ No newline at end of file diff --git a/deeplearning4j/src/main/java/com/baeldung/logreg/MnistClassifier.java b/deeplearning4j/src/main/java/com/baeldung/logreg/MnistClassifier.java index c8580b9c27..01f1ef1bdc 100644 --- a/deeplearning4j/src/main/java/com/baeldung/logreg/MnistClassifier.java +++ b/deeplearning4j/src/main/java/com/baeldung/logreg/MnistClassifier.java @@ -11,6 +11,7 @@ import org.datavec.image.loader.NativeImageLoader; import org.datavec.image.recordreader.ImageRecordReader; import org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator; import org.deeplearning4j.eval.Evaluation; +import org.deeplearning4j.nn.conf.LearningRatePolicy; import org.deeplearning4j.nn.conf.MultiLayerConfiguration; import org.deeplearning4j.nn.conf.NeuralNetConfiguration; import org.deeplearning4j.nn.conf.inputs.InputType; @@ -69,7 +70,8 @@ public class MnistClassifier { String localFilePath = basePath + "mnist_png.tar.gz"; File file = new File(localFilePath); if (!file.exists()) { - file.getParentFile().mkdirs(); + file.getParentFile() + .mkdirs(); Utils.downloadAndSave(dataUrl, file); Utils.extractTarArchive(file, basePath); } @@ -132,7 +134,9 @@ public class MnistClassifier { .build(); final MultiLayerConfiguration config = new NeuralNetConfiguration.Builder().seed(seed) .l2(0.0005) // ridge regression value - .updater(new Nesterovs()) //TODO new MapSchedule(ScheduleType.ITERATION, learningRateSchedule) + .updater(new Nesterovs()) + .learningRateSchedule(learningRateSchedule) + .learningRateDecayPolicy(LearningRatePolicy.Schedule) .weightInit(WeightInit.XAVIER) .list() .layer(0, layer1) diff --git a/dependency-exclusion/README.md b/dependency-exclusion/README.md new file mode 100644 index 0000000000..e9eee1be4d --- /dev/null +++ b/dependency-exclusion/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Exclude a Dependency in a Maven Plugin](https://www.baeldung.com/mvn-plugin-dependency-exclusion) diff --git a/dependency-exclusion/core-java-exclusions/pom.xml b/dependency-exclusion/core-java-exclusions/pom.xml new file mode 100644 index 0000000000..cf1b36656d --- /dev/null +++ b/dependency-exclusion/core-java-exclusions/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + core-java-exclusions + 0.0.0-SNAPSHOT + core-java-exclusions + jar + + + com.baeldung.dependency-exclusion + dependency-exclusion + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire-version} + + alphabetical + 1 + + + junit + false + + + + + + + org.apache.maven.surefire + surefire-junit47 + dummy + + + + + + + + + junit + junit + test + + + + diff --git a/dependency-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java b/dependency-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java new file mode 100644 index 0000000000..ed2400f9ac --- /dev/null +++ b/dependency-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java @@ -0,0 +1,12 @@ +package com.sample.project.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ExcludeDirectDependencyUnitTest { + @Test + public void basicUnitTest() { + assertTrue(true); + } +} diff --git a/dependency-exclusion/dummy-surefire-junit47/pom.xml b/dependency-exclusion/dummy-surefire-junit47/pom.xml new file mode 100644 index 0000000000..5859ddbe72 --- /dev/null +++ b/dependency-exclusion/dummy-surefire-junit47/pom.xml @@ -0,0 +1,9 @@ + + + 4.0.0 + org.apache.maven.surefire + surefire-junit47 + dummy + diff --git a/dependency-exclusion/pom.xml b/dependency-exclusion/pom.xml new file mode 100644 index 0000000000..ac83cc161a --- /dev/null +++ b/dependency-exclusion/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + com.baeldung.dependency-exclusion + dependency-exclusion + dependency-exclusion + pom + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + 2.22.2 + + + + dummy-surefire-junit47 + core-java-exclusions + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + -parameters + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire-version} + + 1 + + + + org.apache.maven.surefire + surefire-junit-platform + ${surefire-version} + + + + + + + + + + + junit + junit + 4.13 + + + + + diff --git a/dependeny-exclusion/core-java-exclusions/pom.xml b/dependeny-exclusion/core-java-exclusions/pom.xml new file mode 100644 index 0000000000..cf1f6d1e1b --- /dev/null +++ b/dependeny-exclusion/core-java-exclusions/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + core-java-exclusions + 0.0.0-SNAPSHOT + core-java-exclusions + jar + + + com.baeldung.dependency-exclusion + dependency-exclusion + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire-version} + + alphabetical + 1 + + + junit + false + + + + + + + org.apache.maven.surefire + surefire-junit47 + dummy + + + + + + + + + junit + junit + test + + + + diff --git a/dependeny-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java b/dependeny-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java new file mode 100644 index 0000000000..ed2400f9ac --- /dev/null +++ b/dependeny-exclusion/core-java-exclusions/src/test/java/com/sample/project/tests/ExcludeDirectDependencyUnitTest.java @@ -0,0 +1,12 @@ +package com.sample.project.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ExcludeDirectDependencyUnitTest { + @Test + public void basicUnitTest() { + assertTrue(true); + } +} diff --git a/dependeny-exclusion/dummy-surefire-junit47/pom.xml b/dependeny-exclusion/dummy-surefire-junit47/pom.xml new file mode 100644 index 0000000000..5859ddbe72 --- /dev/null +++ b/dependeny-exclusion/dummy-surefire-junit47/pom.xml @@ -0,0 +1,9 @@ + + + 4.0.0 + org.apache.maven.surefire + surefire-junit47 + dummy + diff --git a/dependeny-exclusion/pom.xml b/dependeny-exclusion/pom.xml new file mode 100644 index 0000000000..ac83cc161a --- /dev/null +++ b/dependeny-exclusion/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + com.baeldung.dependency-exclusion + dependency-exclusion + dependency-exclusion + pom + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + 2.22.2 + + + + dummy-surefire-junit47 + core-java-exclusions + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + -parameters + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire-version} + + 1 + + + + org.apache.maven.surefire + surefire-junit-platform + ${surefire-version} + + + + + + + + + + + junit + junit + 4.13 + + + + + diff --git a/cdi/README.md b/di-modules/cdi/README.md similarity index 100% rename from cdi/README.md rename to di-modules/cdi/README.md diff --git a/cdi/pom.xml b/di-modules/cdi/pom.xml similarity index 72% rename from cdi/pom.xml rename to di-modules/cdi/pom.xml index ee23e082c7..fd920c8ce1 100644 --- a/cdi/pom.xml +++ b/di-modules/cdi/pom.xml @@ -4,14 +4,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cdi - 1.0-SNAPSHOT cdi com.baeldung parent-spring-5 0.0.1-SNAPSHOT - ../parent-spring-5 + ../../parent-spring-5 @@ -43,10 +42,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + 2.0.SP1 - 3.0.5.Final - 1.9.2 + 3.1.6.Final + 1.9.19 \ No newline at end of file diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/application/BootstrappingApplication.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/application/BootstrappingApplication.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/application/BootstrappingApplication.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/application/BootstrappingApplication.java diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEvent.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEvent.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEvent.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEvent.java diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEventSource.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEventSource.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEventSource.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/events/ExampleEventSource.java diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/observers/AnotherExampleEventObserver.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/observers/AnotherExampleEventObserver.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/observers/AnotherExampleEventObserver.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/observers/AnotherExampleEventObserver.java diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/observers/ExampleEventObserver.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/observers/ExampleEventObserver.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/observers/ExampleEventObserver.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/observers/ExampleEventObserver.java diff --git a/cdi/src/main/java/com/baeldung/cdi2observers/services/TextService.java b/di-modules/cdi/src/main/java/com/baeldung/cdi2observers/services/TextService.java similarity index 100% rename from cdi/src/main/java/com/baeldung/cdi2observers/services/TextService.java rename to di-modules/cdi/src/main/java/com/baeldung/cdi2observers/services/TextService.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/application/FileApplication.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/application/FileApplication.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/application/FileApplication.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/application/FileApplication.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/factories/TimeLoggerFactory.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/factories/TimeLoggerFactory.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/factories/TimeLoggerFactory.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/factories/TimeLoggerFactory.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/GifFileEditor.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/GifFileEditor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/GifFileEditor.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/GifFileEditor.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/ImageFileEditor.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/ImageFileEditor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/ImageFileEditor.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/ImageFileEditor.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/JpgFileEditor.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/JpgFileEditor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/JpgFileEditor.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/JpgFileEditor.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/PngFileEditor.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/PngFileEditor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/PngFileEditor.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imagefileeditors/PngFileEditor.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/imageprocessors/ImageFileProcessor.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imageprocessors/ImageFileProcessor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/imageprocessors/ImageFileProcessor.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/imageprocessors/ImageFileProcessor.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/loggers/TimeLogger.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/loggers/TimeLogger.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/loggers/TimeLogger.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/loggers/TimeLogger.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/GifFileEditorQualifier.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/GifFileEditorQualifier.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/GifFileEditorQualifier.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/GifFileEditorQualifier.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/JpgFileEditorQualifier.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/JpgFileEditorQualifier.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/JpgFileEditorQualifier.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/JpgFileEditorQualifier.java diff --git a/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/PngFileEditorQualifier.java b/di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/PngFileEditorQualifier.java similarity index 100% rename from cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/PngFileEditorQualifier.java rename to di-modules/cdi/src/main/java/com/baeldung/dependencyinjection/qualifiers/PngFileEditorQualifier.java diff --git a/cdi/src/main/java/com/baeldung/interceptor/Audited.java b/di-modules/cdi/src/main/java/com/baeldung/interceptor/Audited.java similarity index 100% rename from cdi/src/main/java/com/baeldung/interceptor/Audited.java rename to di-modules/cdi/src/main/java/com/baeldung/interceptor/Audited.java diff --git a/cdi/src/main/java/com/baeldung/interceptor/AuditedInterceptor.java b/di-modules/cdi/src/main/java/com/baeldung/interceptor/AuditedInterceptor.java similarity index 100% rename from cdi/src/main/java/com/baeldung/interceptor/AuditedInterceptor.java rename to di-modules/cdi/src/main/java/com/baeldung/interceptor/AuditedInterceptor.java diff --git a/cdi/src/main/java/com/baeldung/service/SuperService.java b/di-modules/cdi/src/main/java/com/baeldung/service/SuperService.java similarity index 100% rename from cdi/src/main/java/com/baeldung/service/SuperService.java rename to di-modules/cdi/src/main/java/com/baeldung/service/SuperService.java diff --git a/cdi/src/main/java/com/baeldung/spring/aspect/SpringTestAspect.java b/di-modules/cdi/src/main/java/com/baeldung/spring/aspect/SpringTestAspect.java similarity index 100% rename from cdi/src/main/java/com/baeldung/spring/aspect/SpringTestAspect.java rename to di-modules/cdi/src/main/java/com/baeldung/spring/aspect/SpringTestAspect.java diff --git a/cdi/src/main/java/com/baeldung/spring/configuration/AppConfig.java b/di-modules/cdi/src/main/java/com/baeldung/spring/configuration/AppConfig.java similarity index 100% rename from cdi/src/main/java/com/baeldung/spring/configuration/AppConfig.java rename to di-modules/cdi/src/main/java/com/baeldung/spring/configuration/AppConfig.java diff --git a/cdi/src/main/java/com/baeldung/spring/service/SpringSuperService.java b/di-modules/cdi/src/main/java/com/baeldung/spring/service/SpringSuperService.java similarity index 100% rename from cdi/src/main/java/com/baeldung/spring/service/SpringSuperService.java rename to di-modules/cdi/src/main/java/com/baeldung/spring/service/SpringSuperService.java diff --git a/cdi/src/main/resources/META-INF/beans.xml b/di-modules/cdi/src/main/resources/META-INF/beans.xml similarity index 100% rename from cdi/src/main/resources/META-INF/beans.xml rename to di-modules/cdi/src/main/resources/META-INF/beans.xml diff --git a/cdi/src/main/resources/logback.xml b/di-modules/cdi/src/main/resources/logback.xml similarity index 100% rename from cdi/src/main/resources/logback.xml rename to di-modules/cdi/src/main/resources/logback.xml diff --git a/cdi/src/test/java/com/baeldung/test/InterceptorIntegrationTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/InterceptorIntegrationTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/InterceptorIntegrationTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/InterceptorIntegrationTest.java diff --git a/cdi/src/test/java/com/baeldung/test/SpringInterceptorIntegrationTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/SpringInterceptorIntegrationTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/SpringInterceptorIntegrationTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/SpringInterceptorIntegrationTest.java diff --git a/cdi/src/test/java/com/baeldung/test/cdi2observers/tests/TextServiceUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/cdi2observers/tests/TextServiceUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/cdi2observers/tests/TextServiceUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/cdi2observers/tests/TextServiceUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/GifFileEditorUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/GifFileEditorUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/GifFileEditorUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/GifFileEditorUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/ImageProcessorUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/ImageProcessorUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/ImageProcessorUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/ImageProcessorUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/JpgFileEditorUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/JpgFileEditorUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/JpgFileEditorUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/JpgFileEditorUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/PngFileEditorUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/PngFileEditorUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/PngFileEditorUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/PngFileEditorUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerFactoryUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerFactoryUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerFactoryUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerFactoryUnitTest.java diff --git a/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerUnitTest.java b/di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerUnitTest.java similarity index 100% rename from cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerUnitTest.java rename to di-modules/cdi/src/test/java/com/baeldung/test/dependencyinjection/TimeLoggerUnitTest.java diff --git a/dagger/README.md b/di-modules/dagger/README.md similarity index 100% rename from dagger/README.md rename to di-modules/dagger/README.md diff --git a/dagger/pom.xml b/di-modules/dagger/pom.xml similarity index 96% rename from dagger/pom.xml rename to di-modules/dagger/pom.xml index 304b0e428e..59811c7c86 100644 --- a/dagger/pom.xml +++ b/di-modules/dagger/pom.xml @@ -8,7 +8,7 @@ com.baeldung - parent-modules + di-modules 1.0.0-SNAPSHOT diff --git a/dagger/src/main/java/com/baeldung/dagger/intro/Brand.java b/di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Brand.java similarity index 100% rename from dagger/src/main/java/com/baeldung/dagger/intro/Brand.java rename to di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Brand.java diff --git a/dagger/src/main/java/com/baeldung/dagger/intro/Car.java b/di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Car.java similarity index 100% rename from dagger/src/main/java/com/baeldung/dagger/intro/Car.java rename to di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Car.java diff --git a/dagger/src/main/java/com/baeldung/dagger/intro/Engine.java b/di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Engine.java similarity index 100% rename from dagger/src/main/java/com/baeldung/dagger/intro/Engine.java rename to di-modules/dagger/src/main/java/com/baeldung/dagger/intro/Engine.java diff --git a/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesComponent.java b/di-modules/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesComponent.java similarity index 100% rename from dagger/src/main/java/com/baeldung/dagger/intro/VehiclesComponent.java rename to di-modules/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesComponent.java diff --git a/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesModule.java b/di-modules/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesModule.java similarity index 100% rename from dagger/src/main/java/com/baeldung/dagger/intro/VehiclesModule.java rename to di-modules/dagger/src/main/java/com/baeldung/dagger/intro/VehiclesModule.java diff --git a/dagger/src/main/resources/logback.xml b/di-modules/dagger/src/main/resources/logback.xml similarity index 100% rename from dagger/src/main/resources/logback.xml rename to di-modules/dagger/src/main/resources/logback.xml diff --git a/dagger/src/test/java/com/baeldung/dagger/intro/DaggerUnitTest.java b/di-modules/dagger/src/test/java/com/baeldung/dagger/intro/DaggerUnitTest.java similarity index 100% rename from dagger/src/test/java/com/baeldung/dagger/intro/DaggerUnitTest.java rename to di-modules/dagger/src/test/java/com/baeldung/dagger/intro/DaggerUnitTest.java diff --git a/flyway-cdi-extension/README.md b/di-modules/flyway-cdi-extension/README.md similarity index 100% rename from flyway-cdi-extension/README.md rename to di-modules/flyway-cdi-extension/README.md diff --git a/flyway-cdi-extension/pom.xml b/di-modules/flyway-cdi-extension/pom.xml similarity index 95% rename from flyway-cdi-extension/pom.xml rename to di-modules/flyway-cdi-extension/pom.xml index 3d52ff0e36..0865ae0834 100644 --- a/flyway-cdi-extension/pom.xml +++ b/di-modules/flyway-cdi-extension/pom.xml @@ -4,12 +4,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 flyway-cdi-extension - 1.0-SNAPSHOT flyway-cdi-extension com.baeldung - parent-modules + di-modules 1.0.0-SNAPSHOT diff --git a/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayExtension.java b/di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayExtension.java similarity index 100% rename from flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayExtension.java rename to di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayExtension.java diff --git a/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayType.java b/di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayType.java similarity index 100% rename from flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayType.java rename to di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/FlywayType.java diff --git a/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/MainApp.java b/di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/MainApp.java similarity index 100% rename from flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/MainApp.java rename to di-modules/flyway-cdi-extension/src/main/java/com/baeldung/cdi/extension/MainApp.java diff --git a/flyway-cdi-extension/src/main/resources/META-INF/beans.xml b/di-modules/flyway-cdi-extension/src/main/resources/META-INF/beans.xml similarity index 100% rename from flyway-cdi-extension/src/main/resources/META-INF/beans.xml rename to di-modules/flyway-cdi-extension/src/main/resources/META-INF/beans.xml diff --git a/flyway-cdi-extension/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/di-modules/flyway-cdi-extension/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension similarity index 100% rename from flyway-cdi-extension/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension rename to di-modules/flyway-cdi-extension/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension diff --git a/flyway-cdi-extension/src/main/resources/db/migration/V1__Create_person_table.sql b/di-modules/flyway-cdi-extension/src/main/resources/db/migration/V1__Create_person_table.sql similarity index 100% rename from flyway-cdi-extension/src/main/resources/db/migration/V1__Create_person_table.sql rename to di-modules/flyway-cdi-extension/src/main/resources/db/migration/V1__Create_person_table.sql diff --git a/flyway-cdi-extension/src/main/resources/db/migration/V2__Add_people.sql b/di-modules/flyway-cdi-extension/src/main/resources/db/migration/V2__Add_people.sql similarity index 100% rename from flyway-cdi-extension/src/main/resources/db/migration/V2__Add_people.sql rename to di-modules/flyway-cdi-extension/src/main/resources/db/migration/V2__Add_people.sql diff --git a/guice/README.md b/di-modules/guice/README.md similarity index 100% rename from guice/README.md rename to di-modules/guice/README.md diff --git a/guice/pom.xml b/di-modules/guice/pom.xml similarity index 85% rename from guice/pom.xml rename to di-modules/guice/pom.xml index 2d968cdfc7..a28dbe5297 100644 --- a/guice/pom.xml +++ b/di-modules/guice/pom.xml @@ -5,13 +5,12 @@ 4.0.0 com.baeldung.examples.guice guice - 1.0-SNAPSHOT guice jar com.baeldung - parent-modules + di-modules 1.0.0-SNAPSHOT @@ -24,7 +23,7 @@ - 4.1.0 + 5.0.1 \ No newline at end of file diff --git a/guice/src/main/java/com/baeldung/examples/RunGuice.java b/di-modules/guice/src/main/java/com/baeldung/examples/RunGuice.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/RunGuice.java rename to di-modules/guice/src/main/java/com/baeldung/examples/RunGuice.java diff --git a/guice/src/main/java/com/baeldung/examples/common/Account.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/Account.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/Account.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/Account.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AccountService.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AccountService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AccountService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AccountService.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AccountServiceImpl.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AccountServiceImpl.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AccountServiceImpl.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AccountServiceImpl.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AudioBookService.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AudioBookService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AudioBookService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AudioBookService.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AudioBookServiceImpl.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AudioBookServiceImpl.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AudioBookServiceImpl.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AudioBookServiceImpl.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AuthorService.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AuthorService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AuthorService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AuthorService.java diff --git a/guice/src/main/java/com/baeldung/examples/common/AuthorServiceImpl.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/AuthorServiceImpl.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/AuthorServiceImpl.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/AuthorServiceImpl.java diff --git a/guice/src/main/java/com/baeldung/examples/common/BookService.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/BookService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/BookService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/BookService.java diff --git a/guice/src/main/java/com/baeldung/examples/common/BookServiceImpl.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/BookServiceImpl.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/BookServiceImpl.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/BookServiceImpl.java diff --git a/guice/src/main/java/com/baeldung/examples/common/PersonDao.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/PersonDao.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/PersonDao.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/PersonDao.java diff --git a/guice/src/main/java/com/baeldung/examples/common/PersonDaoImpl.java b/di-modules/guice/src/main/java/com/baeldung/examples/common/PersonDaoImpl.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/common/PersonDaoImpl.java rename to di-modules/guice/src/main/java/com/baeldung/examples/common/PersonDaoImpl.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/Communication.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/Communication.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/Communication.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/Communication.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/Foo.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/Foo.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/Foo.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/Foo.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/FooProcessor.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/FooProcessor.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/FooProcessor.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/FooProcessor.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/GuicePersonService.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/GuicePersonService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/GuicePersonService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/GuicePersonService.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/GuiceUserService.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/GuiceUserService.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/GuiceUserService.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/GuiceUserService.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/Person.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/Person.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/Person.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/Person.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java diff --git a/guice/src/main/java/com/baeldung/examples/guice/modules/GuiceModule.java b/di-modules/guice/src/main/java/com/baeldung/examples/guice/modules/GuiceModule.java similarity index 100% rename from guice/src/main/java/com/baeldung/examples/guice/modules/GuiceModule.java rename to di-modules/guice/src/main/java/com/baeldung/examples/guice/modules/GuiceModule.java diff --git a/guice/src/main/resources/logback.xml b/di-modules/guice/src/main/resources/logback.xml similarity index 100% rename from guice/src/main/resources/logback.xml rename to di-modules/guice/src/main/resources/logback.xml diff --git a/guice/src/test/java/com/baeldung/examples/GuiceUnitTest.java b/di-modules/guice/src/test/java/com/baeldung/examples/GuiceUnitTest.java similarity index 100% rename from guice/src/test/java/com/baeldung/examples/GuiceUnitTest.java rename to di-modules/guice/src/test/java/com/baeldung/examples/GuiceUnitTest.java diff --git a/di-modules/pom.xml b/di-modules/pom.xml new file mode 100644 index 0000000000..e6c86d48e6 --- /dev/null +++ b/di-modules/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + di-modules + di-modules + pom + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + + cdi + dagger + flyway-cdi-extension + guice + + + \ No newline at end of file diff --git a/discord4j/pom.xml b/discord4j/pom.xml index e15bd47583..3ea85c05c7 100644 --- a/discord4j/pom.xml +++ b/discord4j/pom.xml @@ -53,19 +53,10 @@ org.springframework.boot spring-boot-maven-plugin - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - 1.8 3.1.1 diff --git a/docker-modules/docker-caching/multi-module-caching/pom.xml b/docker-modules/docker-caching/multi-module-caching/pom.xml index f85f00a28d..94a370453c 100644 --- a/docker-modules/docker-caching/multi-module-caching/pom.xml +++ b/docker-modules/docker-caching/multi-module-caching/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 multi-module-caching @@ -25,6 +25,7 @@ + UTF-8 1.8 31.1-jre diff --git a/docker-modules/docker-caching/pom.xml b/docker-modules/docker-caching/pom.xml index 6ee7bfc442..25572dfe4f 100644 --- a/docker-modules/docker-caching/pom.xml +++ b/docker-modules/docker-caching/pom.xml @@ -17,4 +17,5 @@ single-module-caching multi-module-caching - + + \ 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 aa9720a273..4a4e53f1d3 100644 --- a/docker-modules/docker-caching/single-module-caching/pom.xml +++ b/docker-modules/docker-caching/single-module-caching/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 com.baeldung single-module-caching @@ -48,6 +48,7 @@ 8 8 + UTF-8 31.1-jre diff --git a/docker-modules/docker-compose-2/README.md b/docker-modules/docker-compose-2/README.md new file mode 100644 index 0000000000..353b85f154 --- /dev/null +++ b/docker-modules/docker-compose-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles: +- [Communicating With Docker Containers on the Same Machine](https://www.baeldung.com/ops/docker-communicating-with-containers-on-same-machine) diff --git a/docker-modules/docker-compose-2/communication_same_machine/Dockerfile b/docker-modules/docker-compose-2/communication_same_machine/Dockerfile new file mode 100644 index 0000000000..a0c4ebe59a --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine:latest +MAINTAINER baeldung.com +RUN apk update && apk add iputils && apk add bash && apk add curl \ No newline at end of file diff --git a/docker-modules/docker-compose-2/communication_same_machine/Dockerfile.node b/docker-modules/docker-compose-2/communication_same_machine/Dockerfile.node new file mode 100644 index 0000000000..6d8f0eff81 --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/Dockerfile.node @@ -0,0 +1,7 @@ +FROM node:8.16.1-alpine +WORKDIR /app +COPY host_docker_internal/package.json /app +COPY host_docker_internal/index.js /app +RUN npm install +CMD node index.js +EXPOSE 8080 \ No newline at end of file diff --git a/docker-modules/docker-compose-2/communication_same_machine/dns/docker-compose.yml b/docker-modules/docker-compose-2/communication_same_machine/dns/docker-compose.yml new file mode 100644 index 0000000000..0a06993241 --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/dns/docker-compose.yml @@ -0,0 +1,20 @@ +services: + alpine-app-1: + container_name: alpine-app-1 + image: alpine-app-1 + build: + context: .. + dockerfile: Dockerfile + tty: true + ports: + - 8081:8081 + + alpine-app-2: + container_name: alpine-app-2 + image: alpine-app-2 + build: + context: .. + dockerfile: Dockerfile + tty: true + ports: + - 8080:8080 diff --git a/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/docker-compose.yml b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/docker-compose.yml new file mode 100644 index 0000000000..8e7174a9a1 --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/docker-compose.yml @@ -0,0 +1,29 @@ +services: + alpine-app-1: + container_name: alpine-app-1 + extra_hosts: # for linux hosts since version 20.10 + - host.docker.internal:host-gateway + build: + context: .. + dockerfile: Dockerfile + image: alpine-app-1 + tty: true + networks: + - first-network + + node-app: + container_name: node-app + build: + context: .. + dockerfile: Dockerfile.node + image: node-app + ports: + - 8080:8080 + networks: + - second-network + +networks: + first-network: + driver: bridge + second-network: + driver: bridge \ No newline at end of file diff --git a/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/index.js b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/index.js new file mode 100644 index 0000000000..cefae028e5 --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/index.js @@ -0,0 +1,10 @@ +var express = require('express') +var app = express() + +app.get('/', function (req, res) { + res.send('Hello World!') +}) + +app.listen(8080, function () { + console.log('app listening on port 8080!') +}) \ No newline at end of file diff --git a/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/package.json b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/package.json new file mode 100644 index 0000000000..cde98b1cfd --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/host_docker_internal/package.json @@ -0,0 +1,14 @@ +{ + "name": "host_docker_internal", + "version": "1.0.0", + "description": "node js app", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Baeldung", + "license": "ISC", + "dependencies": { + "express": "^4.18.2" + } +} diff --git a/docker-modules/docker-compose-2/communication_same_machine/static_ip_bridge/docker-compose.yml b/docker-modules/docker-compose-2/communication_same_machine/static_ip_bridge/docker-compose.yml new file mode 100644 index 0000000000..0193bd72fb --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/static_ip_bridge/docker-compose.yml @@ -0,0 +1,34 @@ +services: + alpine-app-1: + container_name: alpine-app-1 + build: + context: .. + dockerfile: Dockerfile + image: alpine-app-1 + tty: true + ports: + - 8080:8080 + networks: + network-example: + ipv4_address: 10.5.0.2 + + alpine-app-2: + container_name: alpine-app-2 + build: + context: .. + dockerfile: Dockerfile + image: alpine-app-2 + tty: true + ports: + - 8081:8081 + networks: + network-example: + ipv4_address: 10.5.0.3 + +networks: + network-example: + driver: bridge + ipam: + config: + - subnet: 10.5.0.0/16 + gateway: 10.5.0.1 \ No newline at end of file diff --git a/docker-modules/docker-compose-2/communication_same_machine/static_ip_macvlan/docker-compose.yml b/docker-modules/docker-compose-2/communication_same_machine/static_ip_macvlan/docker-compose.yml new file mode 100644 index 0000000000..cef1a0b5cb --- /dev/null +++ b/docker-modules/docker-compose-2/communication_same_machine/static_ip_macvlan/docker-compose.yml @@ -0,0 +1,36 @@ +services: + alpine-app-1: + container_name: alpine-app-1 + build: + context: .. + dockerfile: Dockerfile + image: alpine-app-1 + tty: true + ports: + - 8080:8080 + networks: + network-example: + ipv4_address: 192.168.2.2 + + alpine-app-2: + container_name: alpine-app-2 + build: + context: .. + dockerfile: Dockerfile + image: alpine-app-2 + tty: true + ports: + - 8081:8081 + networks: + network-example: + ipv4_address: 192.168.2.3 + +networks: + network-example: + driver: macvlan + driver_opts: + parent: enp0s3 + ipam: + config: + - subnet: 192.168.2.0/24 + gateway: 192.168.2.1 \ No newline at end of file diff --git a/docker-modules/docker-compose-2/pom.xml b/docker-modules/docker-compose-2/pom.xml new file mode 100644 index 0000000000..851742309d --- /dev/null +++ b/docker-modules/docker-compose-2/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + docker-compose-2 + Demo project for Spring Boot and Docker - Module docker-compose-2 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + \ No newline at end of file diff --git a/docker-modules/pom.xml b/docker-modules/pom.xml index 89dbf80408..1a87fa5d1c 100644 --- a/docker-modules/pom.xml +++ b/docker-modules/pom.xml @@ -18,6 +18,7 @@ docker-caching docker-compose + docker-compose-2 docker-containers docker-images docker-spring-boot @@ -29,4 +30,4 @@ 11 - + \ No newline at end of file diff --git a/drools/pom.xml b/drools/pom.xml index daaf1fa8a7..12aaf1318a 100644 --- a/drools/pom.xml +++ b/drools/pom.xml @@ -8,9 +8,8 @@ com.baeldung - parent-spring-4 - 0.0.1-SNAPSHOT - ../parent-spring-4 + parent-modules + 1.0.0-SNAPSHOT @@ -57,10 +56,10 @@ - 4.4.6 - 7.4.1.Final - 3.13 - 7.10.0.Final + 4.4.16 + 8.32.0.Final + 5.2.3 + 8.32.0.Final - \ No newline at end of file + diff --git a/drools/src/main/java/com/baeldung/drools/backward_chaining/BackwardChaining.java b/drools/src/main/java/com/baeldung/drools/backward_chaining/BackwardChaining.java index 6f15ee510b..3baabbeb0f 100644 --- a/drools/src/main/java/com/baeldung/drools/backward_chaining/BackwardChaining.java +++ b/drools/src/main/java/com/baeldung/drools/backward_chaining/BackwardChaining.java @@ -11,7 +11,6 @@ public class BackwardChaining { Result result = new BackwardChaining().backwardChaining(); System.out.println(result.getValue()); result.getFacts() - .stream() .forEach(System.out::println); } 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 cf5d56f246..bbc1f3170a 100644 --- a/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java +++ b/drools/src/main/java/com/baeldung/drools/config/DroolsBeanFactory.java @@ -10,26 +10,25 @@ 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.io.IOException; 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 KieServices kieServices = KieServices.Factory.get(); - private KieFileSystem getKieFileSystem() throws IOException{ + private KieFileSystem getKieFileSystem() { KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); - List rules=Arrays.asList("BackwardChaining.drl","SuggestApplicant.drl","Product_rules.xls"); - for(String rule:rules){ + List rules = Arrays.asList("BackwardChaining.drl", "SuggestApplicant.drl", "Product_rules.xls"); + for(String rule:rules) { kieFileSystem.write(ResourceFactory.newClassPathResource(rule)); } return kieFileSystem; } - public KieContainer getKieContainer() throws IOException { + public KieContainer getKieContainer() { getKieRepository(); KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem()); @@ -44,14 +43,10 @@ public class DroolsBeanFactory { private void getKieRepository() { final KieRepository kieRepository = kieServices.getRepository(); - kieRepository.addKieModule(new KieModule() { - public ReleaseId getReleaseId() { - return kieRepository.getDefaultReleaseId(); - } - }); + kieRepository.addKieModule(kieRepository::getDefaultReleaseId); } - public KieSession getKieSession(){ + public KieSession getKieSession() { getKieRepository(); KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); @@ -59,7 +54,6 @@ public class DroolsBeanFactory { kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/SuggestApplicant.drl")); kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/Product_rules.xls")); - KieBuilder kb = kieServices.newKieBuilder(kieFileSystem); kb.buildAll(); KieModule kieModule = kb.getKieModule(); @@ -67,7 +61,6 @@ public class DroolsBeanFactory { KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId()); return kContainer.newKieSession(); - } public KieSession getKieSession(Resource dt) { diff --git a/drools/src/main/java/com/baeldung/drools/optaplanner/CourseSchedule.java b/drools/src/main/java/com/baeldung/drools/optaplanner/CourseSchedule.java index 7b2ba117a1..d0ae5318b9 100644 --- a/drools/src/main/java/com/baeldung/drools/optaplanner/CourseSchedule.java +++ b/drools/src/main/java/com/baeldung/drools/optaplanner/CourseSchedule.java @@ -6,7 +6,7 @@ import java.util.List; import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty; import org.optaplanner.core.api.domain.solution.PlanningScore; import org.optaplanner.core.api.domain.solution.PlanningSolution; -import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty; +import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; import org.slf4j.Logger; diff --git a/drools/src/main/java/com/baeldung/drools/optaplanner/ScoreCalculator.java b/drools/src/main/java/com/baeldung/drools/optaplanner/ScoreCalculator.java index 86501cdccd..c9d2b4df99 100644 --- a/drools/src/main/java/com/baeldung/drools/optaplanner/ScoreCalculator.java +++ b/drools/src/main/java/com/baeldung/drools/optaplanner/ScoreCalculator.java @@ -2,14 +2,13 @@ package com.baeldung.drools.optaplanner; import java.util.HashSet; -import org.optaplanner.core.api.score.Score; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; -import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator; +import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; -public class ScoreCalculator implements EasyScoreCalculator { +public class ScoreCalculator implements EasyScoreCalculator { @Override - public Score calculateScore(CourseSchedule courseSchedule) { + public HardSoftScore calculateScore(CourseSchedule courseSchedule) { int hardScore = 0; int softScore = 0; @@ -27,6 +26,6 @@ public class ScoreCalculator implements EasyScoreCalculator { } } - return HardSoftScore.valueOf(hardScore, softScore); + return HardSoftScore.of(hardScore, softScore); } } diff --git a/drools/src/main/java/com/baeldung/drools/service/ApplicantService.java b/drools/src/main/java/com/baeldung/drools/service/ApplicantService.java index f74298ef05..06f84358b0 100644 --- a/drools/src/main/java/com/baeldung/drools/service/ApplicantService.java +++ b/drools/src/main/java/com/baeldung/drools/service/ApplicantService.java @@ -3,19 +3,20 @@ package com.baeldung.drools.service; import com.baeldung.drools.config.DroolsBeanFactory; import com.baeldung.drools.model.Applicant; import com.baeldung.drools.model.SuggestedRole; -import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; -import java.io.IOException; - public class ApplicantService { - KieSession kieSession=new DroolsBeanFactory().getKieSession(); + KieSession kieSession = new DroolsBeanFactory().getKieSession(); - public SuggestedRole suggestARoleForApplicant(Applicant applicant,SuggestedRole suggestedRole) throws IOException { - kieSession.insert(applicant); - kieSession.setGlobal("suggestedRole",suggestedRole); - kieSession.fireAllRules(); + public SuggestedRole suggestARoleForApplicant(Applicant applicant,SuggestedRole suggestedRole) { + try { + kieSession.insert(applicant); + kieSession.setGlobal("suggestedRole", suggestedRole); + kieSession.fireAllRules(); + } finally { + kieSession.dispose(); + } System.out.println(suggestedRole.getRole()); return suggestedRole; diff --git a/drools/src/main/java/com/baeldung/drools/service/ProductService.java b/drools/src/main/java/com/baeldung/drools/service/ProductService.java index be5e43ed7b..401f5a600f 100644 --- a/drools/src/main/java/com/baeldung/drools/service/ProductService.java +++ b/drools/src/main/java/com/baeldung/drools/service/ProductService.java @@ -2,18 +2,21 @@ package com.baeldung.drools.service; import com.baeldung.drools.config.DroolsBeanFactory; import com.baeldung.drools.model.Product; -import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class ProductService { - private KieSession kieSession=new DroolsBeanFactory().getKieSession(); + private KieSession kieSession = new DroolsBeanFactory().getKieSession(); public Product applyLabelToProduct(Product product){ - kieSession.insert(product); - kieSession.fireAllRules(); + try { + kieSession.insert(product); + kieSession.fireAllRules(); + } finally { + kieSession.dispose(); + } System.out.println(product.getLabel()); - return product; + return product; } diff --git a/drools/src/main/resources/courseScheduleSolverConfigDrools.xml b/drools/src/main/resources/courseScheduleSolverConfigDrools.xml index 7cf95fdcd3..74112d9c7d 100644 --- a/drools/src/main/resources/courseScheduleSolverConfigDrools.xml +++ b/drools/src/main/resources/courseScheduleSolverConfigDrools.xml @@ -1,7 +1,9 @@ - - + + com.baeldung.drools.optaplanner.CourseSchedule + com.baeldung.drools.optaplanner.Lecture + courseSchedule.drl diff --git a/drools/src/main/resources/courseScheduleSolverConfiguration.xml b/drools/src/main/resources/courseScheduleSolverConfiguration.xml index dfedb8f2fd..4214b0943a 100644 --- a/drools/src/main/resources/courseScheduleSolverConfiguration.xml +++ b/drools/src/main/resources/courseScheduleSolverConfiguration.xml @@ -1,7 +1,9 @@ - + com.baeldung.drools.optaplanner.CourseSchedule + com.baeldung.drools.optaplanner.Lecture + com.baeldung.drools.optaplanner.ScoreCalculator diff --git a/drools/src/test/java/com/baeldung/drools/optaplanner/OptaPlannerUnitTest.java b/drools/src/test/java/com/baeldung/drools/optaplanner/OptaPlannerUnitTest.java index 1880e30b86..36b24349c7 100644 --- a/drools/src/test/java/com/baeldung/drools/optaplanner/OptaPlannerUnitTest.java +++ b/drools/src/test/java/com/baeldung/drools/optaplanner/OptaPlannerUnitTest.java @@ -21,13 +21,12 @@ public class OptaPlannerUnitTest { unsolvedCourseSchedule.getLectureList().add(new Lecture()); } - unsolvedCourseSchedule.getPeriodList().addAll(Arrays.asList(new Integer[] { 1, 2, 3 })); - unsolvedCourseSchedule.getRoomList().addAll(Arrays.asList(new Integer[] { 1, 2 })); + unsolvedCourseSchedule.getPeriodList().addAll(Arrays.asList(1, 2, 3)); + unsolvedCourseSchedule.getRoomList().addAll(Arrays.asList(1, 2)); } @Test public void test_whenCustomJavaSolver() { - SolverFactory solverFactory = SolverFactory.createFromXmlResource("courseScheduleSolverConfiguration.xml"); Solver solver = solverFactory.buildSolver(); CourseSchedule solvedCourseSchedule = solver.solve(unsolvedCourseSchedule); @@ -38,7 +37,6 @@ public class OptaPlannerUnitTest { @Test public void test_whenDroolsSolver() { - SolverFactory solverFactory = SolverFactory.createFromXmlResource("courseScheduleSolverConfigDrools.xml"); Solver solver = solverFactory.buildSolver(); CourseSchedule solvedCourseSchedule = solver.solve(unsolvedCourseSchedule); diff --git a/feign/README.md b/feign/README.md index 2dea14ca52..3e733448fb 100644 --- a/feign/README.md +++ b/feign/README.md @@ -7,3 +7,9 @@ This module contains articles about Feign - [Intro to Feign](https://www.baeldung.com/intro-to-feign) - [Retrying Feign Calls](https://www.baeldung.com/feign-retry) - [Setting Request Headers Using Feign](https://www.baeldung.com/java-feign-request-headers) +- [File Upload With Open Feign](https://www.baeldung.com/java-feign-file-upload) +- [Feign Logging Configuration](https://www.baeldung.com/java-feign-logging) +- [Retrieve Original Message From Feign ErrorDecoder](https://www.baeldung.com/feign-retrieve-original-message) +- [RequestLine with Feign Client](https://www.baeldung.com/feign-requestline) +- [Propagating Exceptions With OpenFeign and Spring](https://www.baeldung.com/spring-openfeign-propagate-exception) +- [Post form-url-encoded Data with Spring Cloud Feign](https://www.baeldung.com/spring-cloud-post-form-url-encoded-data) diff --git a/feign/pom.xml b/feign/pom.xml index 369fa00137..7338cf7508 100644 --- a/feign/pom.xml +++ b/feign/pom.xml @@ -64,6 +64,22 @@ spring-boot-starter-test test + + io.github.openfeign.form + feign-form-spring + ${feign.form.spring.version} + + + org.springframework.cloud + spring-cloud-starter-openfeign + ${spring.cloud.openfeign.version} + + + com.github.tomakehurst + wiremock-jre8 + ${wire.mock.version} + test + @@ -116,9 +132,11 @@ - 1.8 11.8 1.6.3 + 3.8.0 + 3.1.2 + 2.33.2 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java b/feign/src/main/java/com/baeldung/core/ExampleApplication.java similarity index 90% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java rename to feign/src/main/java/com/baeldung/core/ExampleApplication.java index c7f07f6667..391e808ede 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java +++ b/feign/src/main/java/com/baeldung/core/ExampleApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign; +package com.baeldung.core; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/EmployeeClient.java b/feign/src/main/java/com/baeldung/core/client/EmployeeClient.java similarity index 73% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/EmployeeClient.java rename to feign/src/main/java/com/baeldung/core/client/EmployeeClient.java index 569401bdcf..0ff8637a94 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/EmployeeClient.java +++ b/feign/src/main/java/com/baeldung/core/client/EmployeeClient.java @@ -1,6 +1,7 @@ -package com.baeldung.cloud.openfeign.client; +package com.baeldung.core.client; + +import com.baeldung.core.model.Employee; -import com.baeldung.cloud.openfeign.model.Employee; import feign.Headers; import feign.Param; import feign.RequestLine; diff --git a/feign/src/main/java/com/baeldung/core/client/FormClient.java b/feign/src/main/java/com/baeldung/core/client/FormClient.java new file mode 100644 index 0000000000..074402aef3 --- /dev/null +++ b/feign/src/main/java/com/baeldung/core/client/FormClient.java @@ -0,0 +1,37 @@ +package com.baeldung.core.client; + +import java.util.Map; + +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.support.SpringEncoder; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import com.baeldung.core.defaulterrorhandling.model.FormData; + +import feign.codec.Encoder; +import feign.form.spring.SpringFormEncoder; + +@FeignClient(name = "form-client", url = "http://localhost:8085/api", configuration = FormFeignEncoderConfig.class) +public interface FormClient { + + @PostMapping(value = "/form", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + void postFormData(@RequestBody FormData data); + + @PostMapping(value = "/form/map", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + void postFormMapData(Map data); + +} + +class FormFeignEncoderConfig { + + @Bean + public Encoder encoder(ObjectFactory converters) { + return new SpringFormEncoder(new SpringEncoder(converters)); + } + +} \ No newline at end of file diff --git a/feign/src/main/java/com/baeldung/core/client/UserClient.java b/feign/src/main/java/com/baeldung/core/client/UserClient.java new file mode 100644 index 0000000000..a16f924ad5 --- /dev/null +++ b/feign/src/main/java/com/baeldung/core/client/UserClient.java @@ -0,0 +1,13 @@ +package com.baeldung.core.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +import com.baeldung.core.config.FeignConfig; + +@FeignClient(name = "user-client", url="https://jsonplaceholder.typicode.com", configuration = FeignConfig.class) +public interface UserClient { + + @GetMapping(value = "/users") + String getUsers(); +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/FeignConfig.java b/feign/src/main/java/com/baeldung/core/config/FeignConfig.java similarity index 79% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/FeignConfig.java rename to feign/src/main/java/com/baeldung/core/config/FeignConfig.java index d51e97b9e4..43da2fce0e 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/FeignConfig.java +++ b/feign/src/main/java/com/baeldung/core/config/FeignConfig.java @@ -1,7 +1,8 @@ -package com.baeldung.cloud.openfeign.config; +package com.baeldung.core.config; + +import org.springframework.context.annotation.Bean; import feign.Logger; -import org.springframework.context.annotation.Bean; public class FeignConfig { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/EmployeeController.java b/feign/src/main/java/com/baeldung/core/controller/EmployeeController.java similarity index 81% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/EmployeeController.java rename to feign/src/main/java/com/baeldung/core/controller/EmployeeController.java index 65897ad48e..7f7d39240e 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/EmployeeController.java +++ b/feign/src/main/java/com/baeldung/core/controller/EmployeeController.java @@ -1,13 +1,15 @@ -package com.baeldung.cloud.openfeign.controller; +package com.baeldung.core.controller; -import com.baeldung.cloud.openfeign.client.EmployeeClient; -import com.baeldung.cloud.openfeign.model.Employee; -import feign.Feign; -import feign.form.spring.SpringFormEncoder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import com.baeldung.core.client.EmployeeClient; +import com.baeldung.core.model.Employee; + +import feign.Feign; +import feign.form.spring.SpringFormEncoder; + @RestController public class EmployeeController { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClient.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/client/ProductClient.java similarity index 70% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClient.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/client/ProductClient.java index 8a6c5d5846..113051722b 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClient.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/client/ProductClient.java @@ -1,13 +1,13 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.client; - -import com.baeldung.cloud.openfeign.customizederrorhandling.config.FeignConfig; -import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product; +package com.baeldung.core.customizederrorhandling.client; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import com.baeldung.core.customizederrorhandling.config.FeignConfig; +import com.baeldung.core.defaulterrorhandling.model.Product; + @FeignClient(name = "product-client-2", url = "http://localhost:8081/product/", configuration = FeignConfig.class) public interface ProductClient { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/CustomErrorDecoder.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/config/CustomErrorDecoder.java similarity index 65% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/CustomErrorDecoder.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/config/CustomErrorDecoder.java index 3750e6288d..5466b61b3a 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/CustomErrorDecoder.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/config/CustomErrorDecoder.java @@ -1,8 +1,9 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.config; +package com.baeldung.core.customizederrorhandling.config; + +import com.baeldung.core.customizederrorhandling.exception.ProductNotFoundException; +import com.baeldung.core.customizederrorhandling.exception.ProductServiceNotAvailableException; +import com.baeldung.core.exception.BadRequestException; -import com.baeldung.cloud.openfeign.exception.BadRequestException; -import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductNotFoundException; -import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductServiceNotAvailableException; import feign.Response; import feign.codec.ErrorDecoder; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/FeignConfig.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/config/FeignConfig.java similarity index 81% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/FeignConfig.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/config/FeignConfig.java index 5cddd521f1..980b8b5b38 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/config/FeignConfig.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/config/FeignConfig.java @@ -1,8 +1,9 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.config; +package com.baeldung.core.customizederrorhandling.config; + +import org.springframework.context.annotation.Bean; import feign.Logger; import feign.codec.ErrorDecoder; -import org.springframework.context.annotation.Bean; public class FeignConfig { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductController.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/controller/ProductController.java similarity index 52% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductController.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/controller/ProductController.java index 9b7a5aea1d..6d6f784e66 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductController.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/controller/ProductController.java @@ -1,12 +1,13 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.controller; +package com.baeldung.core.customizederrorhandling.controller; -import com.baeldung.cloud.openfeign.customizederrorhandling.client.ProductClient; - - -import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.baeldung.core.customizederrorhandling.client.ProductClient; +import com.baeldung.core.defaulterrorhandling.model.Product; @RestController("product_controller2") @RequestMapping(value = "myapp2") diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ErrorResponse.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ErrorResponse.java similarity index 94% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ErrorResponse.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ErrorResponse.java index c72e3db68b..6e739e5e40 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ErrorResponse.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ErrorResponse.java @@ -1,10 +1,11 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.exception; +package com.baeldung.core.customizederrorhandling.exception; + +import java.util.Date; + +import org.springframework.http.HttpStatus; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; -import org.springframework.http.HttpStatus; - -import java.util.Date; public class ErrorResponse { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductExceptionHandler.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductExceptionHandler.java similarity index 92% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductExceptionHandler.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductExceptionHandler.java index 2ed709bc34..c83d917570 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductExceptionHandler.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductExceptionHandler.java @@ -1,6 +1,5 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.exception; +package com.baeldung.core.customizederrorhandling.exception; -import com.baeldung.cloud.openfeign.exception.BadRequestException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductNotFoundException.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductNotFoundException.java similarity index 68% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductNotFoundException.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductNotFoundException.java index 337cb89f7b..fa993ce700 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductNotFoundException.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductNotFoundException.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.exception; +package com.baeldung.core.customizederrorhandling.exception; public class ProductNotFoundException extends RuntimeException { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductServiceNotAvailableException.java b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductServiceNotAvailableException.java similarity index 70% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductServiceNotAvailableException.java rename to feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductServiceNotAvailableException.java index ce30f8c310..887d2cd91d 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/customizederrorhandling/exception/ProductServiceNotAvailableException.java +++ b/feign/src/main/java/com/baeldung/core/customizederrorhandling/exception/ProductServiceNotAvailableException.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.exception; +package com.baeldung.core.customizederrorhandling.exception; public class ProductServiceNotAvailableException extends RuntimeException { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClient.java b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/client/ProductClient.java similarity index 70% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClient.java rename to feign/src/main/java/com/baeldung/core/defaulterrorhandling/client/ProductClient.java index 2cef3d4238..4eb435331d 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClient.java +++ b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/client/ProductClient.java @@ -1,13 +1,13 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.client; - -import com.baeldung.cloud.openfeign.defaulterrorhandling.config.FeignConfig; -import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product; +package com.baeldung.core.defaulterrorhandling.client; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import com.baeldung.core.defaulterrorhandling.config.FeignConfig; +import com.baeldung.core.defaulterrorhandling.model.Product; + @FeignClient(name = "product-client", url = "http://localhost:8084/product/", configuration = FeignConfig.class) public interface ProductClient { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/config/FeignConfig.java b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/config/FeignConfig.java similarity index 74% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/config/FeignConfig.java rename to feign/src/main/java/com/baeldung/core/defaulterrorhandling/config/FeignConfig.java index f2329ebe0b..cef8cbb6d9 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/config/FeignConfig.java +++ b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/config/FeignConfig.java @@ -1,7 +1,8 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.config; +package com.baeldung.core.defaulterrorhandling.config; + +import org.springframework.context.annotation.Bean; import feign.Logger; -import org.springframework.context.annotation.Bean; public class FeignConfig { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductController.java b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/controller/ProductController.java similarity index 52% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductController.java rename to feign/src/main/java/com/baeldung/core/defaulterrorhandling/controller/ProductController.java index df352f8d52..80f571f29a 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductController.java +++ b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/controller/ProductController.java @@ -1,10 +1,13 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.controller; +package com.baeldung.core.defaulterrorhandling.controller; -import com.baeldung.cloud.openfeign.defaulterrorhandling.client.ProductClient; - -import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.core.defaulterrorhandling.client.ProductClient; +import com.baeldung.core.defaulterrorhandling.model.Product; @RestController("product_controller1") @RequestMapping(value ="myapp1") diff --git a/feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/FormData.java b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/FormData.java new file mode 100644 index 0000000000..6210451f2d --- /dev/null +++ b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/FormData.java @@ -0,0 +1,12 @@ +package com.baeldung.core.defaulterrorhandling.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class FormData { + + int id; + String name; +} diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/model/Product.java b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/Product.java similarity index 82% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/model/Product.java rename to feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/Product.java index 25a1662c99..35d860332e 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/defaulterrorhandling/model/Product.java +++ b/feign/src/main/java/com/baeldung/core/defaulterrorhandling/model/Product.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.model; +package com.baeldung.core.defaulterrorhandling.model; public class Product { diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java b/feign/src/main/java/com/baeldung/core/exception/BadRequestException.java similarity index 75% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java rename to feign/src/main/java/com/baeldung/core/exception/BadRequestException.java index 7c2daf43fe..4553bb5576 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java +++ b/feign/src/main/java/com/baeldung/core/exception/BadRequestException.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.exception; +package com.baeldung.core.exception; public class BadRequestException extends Exception { @@ -15,7 +15,7 @@ public class BadRequestException extends Exception { @Override public String toString() { - return "BadRequestException: " + getMessage(); + return "BadRequestException: "+getMessage(); } } diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java b/feign/src/main/java/com/baeldung/core/exception/NotFoundException.java similarity index 86% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java rename to feign/src/main/java/com/baeldung/core/exception/NotFoundException.java index 19f6204b86..07f4e0862f 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java +++ b/feign/src/main/java/com/baeldung/core/exception/NotFoundException.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.exception; +package com.baeldung.core.exception; public class NotFoundException extends Exception { diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java b/feign/src/main/java/com/baeldung/core/fileupload/config/ExceptionMessage.java similarity index 95% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java rename to feign/src/main/java/com/baeldung/core/fileupload/config/ExceptionMessage.java index 45a555b2ea..8301705ca6 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/ExceptionMessage.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/config/ExceptionMessage.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.fileupload.config; +package com.baeldung.core.fileupload.config; public class ExceptionMessage { private String timestamp; diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java b/feign/src/main/java/com/baeldung/core/fileupload/config/FeignSupportConfig.java similarity index 57% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java rename to feign/src/main/java/com/baeldung/core/fileupload/config/FeignSupportConfig.java index 802077a3d7..c8c9eb1acc 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/config/FeignSupportConfig.java @@ -1,6 +1,5 @@ -package com.baeldung.cloud.openfeign.fileupload.config; +package com.baeldung.core.fileupload.config; -import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.annotation.Bean; @@ -13,12 +12,7 @@ import feign.form.spring.SpringFormEncoder; public class FeignSupportConfig { @Bean public Encoder multipartFormEncoder() { - return new SpringFormEncoder(new SpringEncoder(new ObjectFactory() { - @Override - public HttpMessageConverters getObject() { - return new HttpMessageConverters(new RestTemplate().getMessageConverters()); - } - })); + return new SpringFormEncoder(new SpringEncoder(() -> new HttpMessageConverters(new RestTemplate().getMessageConverters()))); } @Bean diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java b/feign/src/main/java/com/baeldung/core/fileupload/config/RetreiveMessageErrorDecoder.java similarity index 82% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java rename to feign/src/main/java/com/baeldung/core/fileupload/config/RetreiveMessageErrorDecoder.java index 5ebd7b6887..fc2c8da0ed 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/config/RetreiveMessageErrorDecoder.java @@ -1,10 +1,10 @@ -package com.baeldung.cloud.openfeign.fileupload.config; +package com.baeldung.core.fileupload.config; import java.io.IOException; import java.io.InputStream; -import com.baeldung.cloud.openfeign.exception.BadRequestException; -import com.baeldung.cloud.openfeign.exception.NotFoundException; +import com.baeldung.core.exception.BadRequestException; +import com.baeldung.core.exception.NotFoundException; import com.fasterxml.jackson.databind.ObjectMapper; import feign.Response; @@ -12,9 +12,10 @@ import feign.codec.ErrorDecoder; public class RetreiveMessageErrorDecoder implements ErrorDecoder { private final ErrorDecoder errorDecoder = new Default(); + @Override public Exception decode(String methodKey, Response response) { - ExceptionMessage message = null; + ExceptionMessage message; try (InputStream bodyIs = response.body() .asInputStream()) { ObjectMapper mapper = new ObjectMapper(); diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java b/feign/src/main/java/com/baeldung/core/fileupload/controller/FileController.java similarity index 88% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java rename to feign/src/main/java/com/baeldung/core/fileupload/controller/FileController.java index 1ddbfcea81..7ba4746979 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/controller/FileController.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.fileupload.controller; +package com.baeldung.core.fileupload.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; @@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.baeldung.cloud.openfeign.fileupload.service.UploadService; +import com.baeldung.core.fileupload.service.UploadService; @RestController public class FileController { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadClient.java similarity index 85% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java rename to feign/src/main/java/com/baeldung/core/fileupload/service/UploadClient.java index 8f3ef7e421..37b059d642 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadClient.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.fileupload.service; +package com.baeldung.core.fileupload.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; @@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; -import com.baeldung.cloud.openfeign.fileupload.config.FeignSupportConfig; +import com.baeldung.core.fileupload.config.FeignSupportConfig; @FeignClient(name = "file", url = "http://localhost:8081", configuration = FeignSupportConfig.class) public interface UploadClient { diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadResource.java similarity index 75% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java rename to feign/src/main/java/com/baeldung/core/fileupload/service/UploadResource.java index 2d5090897d..9d3d173cd4 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadResource.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.fileupload.service; +package com.baeldung.core.fileupload.service; import org.springframework.web.multipart.MultipartFile; @@ -9,7 +9,7 @@ import feign.Response; public interface UploadResource { - @RequestLine("POST /upload-error") + @RequestLine("POST /upload-file") @Headers("Content-Type: multipart/form-data") Response uploadFile(@Param("file") MultipartFile file); diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadService.java similarity index 62% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java rename to feign/src/main/java/com/baeldung/core/fileupload/service/UploadService.java index 244a5a2168..5176ddf0fa 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java +++ b/feign/src/main/java/com/baeldung/core/fileupload/service/UploadService.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.fileupload.service; +package com.baeldung.core.fileupload.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -13,22 +13,20 @@ public class UploadService { private static final String HTTP_FILE_UPLOAD_URL = "http://localhost:8081"; @Autowired - private FileUploadClientWithFallbackFactory fileUploadClient; - @Autowired - private FileUploadClientWithFallBack fileUploadClientWithFallback; - + private UploadClient client; + public boolean uploadFileWithManualClient(MultipartFile file) { UploadResource fileUploadResource = Feign.builder().encoder(new SpringFormEncoder()) .target(UploadResource.class, HTTP_FILE_UPLOAD_URL); Response response = fileUploadResource.uploadFile(file); return response.status() == 200; } - - public String uploadFileWithFallbackFactory(MultipartFile file) { - return fileUploadClient.fileUpload(file); + + public String uploadFile(MultipartFile file) { + return client.fileUpload(file); } - - public String uploadFileWithFallback(MultipartFile file) { - return fileUploadClientWithFallback.fileUpload(file); + + public String uploadFileError(MultipartFile file) { + return client.fileUpload(file); } } \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Employee.java b/feign/src/main/java/com/baeldung/core/model/Employee.java similarity index 81% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Employee.java rename to feign/src/main/java/com/baeldung/core/model/Employee.java index 7b8ed1232b..7b0c9e1933 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Employee.java +++ b/feign/src/main/java/com/baeldung/core/model/Employee.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign.model; +package com.baeldung.core.model; public class Employee { diff --git a/feign/src/main/resources/application.properties b/feign/src/main/resources/application.properties index a57c6e36a3..e48d5fd65a 100644 --- a/feign/src/main/resources/application.properties +++ b/feign/src/main/resources/application.properties @@ -5,3 +5,5 @@ ws.port.type.name=UsersPort ws.target.namespace=http://www.baeldung.com/springbootsoap/feignclient ws.location.uri=http://localhost:${server.port}/ws/users/ debug=false + +logging.level.com.baeldung.core=DEBUG \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/fileupload.txt b/feign/src/main/resources/fileupload.txt similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/fileupload.txt rename to feign/src/main/resources/fileupload.txt diff --git a/feign/src/main/resources/logback_spring.xml b/feign/src/main/resources/logback_spring.xml new file mode 100644 index 0000000000..2a307a5b27 --- /dev/null +++ b/feign/src/main/resources/logback_spring.xml @@ -0,0 +1,45 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + ${LOGS}/spring-boot-logger.log + + %d %p %C{1.} [%t] %m%n + + + + + ${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log + + + 10MB + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java b/feign/src/test/java/com/baeldung/core/OpenFeignFileUploadLiveTest.java similarity index 55% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java rename to feign/src/test/java/com/baeldung/core/OpenFeignFileUploadLiveTest.java index 6396be2453..f9dc8b13ed 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java +++ b/feign/src/test/java/com/baeldung/core/OpenFeignFileUploadLiveTest.java @@ -1,4 +1,4 @@ -package com.baeldung.cloud.openfeign; +package com.baeldung.core; import java.io.File; import java.io.FileInputStream; @@ -14,11 +14,10 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.multipart.MultipartFile; -import com.baeldung.cloud.openfeign.exception.NotFoundException; -import com.baeldung.cloud.openfeign.fileupload.service.UploadService; +import com.baeldung.core.fileupload.service.UploadService; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = ExampleApplication.class) public class OpenFeignFileUploadLiveTest { @Autowired @@ -26,36 +25,26 @@ public class OpenFeignFileUploadLiveTest { private static String FILE_NAME = "fileupload.txt"; - @Test(expected = NotFoundException.class) - public void whenFileUploadClientFallbackFactory_thenFileUploadError() throws IOException { + @Test + public void whenFeignBuilder_thenFileUploadSuccess() throws IOException { ClassLoader classloader = Thread.currentThread().getContextClassLoader(); File file = new File(classloader.getResource(FILE_NAME).getFile()); Assert.assertTrue(file.exists()); FileInputStream input = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input)); - uploadService.uploadFileWithFallbackFactory(multipartFile); - } - - @Test(expected = NotFoundException.class) - public void whenFileUploadClientFallback_thenFileUploadError() throws IOException { - ClassLoader classloader = Thread.currentThread().getContextClassLoader(); - File file = new File(classloader.getResource(FILE_NAME).getFile()); - Assert.assertTrue(file.exists()); - FileInputStream input = new FileInputStream(file); - MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", - IOUtils.toByteArray(input)); - uploadService.uploadFileWithFallback(multipartFile); + Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile)); } - @Test(expected = NotFoundException.class) - public void whenFileUploadWithMannualClient_thenFileUploadError() throws IOException { + @Test + public void whenAnnotatedFeignClient_thenFileUploadSuccess() throws IOException { ClassLoader classloader = Thread.currentThread().getContextClassLoader(); File file = new File(classloader.getResource(FILE_NAME).getFile()); Assert.assertTrue(file.exists()); FileInputStream input = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input)); - uploadService.uploadFileWithManualClient(multipartFile); + String uploadFile = uploadService.uploadFile(multipartFile); + Assert.assertNotNull(uploadFile); } } diff --git a/feign/src/test/java/com/baeldung/core/client/FormClientUnitTest.java b/feign/src/test/java/com/baeldung/core/client/FormClientUnitTest.java new file mode 100644 index 0000000000..b9c263b60b --- /dev/null +++ b/feign/src/test/java/com/baeldung/core/client/FormClientUnitTest.java @@ -0,0 +1,78 @@ +package com.baeldung.core.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +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.http.HttpStatus; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.core.defaulterrorhandling.model.FormData; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; + +import lombok.extern.slf4j.Slf4j; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +@Slf4j +class FormClientUnitTest { + + private static WireMockServer wireMockServer; + + @Autowired + FormClient formClient; + + @BeforeAll + public static void startWireMockServer() { + wireMockServer = new WireMockServer(8085); + configureFor("localhost", 8085); + wireMockServer.start(); + + } + + @AfterAll + public static void stopWireMockServer() { + wireMockServer.stop(); + } + + @Test + public void givenFormData_whenPostFormDataCalled_thenReturnSuccess() { + FormData formData = new FormData(1, "baeldung"); + stubFor(WireMock.post(urlEqualTo("/api/form")) + .willReturn(aResponse().withStatus(HttpStatus.OK.value()))); + + formClient.postFormData(formData); + wireMockServer.verify(postRequestedFor(urlPathEqualTo("/api/form")) + .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded; charset=UTF-8")) + .withRequestBody(equalTo("name=baeldung&id=1"))); + } + + @Test + public void givenFormMap_whenPostFormMapDataCalled_thenReturnSuccess() { + Map mapData = new HashMap<>(); + mapData.put("name", "baeldung"); + mapData.put("id", "1"); + stubFor(WireMock.post(urlEqualTo("/api/form/map")) + .willReturn(aResponse().withStatus(HttpStatus.OK.value()))); + + formClient.postFormMapData(mapData); + wireMockServer.verify(postRequestedFor(urlPathEqualTo("/api/form/map")) + .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded; charset=UTF-8")) + .withRequestBody(equalTo("name=baeldung&id=1"))); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java b/feign/src/test/java/com/baeldung/core/customizederrorhandling/client/ProductClientUnitTest.java similarity index 69% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java rename to feign/src/test/java/com/baeldung/core/customizederrorhandling/client/ProductClientUnitTest.java index 7cf2a12692..ed5f18eb3f 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java +++ b/feign/src/test/java/com/baeldung/core/customizederrorhandling/client/ProductClientUnitTest.java @@ -1,8 +1,12 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.client; +package com.baeldung.core.customizederrorhandling.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.junit.Assert.assertThrows; -import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductNotFoundException; -import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductServiceNotAvailableException; -import com.github.tomakehurst.wiremock.WireMockServer; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -11,11 +15,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static org.junit.Assert.assertThrows; +import com.baeldung.core.ExampleApplication; +import com.baeldung.core.customizederrorhandling.exception.ProductNotFoundException; +import com.baeldung.core.customizederrorhandling.exception.ProductServiceNotAvailableException; +import com.github.tomakehurst.wiremock.WireMockServer; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = ExampleApplication.class) public class ProductClientUnitTest { @Autowired diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java b/feign/src/test/java/com/baeldung/core/customizederrorhandling/controller/ProductControllerUnitTest.java similarity index 88% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java rename to feign/src/test/java/com/baeldung/core/customizederrorhandling/controller/ProductControllerUnitTest.java index cc9d029e07..04fd68d3e4 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java +++ b/feign/src/test/java/com/baeldung/core/customizederrorhandling/controller/ProductControllerUnitTest.java @@ -1,10 +1,13 @@ -package com.baeldung.cloud.openfeign.customizederrorhandling.controller; +package com.baeldung.core.customizederrorhandling.controller; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.junit.Assert.assertEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.baeldung.cloud.openfeign.customizederrorhandling.client.ProductClient; -import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ErrorResponse; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -18,10 +21,11 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static org.junit.Assert.assertEquals; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.baeldung.core.customizederrorhandling.client.ProductClient; +import com.baeldung.core.customizederrorhandling.exception.ErrorResponse; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; @RunWith(SpringRunner.class) diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/client/ProductClientUnitTest.java similarity index 81% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java rename to feign/src/test/java/com/baeldung/core/defaulterrorhandling/client/ProductClientUnitTest.java index 4dda2bbe15..8a9fa94074 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java +++ b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/client/ProductClientUnitTest.java @@ -1,8 +1,13 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.client; +package com.baeldung.core.defaulterrorhandling.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; -import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product; -import com.github.tomakehurst.wiremock.WireMockServer; -import feign.FeignException; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -12,12 +17,14 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.test.context.junit4.SpringRunner; -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import com.baeldung.core.ExampleApplication; +import com.baeldung.core.defaulterrorhandling.model.Product; +import com.github.tomakehurst.wiremock.WireMockServer; + +import feign.FeignException; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = ExampleApplication.class) public class ProductClientUnitTest { @Autowired diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/ProductControllerUnitTest.java similarity index 85% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java rename to feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/ProductControllerUnitTest.java index f6ec7c3310..798ee9035c 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java +++ b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/ProductControllerUnitTest.java @@ -1,8 +1,13 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.controller; +package com.baeldung.core.defaulterrorhandling.controller; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.baeldung.cloud.openfeign.defaulterrorhandling.client.ProductClient; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -16,10 +21,9 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import com.baeldung.core.defaulterrorhandling.client.ProductClient; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; @RunWith(SpringRunner.class) @WebMvcTest(ProductController.class) diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/TestControllerAdvice.java b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/TestControllerAdvice.java similarity index 88% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/TestControllerAdvice.java rename to feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/TestControllerAdvice.java index 0c7ed86b7c..dfd82ed07d 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/TestControllerAdvice.java +++ b/feign/src/test/java/com/baeldung/core/defaulterrorhandling/controller/TestControllerAdvice.java @@ -1,11 +1,12 @@ -package com.baeldung.cloud.openfeign.defaulterrorhandling.controller; +package com.baeldung.core.defaulterrorhandling.controller; -import feign.FeignException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import feign.FeignException; + @RestControllerAdvice public class TestControllerAdvice { diff --git a/gcp-firebase/.gitignore b/gcp-firebase/.gitignore new file mode 100644 index 0000000000..d0c04ea3fe --- /dev/null +++ b/gcp-firebase/.gitignore @@ -0,0 +1 @@ +/firebase-service-account.json diff --git a/gcp-firebase/README.md b/gcp-firebase/README.md new file mode 100644 index 0000000000..ce4c2f2a77 --- /dev/null +++ b/gcp-firebase/README.md @@ -0,0 +1,3 @@ +## Relevant Articles + +- [Using Firebase Cloud Messaging in Spring Boot Applications](https://www.baeldung.com/spring-fcm) diff --git a/gcp-firebase/pom.xml b/gcp-firebase/pom.xml new file mode 100644 index 0000000000..c563099ad6 --- /dev/null +++ b/gcp-firebase/pom.xml @@ -0,0 +1,48 @@ + + 4.0.0 + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + gcp-firebase + + + 9.1.1 + + + + + com.google.firebase + firebase-admin + ${firebase-admin.version} + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/FirebasePublisherApplication.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/FirebasePublisherApplication.java new file mode 100644 index 0000000000..904ae88f00 --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/FirebasePublisherApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.gcp.firebase.publisher; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FirebasePublisherApplication { + + public static void main(String[] args ) { + SpringApplication.run(FirebasePublisherApplication.class,args); + } +} diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseConfiguration.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseConfiguration.java new file mode 100644 index 0000000000..bbfb63d089 --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseConfiguration.java @@ -0,0 +1,57 @@ +package com.baeldung.gcp.firebase.publisher.config; + +import java.io.IOException; +import java.io.InputStream; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.google.api.client.http.HttpTransport; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; + +@Configuration +@EnableConfigurationProperties(FirebaseProperties.class) +public class FirebaseConfiguration { + + private final FirebaseProperties firebaseProperties; + + public FirebaseConfiguration(FirebaseProperties firebaseProperties) { + this.firebaseProperties = firebaseProperties; + } + + @Bean + GoogleCredentials googleCredentials() { + try { + if (firebaseProperties.getServiceAccount() != null) { + try( InputStream is = firebaseProperties.getServiceAccount().getInputStream()) { + return GoogleCredentials.fromStream(is); + } + } + else { + // Use standard credentials chain. Useful when running inside GKE + return GoogleCredentials.getApplicationDefault(); + } + } + catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + @Bean + FirebaseApp firebaseApp(GoogleCredentials credentials) { + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(credentials) + .build(); + + return FirebaseApp.initializeApp(options); + } + + @Bean + FirebaseMessaging firebaseMessaging(FirebaseApp firebaseApp) { + return FirebaseMessaging.getInstance(firebaseApp); + } +} diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseProperties.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseProperties.java new file mode 100644 index 0000000000..44be70cc5d --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/config/FirebaseProperties.java @@ -0,0 +1,25 @@ +package com.baeldung.gcp.firebase.publisher.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.io.Resource; + +@ConfigurationProperties(prefix = "gcp.firebase") +public class FirebaseProperties { + private Resource serviceAccount; + + + /** + * @return the serviceAccount + */ + public Resource getServiceAccount() { + return serviceAccount; + } + + /** + * @param serviceAccount the serviceAccount to set + */ + public void setServiceAccount(Resource serviceAccount) { + this.serviceAccount = serviceAccount; + } + +} diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/ConditionMessageRepresentation.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/ConditionMessageRepresentation.java new file mode 100644 index 0000000000..f0d470a44c --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/ConditionMessageRepresentation.java @@ -0,0 +1,35 @@ +package com.baeldung.gcp.firebase.publisher.controller; + +public class ConditionMessageRepresentation { + + private String condition; + private String data; + + /** + * @return the condition + */ + public String getCondition() { + return condition; + } + + /** + * @param condition the condition to set + */ + public void setCondition(String condition) { + this.condition = condition; + } + + /** + * @return the data + */ + public String getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(String data) { + this.data = data; + } +} diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherController.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherController.java new file mode 100644 index 0000000000..f926c0ef88 --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherController.java @@ -0,0 +1,110 @@ +package com.baeldung.gcp.firebase.publisher.controller; + + +import java.util.List; +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +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.RestController; + +import com.google.firebase.messaging.AndroidConfig; +import com.google.firebase.messaging.AndroidFcmOptions; +import com.google.firebase.messaging.ApnsConfig; +import com.google.firebase.messaging.BatchResponse; +import com.google.firebase.messaging.FcmOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.MulticastMessage; +import com.google.firebase.messaging.Notification; + +@RestController +public class FirebasePublisherController { + + private final FirebaseMessaging fcm; + + public FirebasePublisherController(FirebaseMessaging fcm) { + this.fcm = fcm; + } + + @PostMapping("/topics/{topic}") + public ResponseEntity postToTopic(@RequestBody String message, @PathVariable("topic") String topic) throws FirebaseMessagingException { + + Message msg = Message.builder() + .setTopic(topic) + .putData("body", message) + .build(); + + String id = fcm.send(msg); + return ResponseEntity + .status(HttpStatus.ACCEPTED) + .body(id); + } + + @PostMapping("/condition") + public ResponseEntity postToCondition(@RequestBody ConditionMessageRepresentation message ) throws FirebaseMessagingException { + + Message msg = Message.builder() + .setCondition(message.getCondition()) + .putData("body", message.getData()) + .build(); + + String id = fcm.send(msg); + return ResponseEntity + .status(HttpStatus.ACCEPTED) + .body(id); + } + + + @PostMapping("/clients/{registrationToken}") + public ResponseEntity postToClient(@RequestBody String message, @PathVariable("registrationToken") String registrationToken) throws FirebaseMessagingException { + + Message msg = Message.builder() + .setToken(registrationToken) + .putData("body", message) + .build(); + + String id = fcm.send(msg); + return ResponseEntity + .status(HttpStatus.ACCEPTED) + .body(id); + } + + @PostMapping("/clients") + public ResponseEntity> postToClients(@RequestBody MulticastMessageRepresentation message) throws FirebaseMessagingException { + + MulticastMessage msg = MulticastMessage.builder() + .addAllTokens(message.getRegistrationTokens()) + .putData("body", message.getData()) + .build(); + + BatchResponse response = fcm.sendMulticast(msg); + + List ids = response.getResponses() + .stream() + .map(r->r.getMessageId()) + .collect(Collectors.toList()); + + return ResponseEntity + .status(HttpStatus.ACCEPTED) + .body(ids); + } + + @PostMapping("/subscriptions/{topic}") + public ResponseEntity createSubscription(@PathVariable("topic") String topic,@RequestBody List registrationTokens) throws FirebaseMessagingException { + fcm.subscribeToTopic(registrationTokens, topic); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/subscriptions/{topic}/{registrationToken}") + public ResponseEntity deleteSubscription(@PathVariable String topic, @PathVariable String registrationToken) throws FirebaseMessagingException { + fcm.subscribeToTopic(Arrays.asList(registrationToken), topic); + return ResponseEntity.ok().build(); + } +} diff --git a/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/MulticastMessageRepresentation.java b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/MulticastMessageRepresentation.java new file mode 100644 index 0000000000..5d86e160e0 --- /dev/null +++ b/gcp-firebase/src/main/java/com/baeldung/gcp/firebase/publisher/controller/MulticastMessageRepresentation.java @@ -0,0 +1,33 @@ +package com.baeldung.gcp.firebase.publisher.controller; + +import java.util.List; + +public class MulticastMessageRepresentation { + + private String data; + private List registrationTokens; + /** + * @return the message + */ + public String getData() { + return data; + } + /** + * @param message the message to set + */ + public void setData(String data) { + this.data = data; + } + /** + * @return the registrationTokens + */ + public List getRegistrationTokens() { + return registrationTokens; + } + /** + * @param registrationTokens the registrationTokens to set + */ + public void setRegistrationTokens(List registrationTokens) { + this.registrationTokens = registrationTokens; + } +} diff --git a/gcp-firebase/src/main/resources/application.properties b/gcp-firebase/src/main/resources/application.properties new file mode 100644 index 0000000000..494aeb2444 --- /dev/null +++ b/gcp-firebase/src/main/resources/application.properties @@ -0,0 +1,2 @@ +# Service account location. Can be a filesystem path or a classpath resource. NB: Generate and use your own firebase-service-account.json file. +gcp.firebase.service-account=classpath:firebase-service-account.json \ No newline at end of file diff --git a/gcp-firebase/src/main/resources/firebase-service-account.json b/gcp-firebase/src/main/resources/firebase-service-account.json new file mode 100644 index 0000000000..ed5afa9f13 --- /dev/null +++ b/gcp-firebase/src/main/resources/firebase-service-account.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "tutorials-2cdfb", + "private_key_id": "d9f6a684d6814f85ed2d0490585eb7bf590f983a", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdJWTeGT2eBFo+\nXxzT9xFJYPtyawTAj0K1rVUNlWNUwj3zszK6P2sAsrpI2Rz1klwQ9aDz9i3+Opxv\n7UZ3pOzur6S58JnoswtNs6BZ9P7oeggLJJC6MPjioxwh8jLLIGMgdVtC2/iPYW3r\nGzurWlwkM8M8DyCgNq7KKJcx44pGcyy16ZGCYiijuTEmK6R+WHJTTyICzRFu3Org\nuHGlZUs/G4E76p10HanoFX2AIS/fDEEMP2DXBB73yoCal5GuvMY9yZWxnvV65Y5z\nGveY3NDB9EESbO2AAhDvHekWT17uWhymtO5N3gM8da48J9d51tVzi0D/NIPZnF0u\nTS64uxK3AgMBAAECggEAYuEQa7oPcfLyQscWRbRH1250n2E4e7zSkBcTW4J7Km+7\ncZajTOGEP4iqgF4Lc8XgQnkBYXOmdvDP97+47VAh3EtOtRDeUEyV9kUlonNH8rx1\nkj3kNEwnTHav4oG/slEl4WJ3zro6NinTEvdXQ7OgVVOLrPP6m4g3uQ5TJCxgLEUI\nTd3Hs3cg3P71mzEqfBF4NmGVmC1ea5lXFELd6giJJMvL7g+O2w22/fquGWOrreAM\ncj/G2Xv9/vmzeb9yzbgGxqCJyY6vspmd90fQLUu7bxkEY5/PPc6Zk8qay4AdEn47\nkL6hnJiR8H1wMCzV2RTUKE7ospriNVdBilXgxm9IMQKBgQD1TmF0Bg85zvXmEKBa\nLBhbc3xTtM7DOgKs+pI12sYDKwgL/QKEI/TKkYXua0aVGiQWc2Bk2/0sYhO6aB2f\n6AN1ZUrf4PRM8c53jebChc7beVLSjWI8Tx+kE+0t8864OwvELYZUzP35oSx3RdJD\nE/CvqBM7NQfJwx2Mw2VJK/YRGQKBgQDmyWLm/IWitehkITw6xMQpkkFs2m4Joq3A\nJvAyri58TRkw/7rqWaIxb5Wcy/7BOvjDN8PZNTHh4ZvhQiHpn7NGUks2/ULnWxUB\nWAA9YbeO9PNHJfZ6PjD2FSvwOXHj+vVkWt2GCXT8pDGYM2ImqXon85Oe3OH/h+N5\nktO9taesTwKBgQCSdPGKK/P7N61oZpTWQW1pbFHWSCUKOiBO1mtk6/E9AvwS7EQM\nUMteBfRInJPPgYP6Q3hRv2YwkX3l1TOavRMTjB5f/BbfuZ7jkj0r9mfCcXUZcIAu\nMa9abus0fFP3eolT3zpMdvdLiwbZTz5x/f29YkPZHZhAxdVmrWJThYOsQQKBgBDu\nZVsc25D8V3hBF/IXzWxfVn1t6PS8ApM+SBDvxmlIHrkBiez3dna6APfn32C9utJX\nnP6qcGZp7s2v1F0XYkeecfYuzmG6xOe8VQgryxOp1M87ccG2HlFvbDHLhRd8qdQa\n9nWG7BY81Yac/m5nsJaNwB6/hbUBeybIJtCcKxjxAoGBAJ3y+QSFb4AYmxLFtmMA\nklOvlT+r70w4RV/z4SEO1gjWEh9IozNSXknl5Q/8Zh9IVm3+/qYap//IzEv9JUc3\nv4+HlpZu0trxTpvRWWjPqVr3ssxRdiFLC0LCLEk4rzqWLBVyzJm8uHVIF9Inv8PE\naudInvdbnfAWi60+1Wi8u0Co\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-2afzd@tutorials-2cdfb.iam.gserviceaccount.com", + "client_id": "111111112074248894669", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-2afzd%40tutorials-2cdfb.iam.gserviceaccount.com" +} diff --git a/gcp-firebase/src/test/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherControllerLiveTest.java b/gcp-firebase/src/test/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherControllerLiveTest.java new file mode 100644 index 0000000000..eae4fc0e57 --- /dev/null +++ b/gcp-firebase/src/test/java/com/baeldung/gcp/firebase/publisher/controller/FirebasePublisherControllerLiveTest.java @@ -0,0 +1,48 @@ +package com.baeldung.gcp.firebase.publisher.controller; + +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; +import java.util.Map; + +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.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +class FirebasePublisherControllerLiveTest { + + @LocalServerPort + int serverPort; + + @Autowired + TestRestTemplate restTemplate; + + @Test + void testWhenPostTopicMessage_thenSucess() throws Exception{ + + URI uri = new URI("http://localhost:" + serverPort + "/topics/my-topic"); + ResponseEntity response = restTemplate.postForEntity(uri, "Hello, world", String.class); + + assertNotNull(response); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); + assertNotNull(response.getBody()); + } + + @Test + void testWhenPostClientMessage_thenSucess() throws Exception{ + + URI uri = new URI("http://localhost:" + serverPort + "/clients/fake-registration1"); + ResponseEntity response = restTemplate.postForEntity(uri, "Hello, world", String.class); + + assertNotNull(response); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); + assertNotNull(response.getBody()); + } + +} diff --git a/geotools/pom.xml b/geotools/pom.xml index 05cae922a4..f17b4cc5da 100644 --- a/geotools/pom.xml +++ b/geotools/pom.xml @@ -42,9 +42,9 @@ - 15.2 - 15.2 - 15.2 + 28.1 + 28.1 + 28.1 \ No newline at end of file diff --git a/geotools/src/main/java/com/baeldung/geotools/ShapeFile.java b/geotools/src/main/java/com/baeldung/geotools/ShapeFile.java index de789918cd..64650fb486 100644 --- a/geotools/src/main/java/com/baeldung/geotools/ShapeFile.java +++ b/geotools/src/main/java/com/baeldung/geotools/ShapeFile.java @@ -1,8 +1,8 @@ package com.baeldung.geotools; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.Point; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Point; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; @@ -35,7 +35,7 @@ public class ShapeFile { DefaultFeatureCollection collection = new DefaultFeatureCollection(); - GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); + GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); SimpleFeatureType TYPE = DataUtilities.createType("Location", "location:Point:srid=4326," + "name:String"); diff --git a/gradle-modules/gradle-7/README.md b/gradle-modules/gradle-7/README.md index 19dfc7b15c..ef1e536229 100644 --- a/gradle-modules/gradle-7/README.md +++ b/gradle-modules/gradle-7/README.md @@ -2,3 +2,4 @@ ### Relevant Articles: - [How to Configure Conditional Dependencies in Gradle](https://www.baeldung.com/gradle-conditional-dependencies) +- [Working With Multiple Repositories in Gradle](https://www.baeldung.com/java-gradle-multiple-repositories) diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/build.gradle b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/build.gradle new file mode 100644 index 0000000000..355744da86 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/build.gradle @@ -0,0 +1,29 @@ +plugins { + id 'java' +} + +group = "com.baeldung.gradle" +version = "1.0.0-SNAPSHOT" +sourceCompatibility = JavaVersion.VERSION_17 + +repositories { + mavenLocal() + mavenCentral() + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/eugenp/tutorials" + credentials { + username = project.USERNAME + password = project.GITHUB_TOKEN + } + } +} + +dependencies { + implementation('com.baeldung.gradle:publish-package:1.0.0-SNAPSHOT') + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.0") +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.jar b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..41d9927a4d Binary files /dev/null and b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.properties b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..070cb702f0 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew new file mode 100755 index 0000000000..1b6c787337 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew.bat b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/settings.gradle b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/settings.gradle new file mode 100644 index 0000000000..0177937493 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "multiple-repositories" diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/main/java/com/baeldung/gradle/multiplerepositories/Student.java b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/main/java/com/baeldung/gradle/multiplerepositories/Student.java new file mode 100644 index 0000000000..dcb28a3742 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/main/java/com/baeldung/gradle/multiplerepositories/Student.java @@ -0,0 +1,26 @@ +package com.baeldung.gradle.multiplerepositories; + +import com.baeldung.gradle.publishPackage.User; + +public class Student extends User { + + private String studentCode; + + private String lastInstitution; + + public String getStudentCode() { + return studentCode; + } + + public void setStudentCode(String studentCode) { + this.studentCode = studentCode; + } + + public String getLastInstitution() { + return lastInstitution; + } + + public void setLastInstitution(String lastInstitution) { + this.lastInstitution = lastInstitution; + } +} diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/test/java/com/baeldung/gradle/multiplerepositories/MultipleRepositoryTest.java b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/test/java/com/baeldung/gradle/multiplerepositories/MultipleRepositoryTest.java new file mode 100644 index 0000000000..d0a72d9b3c --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/multiple-repositories/src/test/java/com/baeldung/gradle/multiplerepositories/MultipleRepositoryTest.java @@ -0,0 +1,19 @@ +package com.baeldung.gradle.multiplerepositories; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MultipleRepositoryTest { + + @Test + public void testPublishedPackage() { + Student student = new Student(); + student.setId(1); + student.setStudentCode("CD-875"); + student.setName("John Doe"); + student.setLastInstitution("Institute of Technology"); + + assertEquals("John Doe", student.getName()); + } +} diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/build.gradle b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/build.gradle new file mode 100644 index 0000000000..bd97650e9c --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/build.gradle @@ -0,0 +1,33 @@ +plugins { + id "maven-publish" + id "java" +} + +group = "com.baeldung.gradle" +version = "1.0.0-SNAPSHOT" + +repositories { + mavenLocal() + mavenCentral() +} + +publishing { + publications { + register("jar", MavenPublication) { + from(components["java"]) + pom { + url.set("https://github.com/eugenp/tutorials.git") + } + } + } + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/eugenp/tutorials" + credentials { + username = project.USERNAME + password = project.GITHUB_TOKEN + } + } + } +} diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.jar b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..41d9927a4d Binary files /dev/null and b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.properties b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..070cb702f0 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew new file mode 100755 index 0000000000..1b6c787337 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew.bat b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/settings.gradle b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/settings.gradle new file mode 100644 index 0000000000..9ccd121d0d --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "publish-package" diff --git a/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/src/main/java/com/baeldung/gradle/publish_package/User.java b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/src/main/java/com/baeldung/gradle/publish_package/User.java new file mode 100644 index 0000000000..bc612d038b --- /dev/null +++ b/gradle-modules/gradle-7/multiple-repositories-demo/publish-package/src/main/java/com/baeldung/gradle/publish_package/User.java @@ -0,0 +1,35 @@ +package com.baeldung.gradle.publish_package; + +import java.util.Date; + +public class User { + private Integer id; + + private String name; + + private Date dob; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getDob() { + return dob; + } + + public void setDob(Date dob) { + this.dob = dob; + } +} diff --git a/guava-modules/guava-collections/pom.xml b/guava-modules/guava-collections/pom.xml index 9283107023..8dc052db75 100644 --- a/guava-modules/guava-collections/pom.xml +++ b/guava-modules/guava-collections/pom.xml @@ -37,6 +37,7 @@ ${java-hamcrest.version} test + diff --git a/httpclient-simple/pom.xml b/httpclient-simple/pom.xml index 49e47afe92..eea056477c 100644 --- a/httpclient-simple/pom.xml +++ b/httpclient-simple/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 httpclient-simple 0.1-SNAPSHOT @@ -10,97 +10,50 @@ com.baeldung - parent-spring-5 + parent-boot-3 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-boot-3 - - org.springframework.security - spring-security-web - ${spring-security.version} + org.springframework.boot + spring-boot-starter - org.springframework.security - spring-security-config - ${spring-security.version} - - - - org.springframework - spring-core - ${spring.version} - - - commons-logging - commons-logging - - + org.springframework.boot + spring-boot-starter-security - org.springframework - spring-context - ${spring.version} + org.springframework.boot + spring-boot-starter-jdbc - org.springframework - spring-jdbc - ${spring.version} + org.springframework.boot + spring-boot-starter-aop - org.springframework - spring-beans - ${spring.version} + org.springframework.boot + spring-boot-starter-web - org.springframework - spring-aop - ${spring.version} + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 - org.springframework - spring-tx - ${spring.version} - - - org.springframework - spring-expression - ${spring.version} - - - org.springframework - spring-web - ${spring.version} - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-oxm - ${spring.version} + com.sun.xml.bind + jaxb-impl + 4.0.0 + runtime + com.fasterxml.jackson.core jackson-databind ${jackson.version} - - org.apache.httpcomponents - httpcore - ${httpcore.version} - - - commons-logging - commons-logging - - - org.apache.commons @@ -109,9 +62,9 @@ - org.apache.httpcomponents - httpclient - ${httpclient.version} + org.apache.httpcomponents.client5 + httpclient5 + ${httpclient5.version} commons-logging @@ -120,9 +73,9 @@ - org.apache.httpcomponents - fluent-hc - ${httpclient.version} + org.apache.httpcomponents.core5 + httpcore5 + ${httpcore5.version} commons-logging @@ -131,26 +84,21 @@ - org.apache.httpcomponents - httpmime - ${httpclient.version} + org.apache.httpcomponents.client5 + httpclient5-fluent + ${httpclient5-fluent.version} + + + commons-logging + commons-logging + + commons-codec commons-codec ${commons-codec.version} - - org.apache.httpcomponents - httpasyncclient - ${httpasyncclient.version} - - - commons-logging - commons-logging - - - com.github.tomakehurst wiremock @@ -176,13 +124,6 @@ guava ${guava.version} - - - org.springframework - spring-test - ${spring.version} - test - @@ -197,26 +138,13 @@ org.apache.maven.plugins maven-war-plugin - ${maven-war-plugin.version} + 3.3.2 - org.codehaus.cargo - cargo-maven2-plugin - ${cargo-maven2-plugin.version} + org.springframework.boot + spring-boot-maven-plugin - true - - jetty8x - embedded - - - - - - - 8082 - - + true @@ -229,7 +157,7 @@ org.codehaus.cargo - cargo-maven2-plugin + cargo-maven3-plugin start-server @@ -276,13 +204,15 @@ + 17 1.10 - 4.1.4 2.5.1 - 4.4.11 - 4.5.8 + + 5.2 + 5.2 + 5.2 1.6.1 diff --git a/httpclient-simple/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java b/httpclient-simple/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java index cafd8cfb7b..487794cc7f 100644 --- a/httpclient-simple/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java +++ b/httpclient-simple/src/main/java/com/baeldung/basic/MyBasicAuthenticationEntryPoint.java @@ -3,8 +3,8 @@ package com.baeldung.basic; import java.io.IOException; import java.io.PrintWriter; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; diff --git a/httpclient-simple/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java b/httpclient-simple/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java index 81f82a2c1c..7a0599cd49 100644 --- a/httpclient-simple/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java +++ b/httpclient-simple/src/main/java/com/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java @@ -2,13 +2,13 @@ package com.baeldung.client; import java.net.URI; -import org.apache.http.HttpHost; -import org.apache.http.client.AuthCache; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.apache.hc.core5.http.protocol.HttpContext; import org.springframework.http.HttpMethod; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; @@ -21,6 +21,7 @@ public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpCompone this.host = host; } + @Override protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { return createHttpContext(); } diff --git a/httpclient-simple/src/main/java/com/baeldung/client/RestTemplateFactory.java b/httpclient-simple/src/main/java/com/baeldung/client/RestTemplateFactory.java index aac4f8cebd..fafaae0157 100644 --- a/httpclient-simple/src/main/java/com/baeldung/client/RestTemplateFactory.java +++ b/httpclient-simple/src/main/java/com/baeldung/client/RestTemplateFactory.java @@ -1,6 +1,6 @@ package com.baeldung.client; -import org.apache.http.HttpHost; +import org.apache.hc.core5.http.HttpHost; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.client.ClientHttpRequestFactory; @@ -35,7 +35,7 @@ public class RestTemplateFactory implements FactoryBean, Initializ @Override public void afterPropertiesSet() { - HttpHost host = new HttpHost("localhost", 8082, "http"); + HttpHost host = new HttpHost("http", "localhost", 8082); final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host); restTemplate = new RestTemplate(requestFactory); restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("user1", "user1Pass")); diff --git a/httpclient-simple/src/main/java/com/baeldung/filter/CustomFilter.java b/httpclient-simple/src/main/java/com/baeldung/filter/CustomFilter.java index 6bb12610fa..a9509ddafa 100644 --- a/httpclient-simple/src/main/java/com/baeldung/filter/CustomFilter.java +++ b/httpclient-simple/src/main/java/com/baeldung/filter/CustomFilter.java @@ -2,10 +2,10 @@ package com.baeldung.filter; import org.springframework.web.filter.GenericFilterBean; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; import java.io.IOException; public class CustomFilter extends GenericFilterBean { diff --git a/httpclient-simple/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java b/httpclient-simple/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java index fb597e46c8..859b900170 100644 --- a/httpclient-simple/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java +++ b/httpclient-simple/src/main/java/com/baeldung/filter/CustomWebSecurityConfigurerAdapter.java @@ -7,41 +7,38 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; @Configuration @EnableWebSecurity -public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { +public class CustomWebSecurityConfigurerAdapter{ @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth - .inMemoryAuthentication() - .withUser("user1") - .password(passwordEncoder().encode("user1Pass")) - .authorities("ROLE_USER"); + .inMemoryAuthentication() + .withUser("user1") + .password(passwordEncoder().encode("user1Pass")) + .authorities("ROLE_USER"); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .antMatchers("/securityNone") - .permitAll() - .anyRequest() - .authenticated() - .and() - .httpBasic() - .authenticationEntryPoint(authenticationEntryPoint); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + + http.authorizeHttpRequests((authorize) -> authorize.anyRequest() + .authenticated()) + .httpBasic() + .authenticationEntryPoint(authenticationEntryPoint); http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); + return http.build(); } - + @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); diff --git a/httpclient-simple/src/main/java/com/baeldung/handler/CustomHttpClientResponseHandler.java b/httpclient-simple/src/main/java/com/baeldung/handler/CustomHttpClientResponseHandler.java new file mode 100644 index 0000000000..5472da3a97 --- /dev/null +++ b/httpclient-simple/src/main/java/com/baeldung/handler/CustomHttpClientResponseHandler.java @@ -0,0 +1,11 @@ +package com.baeldung.handler; + +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; + +public class CustomHttpClientResponseHandler implements HttpClientResponseHandler { + @Override + public ClassicHttpResponse handleResponse(ClassicHttpResponse response) { + return response; + } +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java b/httpclient-simple/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java index 7dc53e3e1e..d53aa5bdfe 100644 --- a/httpclient-simple/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java +++ b/httpclient-simple/src/main/java/com/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java @@ -2,9 +2,9 @@ package com.baeldung.security; import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; diff --git a/httpclient-simple/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java b/httpclient-simple/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java index 1ae89adb89..615982fae4 100644 --- a/httpclient-simple/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java +++ b/httpclient-simple/src/main/java/com/baeldung/security/RestAuthenticationEntryPoint.java @@ -2,8 +2,8 @@ package com.baeldung.security; import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; diff --git a/httpclient-simple/src/main/java/com/baeldung/web/dto/Bar.java b/httpclient-simple/src/main/java/com/baeldung/web/dto/Bar.java index eb139b0ec1..1bb7476669 100644 --- a/httpclient-simple/src/main/java/com/baeldung/web/dto/Bar.java +++ b/httpclient-simple/src/main/java/com/baeldung/web/dto/Bar.java @@ -2,7 +2,7 @@ package com.baeldung.web.dto; import java.io.Serializable; -import javax.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Bar implements Serializable { diff --git a/httpclient-simple/src/main/java/com/baeldung/web/dto/Foo.java b/httpclient-simple/src/main/java/com/baeldung/web/dto/Foo.java index 23cfab132d..f904be0ad9 100644 --- a/httpclient-simple/src/main/java/com/baeldung/web/dto/Foo.java +++ b/httpclient-simple/src/main/java/com/baeldung/web/dto/Foo.java @@ -2,7 +2,7 @@ package com.baeldung.web.dto; import java.io.Serializable; -import javax.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Foo implements Serializable { diff --git a/httpclient-simple/src/test/java/com/baeldung/client/ClientLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/client/ClientLiveTest.java index 78e9813f06..1c7e766a72 100644 --- a/httpclient-simple/src/test/java/com/baeldung/client/ClientLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/client/ClientLiveTest.java @@ -1,25 +1,23 @@ package com.baeldung.client; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import com.baeldung.client.spring.ClientConfig; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + import com.baeldung.web.dto.Foo; -import org.junit.Test; -import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; + import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ClientConfig.class }, loader = AnnotationConfigContextLoader.class) -public class ClientLiveTest { +class ClientLiveTest { @Autowired private RestTemplate secureRestTemplate; @@ -27,21 +25,24 @@ public class ClientLiveTest { // tests @Test - public final void whenContextIsBootstrapped_thenNoExceptions() { + void whenContextIsBootstrapped_thenNoExceptions() { // } @Test - public final void whenSecuredRestApiIsConsumed_then200OK() { + void whenSecuredRestApiIsConsumed_then200OK() { final ResponseEntity responseEntity = secureRestTemplate.exchange("http://localhost:8082/httpclient-simple/api/foos/1", HttpMethod.GET, null, Foo.class); assertThat(responseEntity.getStatusCode().value(), is(200)); } - @Test(expected = ResourceAccessException.class) - public final void whenHttpsUrlIsConsumed_thenException() { + @Test + void whenHttpsUrlIsConsumed_thenException() { final String urlOverHttps = "https://localhost:8443/httpclient-simple/api/bars/1"; - final ResponseEntity response = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class); - assertThat(response.getStatusCode().value(), equalTo(200)); + assertThrows(ResourceAccessException.class, () -> { + final ResponseEntity response = new RestTemplate() + .exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + }); } } diff --git a/httpclient-simple/src/test/java/com/baeldung/client/RestClientLiveManualTest.java b/httpclient-simple/src/test/java/com/baeldung/client/RestClientLiveManualTest.java index d133bc376c..efa0695aaf 100644 --- a/httpclient-simple/src/test/java/com/baeldung/client/RestClientLiveManualTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/client/RestClientLiveManualTest.java @@ -1,112 +1,78 @@ package com.baeldung.client; -import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.IOException; import java.security.GeneralSecurityException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLPeerUnverifiedException; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.conn.ssl.TrustStrategy; -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.ssl.SSLContexts; -import org.junit.Ignore; -import org.junit.Test; +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.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.ssl.TrustStrategy; +import org.junit.jupiter.api.Test; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; +import com.baeldung.handler.CustomHttpClientResponseHandler; + + /** * This test requires a localhost server over HTTPS
* It should only be manually run, not part of the automated build * */ -public class RestClientLiveManualTest { +class RestClientLiveManualTest { final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; - // tests - // old httpClient will throw UnsupportedOperationException - @Ignore - @Test - public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { - final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); - final CloseableHttpClient httpClient = (CloseableHttpClient) requestFactory.getHttpClient(); - - final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; - - final SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); - httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 8443, sf)); - - final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); - assertThat(response.getStatusCode().value(), equalTo(200)); - } - // new httpClient : 4.4 and above @Test - public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_2() throws GeneralSecurityException { + void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); final Registry socketFactoryRegistry = RegistryBuilder. create() - .register("https", sslsf) - .register("http", new PlainConnectionSocketFactory()) - .build(); + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); final CloseableHttpClient httpClient = HttpClients.custom() - .setSSLSocketFactory(sslsf) - .setConnectionManager(connectionManager) - .build(); + .setConnectionManager(connectionManager) + .build(); final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); } - @Test - public final void givenAcceptingAllCertificatesUsing4_4_whenHttpsUrlIsConsumed_thenCorrect() throws ClientProtocolException, IOException { - final CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); - final HttpGet getMethod = new HttpGet(urlOverHttps); - final HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - } @Test - public final void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect() throws ClientProtocolException, IOException { - final CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); - final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); - requestFactory.setHttpClient(httpClient); - - final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); - assertThat(response.getStatusCode().value(), equalTo(200)); - } - - @Test(expected = SSLPeerUnverifiedException.class) - public void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { - CloseableHttpClient httpClient = HttpClients.createDefault(); + void whenHttpsUrlIsConsumed_thenException() { String urlOverHttps = "https://localhost:8082/httpclient-simple"; HttpGet getMethod = new HttpGet(urlOverHttps); - HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + assertThrows(SSLPeerUnverifiedException.class, () -> { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpResponse response = httpClient.execute(getMethod, new CustomHttpClientResponseHandler()); + assertThat(response.getCode(), equalTo(200)); + }); } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientHeadersLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientHeadersLiveTest.java index 44262851fd..616b6470af 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientHeadersLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientHeadersLiveTest.java @@ -1,100 +1,76 @@ package com.baeldung.httpclient; import com.google.common.collect.Lists; -import org.apache.http.Header; -import org.apache.http.HttpHeaders; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.methods.RequestBuilder; -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.message.BasicHeader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.util.List; -public class HttpClientHeadersLiveTest { +class HttpClientHeadersLiveTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); private static final String SAMPLE_URL = "http://www.github.com"; - private CloseableHttpClient client; - - private CloseableHttpResponse response; - - @Before - public final void before() { - client = HttpClientBuilder.create().build(); - } - - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - - // tests - headers - deprecated - @Test - public final void givenNewApi_whenClientUsesCustomUserAgent_thenCorrect() throws ClientProtocolException, IOException { - client = HttpClients.custom().setUserAgent("Mozilla/5.0 Firefox/26.0").build(); - + void whenClientUsesCustomUserAgent_thenCorrect() throws IOException { final HttpGet request = new HttpGet(SAMPLE_URL); - response = client.execute(request); + + try (CloseableHttpClient client = HttpClients.custom() + .setUserAgent("Mozilla/5.0 Firefox/26.0") + .build()) { + + String response = client.execute(request, new BasicHttpClientResponseHandler()); + logger.info("Response -> {}", response); + } } - // tests - headers - user agent - @Test - public final void givenConfigOnRequest_whenRequestHasCustomUserAgent_thenCorrect() throws ClientProtocolException, IOException { - client = HttpClients.custom().build(); + void whenRequestHasCustomUserAgent_thenCorrect() throws IOException { final HttpGet request = new HttpGet(SAMPLE_URL); request.setHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 Firefox/26.0"); - response = client.execute(request); + + try (CloseableHttpClient client = HttpClients.createDefault()) { + String response = client.execute(request, new BasicHttpClientResponseHandler()); + logger.info("Response -> {}", response); + } } @Test - public final void givenConfigOnClient_whenRequestHasCustomUserAgent_thenCorrect() throws ClientProtocolException, IOException { - client = HttpClients.custom().setUserAgent("Mozilla/5.0 Firefox/26.0").build(); - response = client.execute(new HttpGet(SAMPLE_URL)); - } - - // tests - headers - content type - - @Test - public final void givenUsingNewApi_whenRequestHasCustomContentType_thenCorrect() throws ClientProtocolException, IOException { - client = HttpClients.custom().build(); + void whenRequestHasCustomContentType_thenCorrect() throws IOException { final HttpGet request = new HttpGet(SAMPLE_URL); request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); - response = client.execute(request); + + try (CloseableHttpClient client = HttpClients.createDefault()) { + String response = client.execute(request, new BasicHttpClientResponseHandler()); + logger.debug("Response -> {}", response); + } } @Test - public final void givenRequestBuildWithBuilderWithNewApi_whenRequestHasCustomContentType_thenCorrect() throws ClientProtocolException, IOException { - final CloseableHttpClient client2 = HttpClients.custom().build(); + void givenConfigOnClient_whenRequestHasCustomContentType_thenCorrect() throws IOException { final HttpGet request = new HttpGet(SAMPLE_URL); - request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); - response = client2.execute(request); - } - - @Test - public final void givenRequestBuildWithBuilder_whenRequestHasCustomContentType_thenCorrect() throws ClientProtocolException, IOException { - client = HttpClients.custom().build(); - final HttpUriRequest request = RequestBuilder.get().setUri(SAMPLE_URL).setHeader(HttpHeaders.CONTENT_TYPE, "application/json").build(); - response = client.execute(request); - } - - @Test - public final void givenConfigOnClient_whenRequestHasCustomContentType_thenCorrect() throws ClientProtocolException, IOException { final Header header = new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"); final List
headers = Lists.newArrayList(header); - client = HttpClients.custom().setDefaultHeaders(headers).build(); - final HttpUriRequest request = RequestBuilder.get().setUri(SAMPLE_URL).build(); - response = client.execute(request); - } + + try (CloseableHttpClient client = HttpClients.custom() + .setDefaultHeaders(headers) + .build()) { + + String response = client.execute(request, new BasicHttpClientResponseHandler()); + logger.debug("Response -> {}", response); + } + } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientParamsLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientParamsLiveTest.java index f3ea9be089..ef662e1bd8 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientParamsLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientParamsLiveTest.java @@ -1,7 +1,8 @@ package com.baeldung.httpclient; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; + import java.io.IOException; import java.net.URI; @@ -10,33 +11,30 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import org.apache.http.NameValuePair; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.message.BasicNameValuePair; -import org.junit.Before; -import org.junit.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.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.ClientProtocolException; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.net.URIBuilder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class HttpClientParamsLiveTest { +import com.baeldung.handler.CustomHttpClientResponseHandler; - private CloseableHttpClient client; +class HttpClientParamsLiveTest { - private CloseableHttpResponse response; private List nameValuePairs; - @Before + @BeforeEach public void setUp() { - client = HttpClientBuilder.create() - .build(); - nameValuePairs = new ArrayList(); + nameValuePairs = new ArrayList<>(); NameValuePair param1NameValuePair = new BasicNameValuePair("param1", "value1"); NameValuePair param2NameValuePair = new BasicNameValuePair("param2", "value2"); nameValuePairs.add(param1NameValuePair); @@ -44,68 +42,83 @@ public class HttpClientParamsLiveTest { } @Test - public void givenStringNameValuePairParams_whenGetRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { + void givenStringNameValuePairParams_whenGetRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { HttpGet httpGet = new HttpGet("https://postman-echo.com/get"); - URI uri = new URIBuilder(httpGet.getURI()).addParameter("param1", "value1") + URI uri = new URIBuilder(httpGet.getUri()).addParameter("param1", "value1") .addParameter("param2", "value2") .build(); - ((HttpRequestBase) httpGet).setURI(uri); - response = client.execute(httpGet); + httpGet.setUri(uri); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpGet, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void givenStringNameValuePairParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { + void givenStringNameValuePairParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { HttpPost httpPost = new HttpPost("https://postman-echo.com/post"); - URI uri = new URIBuilder(httpPost.getURI()).addParameter("param1", "value1") + URI uri = new URIBuilder(httpPost.getUri()).addParameter("param1", "value1") .addParameter("param2", "value2") .build(); - ((HttpRequestBase) httpPost).setURI(uri); - response = client.execute(httpPost); + httpPost.setUri(uri); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void givenNameValuePairParams_whenGetRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { + void givenNameValuePairParams_whenGetRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { HttpGet httpGet = new HttpGet("https://postman-echo.com/get"); - URI uri = new URIBuilder(httpGet.getURI()).addParameters(nameValuePairs) + URI uri = new URIBuilder(httpGet.getUri()).addParameters(nameValuePairs) .build(); - ((HttpRequestBase) httpGet).setURI(uri); - response = client.execute(httpGet); + httpGet.setUri(uri); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpGet, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void givenNameValuePairsParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { + void givenNameValuePairsParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { HttpPost httpPost = new HttpPost("https://postman-echo.com/post"); - URI uri = new URIBuilder(httpPost.getURI()).addParameters(nameValuePairs) + URI uri = new URIBuilder(httpPost.getUri()).addParameters(nameValuePairs) .build(); - ((HttpRequestBase) httpPost).setURI(uri); - response = client.execute(httpPost); + httpPost.setUri(uri); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void givenUrlEncodedEntityParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { + void givenUrlEncodedEntityParams_whenPostRequest_thenResponseOk() throws URISyntaxException, ClientProtocolException, IOException { HttpPost httpPost = new HttpPost("https://postman-echo.com/post"); httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, StandardCharsets.UTF_8)); - response = client.execute(httpPost); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientPostingLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientPostingLiveTest.java index f5dff8d757..b30921c990 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientPostingLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientPostingLiveTest.java @@ -1,74 +1,88 @@ package com.baeldung.httpclient; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.auth.AuthenticationException; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.fluent.Form; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.junit.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.Test; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.fluent.Form; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +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.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicNameValuePair; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; +import com.baeldung.handler.CustomHttpClientResponseHandler; /* * NOTE : Need module spring-rest to be running */ -public class HttpClientPostingLiveTest { +class HttpClientPostingLiveTest { private static final String SAMPLE_URL = "http://www.example.com"; private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://browserspy.dk/password-ok.php"; private static final String DEFAULT_USER = "test"; private static final String DEFAULT_PASS = "test"; @Test - public void whenSendPostRequestUsingHttpClient_thenCorrect() throws IOException { - final CloseableHttpClient client = HttpClients.createDefault(); + void whenSendPostRequestUsingHttpClient_thenCorrect() throws IOException { final HttpPost httpPost = new HttpPost(SAMPLE_URL); - final List params = new ArrayList(); params.add(new BasicNameValuePair("username", DEFAULT_USER)); params.add(new BasicNameValuePair("password", DEFAULT_PASS)); httpPost.setEntity(new UrlEncodedFormEntity(params)); - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void whenSendPostRequestWithAuthorizationUsingHttpClient_thenCorrect() throws IOException, AuthenticationException { - final CloseableHttpClient client = HttpClients.createDefault(); + void whenSendPostRequestWithAuthorizationUsingHttpClient_thenCorrect() throws IOException { final HttpPost httpPost = new HttpPost(URL_SECURED_BY_BASIC_AUTHENTICATION); - httpPost.setEntity(new StringEntity("test post")); - final UsernamePasswordCredentials creds = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS); - httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null)); - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); + final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + final UsernamePasswordCredentials credentials = + new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS.toCharArray()); + + credsProvider.setCredentials(new AuthScope(URL_SECURED_BY_BASIC_AUTHENTICATION, 80) ,credentials); + + try (CloseableHttpClient client = HttpClients.custom() + .setDefaultCredentialsProvider(credsProvider) + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void whenPostJsonUsingHttpClient_thenCorrect() throws IOException { - final CloseableHttpClient client = HttpClients.createDefault(); + void whenPostJsonUsingHttpClient_thenCorrect() throws IOException { final HttpPost httpPost = new HttpPost(SAMPLE_URL); final String json = "{\"id\":1,\"name\":\"John\"}"; @@ -77,68 +91,91 @@ public class HttpClientPostingLiveTest { httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void whenPostFormUsingHttpClientFluentAPI_thenCorrect() throws IOException { - final HttpResponse response = Request.Post(SAMPLE_URL).bodyForm(Form.form().add("username", DEFAULT_USER).add("password", DEFAULT_PASS).build()).execute().returnResponse(); + void whenPostFormUsingHttpClientFluentAPI_thenCorrect() throws IOException { + Request request = Request.post(SAMPLE_URL) + .bodyForm(Form.form() + .add("username", DEFAULT_USER) + .add("password", DEFAULT_PASS) + .build()); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + HttpResponse response = request.execute() + .returnResponse(); + assertThat(response.getCode(), equalTo(HttpStatus.SC_OK)); } @Test - public void whenSendMultipartRequestUsingHttpClient_thenCorrect() throws IOException { - final CloseableHttpClient client = HttpClients.createDefault(); + void whenSendMultipartRequestUsingHttpClient_thenCorrect() throws IOException { final HttpPost httpPost = new HttpPost(SAMPLE_URL); final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addTextBody("username", DEFAULT_USER); builder.addTextBody("password", DEFAULT_PASS); - builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); + builder.addBinaryBody( + "file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); + + final HttpEntity multipart = builder.build(); + httpPost.setEntity(multipart); + + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } + } + + @Test + void whenUploadFileUsingHttpClient_thenCorrect() throws IOException { + final HttpPost httpPost = new HttpPost(SAMPLE_URL); + + final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addBinaryBody( + "file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); final HttpEntity multipart = builder.build(); httpPost.setEntity(multipart); - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public void whenUploadFileUsingHttpClient_thenCorrect() throws IOException { - final CloseableHttpClient client = HttpClients.createDefault(); + void whenGetUploadFileProgressUsingHttpClient_thenCorrect() throws IOException { final HttpPost httpPost = new HttpPost(SAMPLE_URL); final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); + builder.addBinaryBody( + "file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); final HttpEntity multipart = builder.build(); - httpPost.setEntity(multipart); - - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); - } - - @Test - public void whenGetUploadFileProgressUsingHttpClient_thenCorrect() throws IOException { - final CloseableHttpClient client = HttpClients.createDefault(); - final HttpPost httpPost = new HttpPost(SAMPLE_URL); - - final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext"); - final HttpEntity multipart = builder.build(); - - final ProgressEntityWrapper.ProgressListener pListener = percentage -> assertFalse(Float.compare(percentage, 100) > 0); + final ProgressEntityWrapper.ProgressListener pListener = + percentage -> assertFalse(Float.compare(percentage, 100) > 0); httpPost.setEntity(new ProgressEntityWrapper(multipart, pListener)); - final CloseableHttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - client.close(); + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(httpPost, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } } \ No newline at end of file diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientTimeoutLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientTimeoutLiveTest.java index 8bd7042dc6..f3d0a1c27f 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientTimeoutLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpClientTimeoutLiveTest.java @@ -1,129 +1,170 @@ package com.baeldung.httpclient; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import java.io.IOException; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.TimeUnit; -import org.apache.http.HttpResponse; -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.params.ClientPNames; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.params.CoreConnectionPNames; -import org.apache.http.params.HttpParams; -import org.junit.After; -import org.junit.Ignore; -import org.junit.Test; +import org.apache.hc.client5.http.ConnectTimeoutException; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +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.HttpClientBuilder; -public class HttpClientTimeoutLiveTest { +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; - private CloseableHttpResponse response; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.util.Timeout; - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - // tests - @Test - public final void givenUsingOldApi_whenSettingTimeoutViaParameter_thenCorrect() throws IOException { - - DefaultHttpClient httpClient = new DefaultHttpClient(); - int timeout = 5; // seconds - HttpParams httpParams = httpClient.getParams(); - httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000); - httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout * 1000); - httpParams.setParameter(ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000)); - - final HttpGet request = new HttpGet("http://www.github.com"); - HttpResponse execute = httpClient.execute(request); - assertThat(execute.getStatusLine().getStatusCode(), equalTo(200)); - } +import com.baeldung.handler.CustomHttpClientResponseHandler; + +class HttpClientTimeoutLiveTest { @Test - public final void givenUsingNewApi_whenSettingTimeoutViaRequestConfig_thenCorrect() throws IOException { - final int timeout = 2; - final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); - final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); - final HttpGet request = new HttpGet("http://www.github.com"); - - response = client.execute(request); - - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - } - - @Test - public final void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException { + void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException { final int timeout = 2; - final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout * 1000).build(); - final CloseableHttpClient client = HttpClientBuilder.create().setDefaultSocketConfig(config).build(); + ConnectionConfig connConfig = ConnectionConfig.custom() + .setConnectTimeout(timeout, TimeUnit.MILLISECONDS) + .setSocketTimeout(timeout, TimeUnit.MILLISECONDS) + .build(); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofMilliseconds(2000L)) + .build(); + + BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(); + cm.setConnectionConfig(connConfig); + final HttpGet request = new HttpGet("http://www.github.com"); - response = client.execute(request); + try (CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .setConnectionManager(cm) + .build(); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public final void givenUsingNewApi_whenSettingTimeoutViaHighLevelApi_thenCorrect() throws IOException { - final int timeout = 5; + void givenUsingNewApi_whenSettingTimeoutViaSocketConfig_thenCorrect() throws IOException { + final int timeout = 2000; + final SocketConfig config = SocketConfig.custom().setSoTimeout(timeout, TimeUnit.MILLISECONDS).build(); - final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); - final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); + BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(); + cm.setSocketConfig(config); final HttpGet request = new HttpGet("http://www.github.com"); - response = client.execute(request); + try (CloseableHttpClient client = HttpClientBuilder.create() + .setConnectionManager(cm) + .build(); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } + /** * This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP) */ - @Test(expected = ConnectTimeoutException.class) - @Ignore - public final void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException { + @Disabled + void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException { final int timeout = 3; - final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); - final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); + ConnectionConfig connConfig = ConnectionConfig.custom() + .setConnectTimeout(timeout, TimeUnit.MILLISECONDS) + .setSocketTimeout(timeout, TimeUnit.MILLISECONDS) + .build(); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofMilliseconds(3000L)) + .build(); + + BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(); + cm.setConnectionConfig(connConfig); final HttpGet request = new HttpGet("http://www.google.com:81"); - client.execute(request); + + assertThrows(ConnectTimeoutException.class, () -> { + try (CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .setConnectionManager(cm) + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } + }); } @Test - public void whenSecuredRestApiIsConsumed_then200OK() throws IOException { - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + void whenSecuredRestApiIsConsumed_then200OK() throws IOException { + int timeout = 20000; // milliseconds + + ConnectionConfig connConfig = ConnectionConfig.custom() + .setConnectTimeout(timeout, TimeUnit.MILLISECONDS) + .setSocketTimeout(timeout, TimeUnit.MILLISECONDS) + .build(); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofMilliseconds(20000L)) + .build(); - int timeout = 20; // seconds - RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000) - .setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1"); getMethod.setConfig(requestConfig); - int hardTimeout = 5; // seconds + + BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(); + cm.setConnectionConfig(connConfig); + + int hardTimeout = 5000; // milliseconds TimerTask task = new TimerTask() { @Override public void run() { getMethod.abort(); } }; - new Timer(true).schedule(task, hardTimeout * 1000); + new Timer(true).schedule(task, hardTimeout); + + try (CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .setConnectionManager(cm) + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(getMethod, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + System.out.println("HTTP Status of response: " + statusCode); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } - HttpResponse response = httpClient.execute(getMethod); - System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode()); } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpsClientSslLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpsClientSslLiveTest.java index 24ceab0069..54633ba932 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpsClientSslLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/HttpsClientSslLiveTest.java @@ -1,7 +1,6 @@ package com.baeldung.httpclient; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.security.GeneralSecurityException; @@ -9,73 +8,50 @@ import java.security.GeneralSecurityException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.conn.ssl.TrustStrategy; -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.PoolingHttpClientConnectionManager; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; -import org.junit.Test; +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.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.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.ssl.TrustStrategy; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import com.baeldung.handler.CustomHttpClientResponseHandler; /** * This test requires a localhost server over HTTPS
* It should only be manually run, not part of the automated build * */ -public class HttpsClientSslLiveTest { +class HttpsClientSslLiveTest { // "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1" // local // "https://mms.nw.ru/" // hosted private static final String HOST_WITH_SSL = "https://mms.nw.ru/"; - // tests - - @Test(expected = SSLHandshakeException.class) - public final void whenHttpsUrlIsConsumed_thenException() throws IOException { - final CloseableHttpClient httpClient = HttpClientBuilder.create() - .build(); - + @Test + void whenHttpsUrlIsConsumed_thenException() { final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); - final HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); + + assertThrows(SSLHandshakeException.class, () -> { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpResponse response = httpClient.execute(getMethod, new CustomHttpClientResponseHandler()); + MatcherAssert.assertThat(response.getCode(), Matchers.equalTo(200)); + }); + } @Test - public final void givenHttpClientPre4_3_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { - final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; - - final SSLContext sslContext = SSLContexts.custom() - .loadTrustMaterial(null, acceptingTrustStrategy) - .build(); - - final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); - Registry socketFactoryRegistry = RegistryBuilder. create().register("https", sslsf).build(); - PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); - - final CloseableHttpClient httpClient = HttpClients.custom() - .setSSLSocketFactory(sslsf) - .setConnectionManager(clientConnectionManager) - .build(); - - final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); - final HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - - httpClient.close(); - } - - @Test - public final void givenHttpClientAfter4_3_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { + void whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; final SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) @@ -83,55 +59,45 @@ public class HttpsClientSslLiveTest { final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); - final CloseableHttpClient httpClient = HttpClients.custom() + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(sslsf) .build(); final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); - final HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); + try (CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(cm) + .build(); - httpClient.close(); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(getMethod, new CustomHttpClientResponseHandler())) { + + final int statusCode = response.getCode(); + MatcherAssert.assertThat(statusCode, Matchers.equalTo(HttpStatus.SC_OK)); + } } @Test - public final void givenHttpClientPost4_3_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { + void usingBuilder_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .build(); final NoopHostnameVerifier hostnameVerifier = new NoopHostnameVerifier(); final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); - final CloseableHttpClient httpClient = HttpClients.custom() - .setSSLHostnameVerifier(hostnameVerifier) + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(sslsf) .build(); - // new - final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); - final HttpResponse response = httpClient.execute(getMethod); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); - httpClient.close(); - - } - - @Test - public final void givenIgnoringCertificates_whenHttpsUrlIsConsumed_thenCorrect() throws Exception { - final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true) + try (CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(cm) .build(); - final CloseableHttpClient client = HttpClients.custom() - .setSSLContext(sslContext) - .setSSLHostnameVerifier(new NoopHostnameVerifier()) - .build(); - final HttpGet httpGet = new HttpGet(HOST_WITH_SSL); - httpGet.setHeader("Accept", "application/xml"); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(getMethod, new CustomHttpClientResponseHandler())) { - final HttpResponse response = client.execute(httpGet); - assertThat(response.getStatusLine() - .getStatusCode(), equalTo(200)); + final int statusCode = response.getCode(); + MatcherAssert.assertThat(statusCode, Matchers.equalTo(HttpStatus.SC_OK)); + } } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/ProgressEntityWrapper.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/ProgressEntityWrapper.java index c7adf51b3e..0fbc6e5dcd 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/ProgressEntityWrapper.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/ProgressEntityWrapper.java @@ -4,8 +4,8 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; -import org.apache.http.HttpEntity; -import org.apache.http.entity.HttpEntityWrapper; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.HttpEntityWrapper; public class ProgressEntityWrapper extends HttpEntityWrapper { private final ProgressListener listener; diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/base/HttpClientBasicLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/base/HttpClientBasicLiveTest.java index d1b093394e..b850f2e8ba 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/base/HttpClientBasicLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/base/HttpClientBasicLiveTest.java @@ -1,72 +1,77 @@ package com.baeldung.httpclient.base; -import org.apache.http.HttpStatus; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; -import com.baeldung.httpclient.ResponseUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import com.baeldung.handler.CustomHttpClientResponseHandler; + +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.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; + +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.ParseException; +import org.junit.jupiter.api.Test; import java.io.IOException; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; -public class HttpClientBasicLiveTest { + +class HttpClientBasicLiveTest { 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 - - // simple request - response - @Test - public final void whenExecutingBasicGetRequest_thenNoExceptions() throws ClientProtocolException, IOException { - response = instance.execute(new HttpGet(SAMPLE_URL)); + void whenExecutingBasicGetRequest_thenNoExceptions() throws IOException { + final HttpGet request = new HttpGet(SAMPLE_URL); + + try (CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + } } @Test - public final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode() throws ClientProtocolException, IOException { - response = instance.execute(new HttpGet(SAMPLE_URL)); - final int statusCode = response.getStatusLine().getStatusCode(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode() throws IOException { + final HttpGet request = new HttpGet(SAMPLE_URL); + try (CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + assertThat(response.getCode(), equalTo(HttpStatus.SC_OK)); + } } - @Test - public final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectMimeType() throws ClientProtocolException, IOException { - response = instance.execute(new HttpGet(SAMPLE_URL)); - final String contentMimeType = ContentType.getOrDefault(response.getEntity()).getMimeType(); - assertThat(contentMimeType, equalTo(ContentType.TEXT_HTML.getMimeType())); + @Test + void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectMimeType() throws IOException { + final HttpGet request = new HttpGet(SAMPLE_URL); + + try (CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + final String contentMimeType = ContentType.parse(response.getEntity().getContentType()).getMimeType(); + assertThat(contentMimeType, equalTo(ContentType.TEXT_HTML.getMimeType())); + } } - @Test - public final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectBody() throws ClientProtocolException, IOException { - response = instance.execute(new HttpGet(SAMPLE_URL)); - final String bodyAsString = EntityUtils.toString(response.getEntity()); - assertThat(bodyAsString, notNullValue()); + @Test + void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectBody() throws IOException, ParseException { + final HttpGet request = new HttpGet(SAMPLE_URL); + try (CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + + assertThat(response, notNullValue()); + } } } diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientAuthLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientAuthLiveTest.java index 0f7018a9ac..35af84679b 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientAuthLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientAuthLiveTest.java @@ -1,118 +1,119 @@ package com.baeldung.httpclient.sec; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + import org.apache.commons.codec.binary.Base64; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpStatus; -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.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.HttpClientContext; -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.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.protocol.HttpContext; -import com.baeldung.httpclient.ResponseUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; + +import com.baeldung.handler.CustomHttpClientResponseHandler; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.CredentialsProvider; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +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.HttpClientBuilder; +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.HttpStatus; +import org.apache.hc.core5.http.protocol.HttpContext; + +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - /* * NOTE : Need module httpclient-simple to be running */ - -public class HttpClientAuthLiveTest { +class HttpClientAuthLiveTest { private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://localhost:8082/httpclient-simple/api/foos/1"; private static final String DEFAULT_USER = "user1"; private static final String DEFAULT_PASS = "user1Pass"; - - private CloseableHttpClient client; - - private CloseableHttpResponse response; - - @Before - public final void before() { - client = HttpClientBuilder.create().build(); - } - - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - - // tests + private final char[] DEFAULT_PASS_ARRAY = DEFAULT_PASS.toCharArray() ; @Test - public final void whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException { - client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider()).build(); + final void whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException { + final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION); + try (CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultCredentialsProvider(provider()) + .build(); - response = client.execute(new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION)); - - final int statusCode = response.getStatusLine().getStatusCode(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public final void givenAuthenticationIsPreemptive_whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException { - client = HttpClientBuilder.create().build(); - response = client.execute(new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION), context()); + final void givenAuthenticationIsPreemptive_whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException { + final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build(); - final int statusCode = response.getStatusLine().getStatusCode(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, context(), new CustomHttpClientResponseHandler())) { + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(200)); + } } @Test - public final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess() throws IOException { - client = HttpClientBuilder.create().build(); - + final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess() throws IOException { final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION); request.setHeader(HttpHeaders.AUTHORIZATION, authorizationHeader(DEFAULT_USER, DEFAULT_PASS)); - response = client.execute(request); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build(); - final int statusCode = response.getStatusLine().getStatusCode(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, context(), new CustomHttpClientResponseHandler())) { + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } @Test - public final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess2() throws IOException { + final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess2() throws IOException { final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION); final String auth = DEFAULT_USER + ":" + DEFAULT_PASS; final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1)); final String authHeader = "Basic " + new String(encodedAuth); request.setHeader(HttpHeaders.AUTHORIZATION, authHeader); - client = HttpClientBuilder.create().build(); - response = client.execute(request); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build(); - final int statusCode = response.getStatusLine().getStatusCode(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + final int statusCode = response.getCode(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + } } // UTILS private CredentialsProvider provider() { - final CredentialsProvider provider = new BasicCredentialsProvider(); - final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS); - provider.setCredentials(AuthScope.ANY, credentials); + final HttpHost targetHost = new HttpHost("http", "localhost", 8082); + final BasicCredentialsProvider provider = new BasicCredentialsProvider(); + AuthScope authScope = new AuthScope(targetHost); + provider.setCredentials(authScope, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS_ARRAY)); return provider; } private HttpContext context() { - final HttpHost targetHost = new HttpHost("localhost", 8082, "http"); - final CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS)); + final HttpHost targetHost = new HttpHost("http", "localhost", 8082); + final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + AuthScope authScope = new AuthScope(targetHost); + credsProvider.setCredentials(authScope, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS_ARRAY)); // Create AuthCache instance final AuthCache authCache = new BasicAuthCache(); diff --git a/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientCookieLiveTest.java b/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientCookieLiveTest.java index 75286e5b2e..90376acf02 100644 --- a/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientCookieLiveTest.java +++ b/httpclient-simple/src/test/java/com/baeldung/httpclient/sec/HttpClientCookieLiveTest.java @@ -1,114 +1,78 @@ package com.baeldung.httpclient.sec; -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.cookie.ClientCookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; -import com.baeldung.httpclient.ResponseUtil; +import com.baeldung.handler.CustomHttpClientResponseHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +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.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; +import org.apache.hc.client5.http.protocol.HttpClientContext; + +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; import java.io.IOException; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -public class HttpClientCookieLiveTest { - - private CloseableHttpClient instance; - - private CloseableHttpResponse response; - - private static Logger log = LoggerFactory.getLogger(HttpClientCookieLiveTest.class); - - @Before - public final void before() { - instance = HttpClientBuilder.create().build(); - } - - @After - public final void after() throws IllegalStateException, IOException { - ResponseUtil.closeResponse(response); - } - - // tests +class HttpClientCookieLiveTest { @Test - public final void whenSettingCookiesOnARequest_thenCorrect() throws IOException { - instance = HttpClientBuilder.create().build(); + final void whenSettingCookiesOnARequest_thenCorrect() throws IOException { final HttpGet request = new HttpGet("http://www.github.com"); request.setHeader("Cookie", "JSESSIONID=1234"); + try (CloseableHttpClient client = HttpClients.createDefault(); - response = instance.execute(request); - - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + assertThat(response.getCode(), equalTo(200)); + } } @Test - public final void givenUsingDeprecatedApi_whenSettingCookiesOnTheHttpClient_thenCorrect() throws IOException { + final void whenSettingCookiesOnTheHttpClient_thenCookieSentCorrectly() throws IOException { final BasicCookieStore cookieStore = new BasicCookieStore(); final BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); - cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "true"); - + cookie.setAttribute("domain", "true"); cookie.setPath("/"); cookieStore.addCookie(cookie); - - DefaultHttpClient client = new DefaultHttpClient(); - client.setCookieStore(cookieStore); - - final HttpGet request = new HttpGet("https://www.github.com"); - - response = (CloseableHttpResponse) client.execute(request); - - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - } - - @Test - public final void whenSettingCookiesOnTheHttpClient_thenCookieSentCorrectly() throws IOException { - final BasicCookieStore cookieStore = new BasicCookieStore(); - final BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); - cookie.setDomain(".github.com"); - cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "true"); - cookie.setPath("/"); - cookieStore.addCookie(cookie); - instance = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build(); - final HttpGet request = new HttpGet("http://www.github.com"); - response = instance.execute(request); + try (CloseableHttpClient client = HttpClientBuilder.create() + .setDefaultCookieStore(cookieStore) + .build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, new CustomHttpClientResponseHandler())) { + assertThat(response.getCode(), equalTo(200)); + } - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); } @Test - public final void whenSettingCookiesOnTheRequest_thenCookieSentCorrectly() throws IOException { + final void whenSettingCookiesOnTheRequest_thenCookieSentCorrectly() throws IOException { final BasicCookieStore cookieStore = new BasicCookieStore(); final BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie); - instance = HttpClientBuilder.create().build(); - final HttpGet request = new HttpGet("http://www.github.com"); - final HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); // localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); // before 4.3 - response = instance.execute(request, localContext); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + try (CloseableHttpClient client = HttpClientBuilder.create().build(); + + CloseableHttpResponse response = (CloseableHttpResponse) client + .execute(request, localContext, new CustomHttpClientResponseHandler())) { + assertThat(response.getCode(), equalTo(200)); + } } } diff --git a/httpclient-simple/src/test/java/com/baeldung/test/LiveTestSuite.java b/httpclient-simple/src/test/java/com/baeldung/test/LiveTestSuite.java deleted file mode 100644 index c864349e02..0000000000 --- a/httpclient-simple/src/test/java/com/baeldung/test/LiveTestSuite.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.test; - -import com.baeldung.client.ClientLiveTest; -import com.baeldung.client.RestClientLiveManualTest; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ -// @formatter:off - RestClientLiveManualTest.class - ,ClientLiveTest.class -}) // -public class LiveTestSuite { - -} diff --git a/jackson-modules/jackson-annotations/README.md b/jackson-modules/jackson-annotations/README.md index 3b6cd6f20b..8b405ec778 100644 --- a/jackson-modules/jackson-annotations/README.md +++ b/jackson-modules/jackson-annotations/README.md @@ -8,3 +8,4 @@ This module contains articles about Jackson annotations. - [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion) - [Jackson JSON Views](https://www.baeldung.com/jackson-json-view-annotation) - [Deduction-Based Polymorphism in Jackson 2.12](https://www.baeldung.com/jackson-deduction-based-polymorphism) +- [@JsonIgnore vs @Transient](https://www.baeldung.com/java-jsonignore-vs-transient) diff --git a/jackson-modules/jackson-annotations/pom.xml b/jackson-modules/jackson-annotations/pom.xml index 56fd6cf2fa..4bb9341e43 100644 --- a/jackson-modules/jackson-annotations/pom.xml +++ b/jackson-modules/jackson-annotations/pom.xml @@ -25,6 +25,27 @@ ${rest-assured.version} test + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-data-jdbc + ${spring-boot.version} + + + com.h2database + h2 + ${h2.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + @@ -38,7 +59,9 @@ + 2.1.214 3.1.1 + 2.5.0 \ No newline at end of file diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Application.java similarity index 57% rename from patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java rename to jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Application.java index 52aaefaaf7..ad4ef9e9ac 100644 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java +++ b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Application.java @@ -1,13 +1,13 @@ -package com.baeldung.pattern.hexagonal; +package com.baeldung.jackson.jsonignorevstransient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class HexArchApplicationDemo { +public class Application { public static void main(String[] args) { - SpringApplication.run(HexArchApplicationDemo.class, args); + SpringApplication.run(Application.class, args); } } diff --git a/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Person.java b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Person.java new file mode 100644 index 0000000000..982d0e6440 --- /dev/null +++ b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/Person.java @@ -0,0 +1,34 @@ +package com.baeldung.jackson.jsonignorevstransient; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.io.Serializable; + +class Person implements Serializable { + + @JsonIgnore + private final Long id; + + private final String firstName; + + private final String lastName; + + public Person(Long id, String firstName, String lastName) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + + public Long getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + +} diff --git a/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/User.java b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/User.java new file mode 100644 index 0000000000..c12e5225db --- /dev/null +++ b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/User.java @@ -0,0 +1,64 @@ +package com.baeldung.jackson.jsonignorevstransient; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import java.io.Serializable; + +@Entity +@Table(name = "Users") +class User implements Serializable { + + @Id + private Long id; + + private String username; + + private String password; + + @Transient + private String repeatedPassword; + + public User() { + } + + public User(Long id, String username, String password, String repeatedPassword) { + this.id = id; + this.username = username; + this.password = password; + this.repeatedPassword = repeatedPassword; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRepeatedPassword() { + return repeatedPassword; + } + + public void setRepeatedPassword(String repeatedPassword) { + this.repeatedPassword = repeatedPassword; + } +} diff --git a/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/UserRepository.java b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/UserRepository.java new file mode 100644 index 0000000000..ca6428ca3e --- /dev/null +++ b/jackson-modules/jackson-annotations/src/main/java/com/baeldung/jackson/jsonignorevstransient/UserRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.jackson.jsonignorevstransient; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { +} diff --git a/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/PersonUnitTest.java b/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/PersonUnitTest.java new file mode 100644 index 0000000000..0595fc240c --- /dev/null +++ b/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/PersonUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.jackson.jsonignorevstransient; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; + +class PersonUnitTest { + + @Test + void givenPerson_whenSerializing_thenIdFieldIgnored() throws JsonProcessingException { + + Person person = new Person(1L, "My First Name", "My Last Name"); + String result = new ObjectMapper().writeValueAsString(person); + + assertThat(result, containsString("firstName")); + assertThat(result, containsString("lastName")); + assertThat(result, not(containsString("id"))); + } +} \ No newline at end of file diff --git a/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/UserUnitTest.java b/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/UserUnitTest.java new file mode 100644 index 0000000000..bc57b6f550 --- /dev/null +++ b/jackson-modules/jackson-annotations/src/test/java/com/baeldung/jackson/jsonignorevstransient/UserUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.jackson.jsonignorevstransient; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +@SpringBootTest +class UserUnitTest { + + @Autowired + UserRepository userRepository; + + @Test + void givenUser_whenSave_thenSkipTransientFields() { + User user = new User(1L, "user", "newPassword123", "newPassword123"); + User savedUser = userRepository.save(user); + + assertNotNull(savedUser); + assertNotNull(savedUser.getPassword()); + assertNull(savedUser.getRepeatedPassword()); + } + + @Test + void givenUser_whenSerializing_thenTransientFieldNotIgnored() throws JsonProcessingException { + User user = new User(1L, "user", "newPassword123", "newPassword123"); + String result = new ObjectMapper().writeValueAsString(user); + + assertThat(result, containsString("user")); + assertThat(result, containsString("repeatedPassword")); + } + +} \ No newline at end of file diff --git a/jackson-modules/jackson-annotations/src/test/resources/application.properties b/jackson-modules/jackson-annotations/src/test/resources/application.properties new file mode 100644 index 0000000000..d0f6dd95ef --- /dev/null +++ b/jackson-modules/jackson-annotations/src/test/resources/application.properties @@ -0,0 +1,5 @@ +hibernate.hbm2ddl.auto=create-drop + +spring.datasource.jdbcUrl=jdbc:h2:mem:testDb;DB_CLOSE_DELAY=-1 +spring.datasource.username=sa +spring.datasource.password=sa \ No newline at end of file diff --git a/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/ItemWithWrappedUser.java b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/ItemWithWrappedUser.java new file mode 100644 index 0000000000..827d7dd768 --- /dev/null +++ b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/ItemWithWrappedUser.java @@ -0,0 +1,31 @@ +package com.baeldung.deserialization; + +public class ItemWithWrappedUser { + + public int id; + public String itemName; + public Wrapper owner; + + public ItemWithWrappedUser() { + super(); + } + + public ItemWithWrappedUser(final int id, final String itemName, final Wrapper owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } + + public int getId() { + return id; + } + + public String getItemName() { + return itemName; + } + + public Wrapper getOwner() { + return owner; + } + +} diff --git a/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/Wrapper.java b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/Wrapper.java new file mode 100644 index 0000000000..a9baa52277 --- /dev/null +++ b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/Wrapper.java @@ -0,0 +1,15 @@ +package com.baeldung.deserialization; + +public class Wrapper { + + T value; + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } + +} diff --git a/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/WrapperDeserializer.java b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/WrapperDeserializer.java new file mode 100644 index 0000000000..e6a4bea0d6 --- /dev/null +++ b/jackson-modules/jackson-custom-conversions/src/main/java/com/baeldung/deserialization/WrapperDeserializer.java @@ -0,0 +1,30 @@ +package com.baeldung.deserialization; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.ContextualDeserializer; + +public class WrapperDeserializer extends JsonDeserializer> implements ContextualDeserializer { + + private JavaType type; + + @Override + public JsonDeserializer createContextual(DeserializationContext ctxt, BeanProperty property) { + this.type = property.getType() + .containedType(0); + return this; + } + + @Override + public Wrapper deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + Wrapper wrapper = new Wrapper<>(); + wrapper.setValue(deserializationContext.readValue(jsonParser, type)); + return wrapper; + } + +} diff --git a/jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/deserialization/CustomDeserializationUnitTest.java b/jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/deserialization/CustomDeserializationUnitTest.java index 17016149a2..b32121dbed 100644 --- a/jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/deserialization/CustomDeserializationUnitTest.java +++ b/jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/deserialization/CustomDeserializationUnitTest.java @@ -1,23 +1,24 @@ package com.baeldung.deserialization; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import java.io.IOException; import java.time.ZoneId; import java.time.ZonedDateTime; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; +import org.junit.Test; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.module.SimpleModule; public class CustomDeserializationUnitTest { @@ -78,4 +79,23 @@ public class CustomDeserializationUnitTest { assertThat(restored, is(now)); } + @Test + public void whenDeserialisingItemWithWrappedUser_ThenWrappedUserIsCorrectlyParsed() throws JsonProcessingException { + final String json = "{\"id\":1,\"itemName\":\"theItem\",\"owner\":{\"id\":2,\"name\":\"theUser\"}}"; + + SimpleModule module = new SimpleModule().addDeserializer(Wrapper.class, new WrapperDeserializer()); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(module); + + final ItemWithWrappedUser readValue = objectMapper.readValue(json, ItemWithWrappedUser.class); + + assertEquals(2, readValue.getOwner() + .getValue() + .getId()); + assertEquals("theUser", readValue.getOwner() + .getValue() + .getName()); + } + } diff --git a/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Contact.java b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Contact.java new file mode 100644 index 0000000000..6417d60310 --- /dev/null +++ b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Contact.java @@ -0,0 +1,15 @@ +package com.baeldung.exceptions; + +public class Contact { + + private String email; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} diff --git a/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Person.java b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Person.java new file mode 100644 index 0000000000..1572d7a71f --- /dev/null +++ b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/Person.java @@ -0,0 +1,33 @@ +package com.baeldung.exceptions; + +public class Person { + + private String firstName; + private String lastName; + private String contact; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } + +} diff --git a/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/PersonContact.java b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/PersonContact.java new file mode 100644 index 0000000000..0c75240d94 --- /dev/null +++ b/jackson-modules/jackson-exceptions/src/main/java/com/baeldung/exceptions/PersonContact.java @@ -0,0 +1,33 @@ +package com.baeldung.exceptions; + +public class PersonContact { + + private String firstName; + private String lastName; + private Contact contact; + + 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 Contact getContact() { + return contact; + } + + public void setContact(Contact contact) { + this.contact = contact; + } + +} diff --git a/jackson-modules/jackson-exceptions/src/test/java/com/baeldung/exceptions/JacksonExceptionsUnitTest.java b/jackson-modules/jackson-exceptions/src/test/java/com/baeldung/exceptions/JacksonExceptionsUnitTest.java index 38ef3f9390..127d466436 100644 --- a/jackson-modules/jackson-exceptions/src/test/java/com/baeldung/exceptions/JacksonExceptionsUnitTest.java +++ b/jackson-modules/jackson-exceptions/src/test/java/com/baeldung/exceptions/JacksonExceptionsUnitTest.java @@ -3,17 +3,14 @@ package com.baeldung.exceptions; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.List; import org.junit.Test; -import com.baeldung.exceptions.User; -import com.baeldung.exceptions.UserWithPrivateFields; -import com.baeldung.exceptions.UserWithRoot; -import com.baeldung.exceptions.Zoo; -import com.baeldung.exceptions.ZooConfigured; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonFactory; @@ -82,6 +79,32 @@ public class JacksonExceptionsUnitTest { .readValue(json); } + @Test + public void givenJsonObject_whenDeserializingIntoString_thenException() throws IOException { + final String json = "{\"firstName\":\"Azhrioun\",\"lastName\":\"Abderrahim\",\"contact\":{\"email\":\"azh@email.com\"}}"; + final ObjectMapper mapper = new ObjectMapper(); + + Exception exception = assertThrows(JsonMappingException.class, () -> mapper.reader() + .forType(Person.class) + .readValue(json)); + + assertTrue(exception.getMessage() + .contains("Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)")); + } + + @Test + public void givenJsonObject_whenDeserializingIntoObject_thenDeserialize() throws IOException { + final String json = "{\"firstName\":\"Azhrioun\",\"lastName\":\"Abderrahim\",\"contact\":{\"email\":\"azh@email.com\"}}"; + final ObjectMapper mapper = new ObjectMapper(); + + PersonContact person = mapper.reader() + .forType(PersonContact.class) + .readValue(json); + + assertEquals("azh@email.com", person.getContact() + .getEmail()); + } + @Test public void givenDefaultConstructor_whenDeserializing_thenCorrect() throws IOException { final String json = "{\"id\":1,\"name\":\"John\"}"; diff --git a/java-blockchain/pom.xml b/java-blockchain/pom.xml index 6d3910df80..2279a7ceff 100644 --- a/java-blockchain/pom.xml +++ b/java-blockchain/pom.xml @@ -24,22 +24,6 @@ true - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - - - 1.8 - 1.8 - - \ No newline at end of file diff --git a/java-panama/pom.xml b/java-panama/pom.xml new file mode 100644 index 0000000000..8453a38abd --- /dev/null +++ b/java-panama/pom.xml @@ -0,0 +1,49 @@ + + ${project.model.version} + + com.baeldung.java.panama + java-panama + ${project.version} + jar + + java-panama + https://maven.apache.org + + + 4.0.0 + UTF-8 + 1.0 + 19 + 19 + 3.10.1 + 5.9.0 + + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + --add-opens=java.base/java.lang.foreign=ALL-UNNAMED + --enable-preview + + + + + + diff --git a/java-panama/src/main/java/com/baeldung/java/panama/core/Greetings.java b/java-panama/src/main/java/com/baeldung/java/panama/core/Greetings.java new file mode 100644 index 0000000000..1937bd65e9 --- /dev/null +++ b/java-panama/src/main/java/com/baeldung/java/panama/core/Greetings.java @@ -0,0 +1,40 @@ +package com.baeldung.java.panama.core; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +public class Greetings { + + public static void main(String[] args) throws Throwable { + + String symbolName = "printf"; + String greeting = "Hello World from Project Panama Baeldung Article"; + + Linker nativeLinker = Linker.nativeLinker(); + SymbolLookup stdlibLookup = nativeLinker.defaultLookup(); + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + + FunctionDescriptor descriptor = FunctionDescriptor.of(JAVA_INT, ADDRESS); + + MethodHandle methodHandle = loaderLookup.lookup(symbolName) + .or(() -> stdlibLookup.lookup(symbolName)) + .map(symbolSegment -> nativeLinker.downcallHandle(symbolSegment, descriptor)) + .orElse(null); + + if (methodHandle == null) { + throw new NoSuchMethodError("Method Handle was not found"); + } + + try (MemorySession memorySession = MemorySession.openConfined()) { + MemorySegment greetingSegment = memorySession.allocateUtf8String(greeting); + methodHandle.invoke(greetingSegment); + } + } +} diff --git a/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryAllocation.java b/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryAllocation.java new file mode 100644 index 0000000000..239b25b69e --- /dev/null +++ b/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryAllocation.java @@ -0,0 +1,23 @@ +package com.baeldung.java.panama.core; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.ValueLayout; + +public class MemoryAllocation { + + public static void main(String[] args) throws Throwable { + + try (MemorySession session = MemorySession.openConfined()) { + String[] greetingStrings = { "hello", "world", "panama", "baeldung" }; + SegmentAllocator allocator = SegmentAllocator.implicitAllocator(); + MemorySegment offHeapSegment = allocator.allocateArray(ValueLayout.ADDRESS, greetingStrings.length); + for (int i = 0; i < greetingStrings.length; i++) { + // Allocate a string off-heap, then store a pointer to it + MemorySegment cString = allocator.allocateUtf8String(greetingStrings[i]); + offHeapSegment.setAtIndex(ValueLayout.ADDRESS, i, cString); + } + } + } +} diff --git a/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryLayout.java b/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryLayout.java new file mode 100644 index 0000000000..612997e35e --- /dev/null +++ b/java-panama/src/main/java/com/baeldung/java/panama/core/MemoryLayout.java @@ -0,0 +1,53 @@ +package com.baeldung.java.panama.core; + +import static java.lang.foreign.MemoryLayout.sequenceLayout; +import static java.lang.foreign.MemoryLayout.structLayout; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.PathElement; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SequenceLayout; +import java.lang.invoke.VarHandle; + +public class MemoryLayout { + + public static void main(String[] args) { + + GroupLayout pointLayout = structLayout(JAVA_DOUBLE.withName("x"), JAVA_DOUBLE.withName("y")); + + SequenceLayout ptsLayout = sequenceLayout(10, pointLayout); + + VarHandle xvarHandle = pointLayout.varHandle(PathElement.groupElement("x")); + VarHandle yvarHandle = pointLayout.varHandle(PathElement.groupElement("y")); + + try (MemorySession memorySession = MemorySession.openConfined()) { + + MemorySegment pointSegment = memorySession.allocate(pointLayout); + xvarHandle.set(pointSegment, 3d); + yvarHandle.set(pointSegment, 4d); + + System.out.println(pointSegment.toString()); + + } + + } + + static class ValueLayout { + + public static void main(String[] args) { + + try (MemorySession memorySession = MemorySession.openConfined()) { + int byteSize = 5; + int index = 3; + float value = 6; + MemorySegment segment = MemorySegment.allocateNative(byteSize, memorySession); + segment.setAtIndex(JAVA_FLOAT, index, value); + float result = segment.getAtIndex(JAVA_FLOAT, index); + System.out.println("Float value is:" + result); + } + } + } +} diff --git a/java-panama/src/main/java/com/baeldung/java/panama/jextract/Greetings.java b/java-panama/src/main/java/com/baeldung/java/panama/jextract/Greetings.java new file mode 100644 index 0000000000..43b575d52a --- /dev/null +++ b/java-panama/src/main/java/com/baeldung/java/panama/jextract/Greetings.java @@ -0,0 +1,19 @@ +package com.baeldung.java.panama.jextract; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +// Generate JExtract bindings before uncommenting +// import static foreign.c.stdio_h.printf; + +public class Greetings { + + public static void main(String[] args) { + String greeting = "Hello World from Project Panama Baeldung Article, using JExtract!"; + + try (MemorySession memorySession = MemorySession.openConfined()) { + MemorySegment greetingSegment = memorySession.allocateUtf8String(greeting); + // Generate JExtract bingings before uncommenting + // printf(greetingSegment); + } + } +} diff --git a/java-panama/src/main/resources/hello.c b/java-panama/src/main/resources/hello.c new file mode 100644 index 0000000000..3f2d3fce6a --- /dev/null +++ b/java-panama/src/main/resources/hello.c @@ -0,0 +1,5 @@ +#include +int main() { + printf("Hello World from Project Panama Baeldung Article"); + return 0; +} \ No newline at end of file diff --git a/javax-validation-advanced/README.md b/javax-validation-advanced/README.md index 8f03107330..b3ed669c39 100644 --- a/javax-validation-advanced/README.md +++ b/javax-validation-advanced/README.md @@ -3,3 +3,4 @@ This module contains articles about Bean Validation. ### Relevant Articles: +- [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) diff --git a/javaxval-2/pom.xml b/javaxval-2/pom.xml index fd4aa70023..5c311e10f8 100644 --- a/javaxval-2/pom.xml +++ b/javaxval-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 javaxval-2 0.1-SNAPSHOT @@ -60,9 +60,6 @@ 6.2.3.Final 6.2.0.Final - 3.6.1 - 1.8 - 1.8 3.0.0 5.3.21 2.7.1 diff --git a/javaxval/pom.xml b/javaxval/pom.xml index 753a46cffe..1feed71abb 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -46,7 +46,7 @@ test - + @@ -60,9 +60,6 @@ 6.2.3.Final 6.2.0.Final - 3.6.1 - 1.8 - 1.8 3.0.0 5.3.21 2.7.1 diff --git a/javaxval2/README.md b/javaxval2/README.md deleted file mode 100644 index 8f03107330..0000000000 --- a/javaxval2/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## Java Bean Validation Examples - -This module contains articles about Bean Validation. - -### Relevant Articles: diff --git a/javaxval2/pom.xml b/javaxval2/pom.xml deleted file mode 100644 index 2e0ed0a281..0000000000 --- a/javaxval2/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 4.0.0 - javaxval2 - 0.1-SNAPSHOT - javaxval2 - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-validation - ${spring.boot.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} - - - - - 2.7.5 - 2.14.0 - - - \ No newline at end of file diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java deleted file mode 100644 index 3e20ebad6b..0000000000 --- a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.javaxval.afterdeserialization; - -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.DeserializationConfig; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; - -public class BeanDeserializerModifierWithValidation extends BeanDeserializerModifier { - - @Override - public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { - if (deserializer instanceof BeanDeserializer) { - return new BeanDeserializerWithValidation((BeanDeserializer) deserializer); - } - - return deserializer; - } - -} diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java deleted file mode 100644 index 332c83010d..0000000000 --- a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.javaxval.afterdeserialization; - -import java.io.IOException; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.BeanDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializerBase; - -public class BeanDeserializerWithValidation extends BeanDeserializer { - - private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - private static final Validator validator = factory.getValidator(); - - protected BeanDeserializerWithValidation(BeanDeserializerBase src) { - super(src); - } - - @Override - public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - Object instance = super.deserialize(p, ctxt); - validate(instance); - return instance; - } - - public void validate(T t) { - Set> violations = validator.validate(t); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } - } - -} diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java deleted file mode 100644 index c1923de265..0000000000 --- a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.baeldung.javaxval.afterdeserialization; - -import javax.validation.constraints.Size; - -public class Student { - - @Size(min = 5, max = 10, message = "Student's name must be between 5 and 10 characters") - private String name; - - public String getName() { - return name; - } - -} diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java deleted file mode 100644 index e652a43ccb..0000000000 --- a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.javaxval.afterdeserialization; - -import java.io.IOException; -import java.io.InputStream; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; - -public class StudentDeserializerWithValidation { - - public static Student readStudent(InputStream inputStream) throws IOException { - ObjectMapper mapper = getObjectMapperWithValidation(); - return mapper.readValue(inputStream, Student.class); - } - - private static ObjectMapper getObjectMapperWithValidation() { - SimpleModule validationModule = new SimpleModule(); - validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation()); - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(validationModule); - return mapper; - } - -} diff --git a/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java b/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java deleted file mode 100644 index edbe85ecfe..0000000000 --- a/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.javaxval; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.io.IOException; -import java.io.InputStream; - -import javax.validation.ConstraintViolationException; - -import org.junit.jupiter.api.Test; - -import com.baeldung.javaxval.afterdeserialization.Student; -import com.baeldung.javaxval.afterdeserialization.StudentDeserializerWithValidation; - -public class StudentDeserializerWithValidationUnitTest { - - private final String EXPECTED_ERROR_MESSAGE = "name: Student's name must be between 5 and 10 characters"; - private final String EXPECTED_STUDENT_NAME = "Daniel"; - private final String NAME_TOO_LONG_STUDENT_FILE = "nameTooLongStudent.json"; - private final String NAME_TOO_SHORT_STUDENT_FILE = "nameTooShortStudent.json"; - private final String SUBDIRECTORY = "afterdeserialization/"; - private final String VALID_STUDENT_FILE = "validStudent.json"; - - @Test - void givenValidStudent_WhenReadStudent_ThenReturnStudent() throws IOException { - InputStream inputStream = getInputStream(VALID_STUDENT_FILE); - Student result = StudentDeserializerWithValidation.readStudent(inputStream); - assertEquals(EXPECTED_STUDENT_NAME, result.getName()); - } - - @Test - void givenStudentWithTooShortName_WhenReadStudent_ThenThrows() { - InputStream inputStream = getInputStream(NAME_TOO_SHORT_STUDENT_FILE); - ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); - assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); - } - - @Test - void givenStudentWithTooLongName_WhenReadStudent_ThenThrows() { - InputStream inputStream = getInputStream(NAME_TOO_LONG_STUDENT_FILE); - ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); - assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); - } - - private InputStream getInputStream(String fileName) { - return getClass().getClassLoader() - .getResourceAsStream(SUBDIRECTORY + fileName); - } - -} diff --git a/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json b/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json deleted file mode 100644 index e537ecb25d..0000000000 --- a/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "Constantine" -} \ No newline at end of file diff --git a/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json b/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json deleted file mode 100644 index 79ab10cb80..0000000000 --- a/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "Max" -} \ No newline at end of file diff --git a/javaxval2/src/test/resources/afterdeserialization/validStudent.json b/javaxval2/src/test/resources/afterdeserialization/validStudent.json deleted file mode 100644 index 938002ea51..0000000000 --- a/javaxval2/src/test/resources/afterdeserialization/validStudent.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "Daniel" -} \ No newline at end of file diff --git a/jenkins-modules/jenkins-jobs/README.md b/jenkins-modules/jenkins-jobs/README.md new file mode 100644 index 0000000000..d29a25244f --- /dev/null +++ b/jenkins-modules/jenkins-jobs/README.md @@ -0,0 +1,5 @@ +## Relevant Articles +- [Trigger Another Job from a Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-trigger-new-job) +- [Fixing the “No Such DSL method” Error in Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-no-such-dsl-method-error) +- [Jenkins Pipeline – Change to Another Folder](https://www.baeldung.com/ops/jenkins-pipeline-change-to-another-folder) +- [How to Stop a Zombie Job on Jenkins Without Restarting the Server?](https://www.baeldung.com/ops/stop-zombie-job-on-jenkins-without-restarting-the-server) diff --git a/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-fullpath-job b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-fullpath-job new file mode 100644 index 0000000000..98dc32efe5 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-fullpath-job @@ -0,0 +1,11 @@ +pipeline { + agent any + stages { + stage('Build') { + steps { + dir('/var/jenkins_home/workspace/SamplePipeline/scripts') { + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-job b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-job new file mode 100644 index 0000000000..42a946ca49 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-dir-job @@ -0,0 +1,11 @@ + pipeline { + agent any + stages { + stage('Build') { + steps { + dir('scripts') { + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-sh-job b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-sh-job new file mode 100644 index 0000000000..9b7f992b86 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/change-directory-job/pipeline-sh-job @@ -0,0 +1,10 @@ +pipeline { + agent any + stages { + stage('Build') { + steps { + sh 'cd scripts' + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/dsl-error-fix/no-such-dsl-method-job b/jenkins-modules/jenkins-jobs/dsl-error-fix/no-such-dsl-method-job new file mode 100644 index 0000000000..f68cb70c2f --- /dev/null +++ b/jenkins-modules/jenkins-jobs/dsl-error-fix/no-such-dsl-method-job @@ -0,0 +1,10 @@ +pipeline { + agent any + stages { + stage('Build') { + steps { + mvn 'clean install' + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/output-job/pipeline-command-substitution-job b/jenkins-modules/jenkins-jobs/output-job/pipeline-command-substitution-job new file mode 100644 index 0000000000..acaacfa867 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/output-job/pipeline-command-substitution-job @@ -0,0 +1,13 @@ +pipeline { + agent any + stages { + stage('Example') { + steps { + script { + def output = sh(script: "echo \$(ls)", returnStdout: true) + echo "Output: ${output}" + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstatus-job b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstatus-job new file mode 100644 index 0000000000..1b1dc7d315 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstatus-job @@ -0,0 +1,17 @@ +pipeline { + agent any + stages { + stage('Example') { + steps { + script { + def status = sh(returnStatus: true, script: 'ls /test') + if (status != 0) { + echo "Error: Command exited with status ${status}" + } else { + echo "Command executed successfully" + } + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdout-job b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdout-job new file mode 100644 index 0000000000..ad00b30d92 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdout-job @@ -0,0 +1,13 @@ +pipeline { + agent any + stages { + stage('Example') { + steps { + script { + def output = sh(returnStdout: true, script: 'pwd') + echo "Output: ${output}" + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdouttrim-job b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdouttrim-job new file mode 100644 index 0000000000..d253173934 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/output-job/pipeline-returnstdouttrim-job @@ -0,0 +1,13 @@ +pipeline { + agent any + stages { + stage('Example') { + steps { + script { + def output = sh(returnStdout: true, returnStdoutTrim: true, script: 'echo " hello "') + echo "Output: '${output}'" + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/parallel-stage-job/pipeline-parallel-job b/jenkins-modules/jenkins-jobs/parallel-stage-job/pipeline-parallel-job new file mode 100644 index 0000000000..c44d61d099 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/parallel-stage-job/pipeline-parallel-job @@ -0,0 +1,34 @@ +pipeline { + agent any + stages { + stage('Build') { + steps { + sh 'echo "Building the application"' + // Add commands to build application + } + } + stage('Test') { + parallel { + stage('Unit Tests') { + steps { + sh 'sleep 5s' + sh 'echo "Running unit tests"' + // Add commands to run unit tests + } + } + stage('Integration Tests') { + steps { + sh 'echo "Running integration tests"' + // Add commands to run integration tests + } + } + } + } + stage('Deploy') { + steps { + sh 'echo "Deploying the application"' + // Add commands to deploy application + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/prevent-build-failure-job/pipeline-prevent-build-failure-job b/jenkins-modules/jenkins-jobs/prevent-build-failure-job/pipeline-prevent-build-failure-job new file mode 100644 index 0000000000..b143f31dc7 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/prevent-build-failure-job/pipeline-prevent-build-failure-job @@ -0,0 +1,16 @@ +pipeline { + agent any + stages { + stage('tryCatch') { + steps { + script { + try { + sh 'test_script.sh' + } catch (e) { + echo "An error occurred: ${e}" + } + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/trigger-another-job/pipeline-trigger-job b/jenkins-modules/jenkins-jobs/trigger-another-job/pipeline-trigger-job new file mode 100644 index 0000000000..e5d958d08f --- /dev/null +++ b/jenkins-modules/jenkins-jobs/trigger-another-job/pipeline-trigger-job @@ -0,0 +1,15 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + echo "parentJob" + } + } + stage('triggerChildJob') { + steps { + build job: "childJob", wait: true + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/zombie-job/pipeline-zombie-job b/jenkins-modules/jenkins-jobs/zombie-job/pipeline-zombie-job new file mode 100644 index 0000000000..8c21ada8c6 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/zombie-job/pipeline-zombie-job @@ -0,0 +1,15 @@ +pipeline { + agent any + stages { + stage('Infinite Loop') { + steps { + script { + while (true) { + println 'This is an infinite loop!' + Thread.sleep(10000) + } + } + } + } + } +} diff --git a/jenkins-modules/jenkins-jobs/zombie-job/zombie-finish-script b/jenkins-modules/jenkins-jobs/zombie-job/zombie-finish-script new file mode 100644 index 0000000000..41090599ee --- /dev/null +++ b/jenkins-modules/jenkins-jobs/zombie-job/zombie-finish-script @@ -0,0 +1,3 @@ +Jenkins.instance.getItemByFullName("sampleZombieJob") + .getBuildByNumber(17) + .finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build")); diff --git a/jenkins-modules/jenkins-jobs/zombie-job/zombie-interrupt-script b/jenkins-modules/jenkins-jobs/zombie-job/zombie-interrupt-script new file mode 100644 index 0000000000..bf79f50ab9 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/zombie-job/zombie-interrupt-script @@ -0,0 +1,6 @@ +Thread.getAllStackTraces().keySet().each() { + if (it.name.contains('sampleZombieJob')) { + println "Stopping $it.name" + it.interrupt() + } +} diff --git a/jenkins-modules/jenkins-jobs/zombie-job/zombie-stop-script b/jenkins-modules/jenkins-jobs/zombie-job/zombie-stop-script new file mode 100644 index 0000000000..40edcf3ff6 --- /dev/null +++ b/jenkins-modules/jenkins-jobs/zombie-job/zombie-stop-script @@ -0,0 +1,6 @@ +Thread.getAllStackTraces().keySet().each() { + if (it.name.contains('sampleZombieJob')) { + println "Stopping $it.name" + it.stop() + } +} diff --git a/jenkins/plugins/README.md b/jenkins-modules/plugins/README.md similarity index 100% rename from jenkins/plugins/README.md rename to jenkins-modules/plugins/README.md diff --git a/jenkins/plugins/pom.xml b/jenkins-modules/plugins/pom.xml similarity index 100% rename from jenkins/plugins/pom.xml rename to jenkins-modules/plugins/pom.xml diff --git a/jenkins/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStats.java b/jenkins-modules/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStats.java similarity index 100% rename from jenkins/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStats.java rename to jenkins-modules/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStats.java diff --git a/jenkins/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStatsBuildWrapper.java b/jenkins-modules/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStatsBuildWrapper.java similarity index 100% rename from jenkins/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStatsBuildWrapper.java rename to jenkins-modules/plugins/src/main/java/com/baeldung/jenkins/plugins/ProjectStatsBuildWrapper.java diff --git a/jenkins/plugins/src/main/resources/logback.xml b/jenkins-modules/plugins/src/main/resources/logback.xml similarity index 100% rename from jenkins/plugins/src/main/resources/logback.xml rename to jenkins-modules/plugins/src/main/resources/logback.xml diff --git a/jenkins/plugins/src/main/resources/stats.html b/jenkins-modules/plugins/src/main/resources/stats.html similarity index 100% rename from jenkins/plugins/src/main/resources/stats.html rename to jenkins-modules/plugins/src/main/resources/stats.html diff --git a/jenkins/pom.xml b/jenkins-modules/pom.xml similarity index 85% rename from jenkins/pom.xml rename to jenkins-modules/pom.xml index cdd701f7d3..5cbc47d1f4 100644 --- a/jenkins/pom.xml +++ b/jenkins-modules/pom.xml @@ -3,8 +3,8 @@ 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 - jenkins - jenkins + jenkins-modules + jenkins-modules pom @@ -16,4 +16,5 @@ plugins - + + \ No newline at end of file diff --git a/jenkins/README.md b/jenkins/README.md deleted file mode 100644 index ba3e13cc95..0000000000 --- a/jenkins/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Jenkins - -This is an aggregator modules for Jenkins-related modules. diff --git a/jersey/pom.xml b/jersey/pom.xml index c8a7de66ae..7c7330d84f 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -72,6 +72,11 @@ ${jersey.version} test + + org.glassfish.jersey.connectors + jersey-apache-connector + ${jersey.version} + @@ -95,7 +100,7 @@ - 2.26 + 2.38 \ No newline at end of file diff --git a/jersey/src/main/java/com/baeldung/jersey/client/JerseyClientHeaders.java b/jersey/src/main/java/com/baeldung/jersey/client/JerseyClientHeaders.java index ebcbe1d4ab..29db298e9e 100644 --- a/jersey/src/main/java/com/baeldung/jersey/client/JerseyClientHeaders.java +++ b/jersey/src/main/java/com/baeldung/jersey/client/JerseyClientHeaders.java @@ -1,6 +1,8 @@ package com.baeldung.jersey.client; import com.baeldung.jersey.client.filter.AddHeaderOnRequestFilter; +import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; +import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.glassfish.jersey.client.oauth1.AccessToken; import org.glassfish.jersey.client.oauth1.ConsumerCredentials; @@ -155,7 +157,8 @@ public class JerseyClientHeaders { } public static Response sendRestrictedHeaderThroughDefaultTransportConnector(String headerKey, String headerValue) { - Client client = ClientBuilder.newClient(); + ClientConfig clientConfig = new ClientConfig().connectorProvider(new ApacheConnectorProvider()); + Client client = ClientBuilder.newClient(clientConfig); System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); return client.target(TARGET) diff --git a/jersey/src/test/java/com/baeldung/jersey/server/EchoHeadersUnitTest.java b/jersey/src/test/java/com/baeldung/jersey/server/EchoHeadersUnitTest.java index ac2cc2c4eb..24552f6d81 100644 --- a/jersey/src/test/java/com/baeldung/jersey/server/EchoHeadersUnitTest.java +++ b/jersey/src/test/java/com/baeldung/jersey/server/EchoHeadersUnitTest.java @@ -2,7 +2,6 @@ package com.baeldung.jersey.server; import com.baeldung.jersey.client.JerseyClientHeaders; import com.baeldung.jersey.client.filter.AddHeaderOnRequestFilter; -import org.glassfish.jersey.media.sse.SseFeature; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.Test; diff --git a/jersey/src/test/java/com/baeldung/jersey/server/ItemsUnitTest.java b/jersey/src/test/java/com/baeldung/jersey/server/ItemsUnitTest.java index df85e26b76..b158d63720 100644 --- a/jersey/src/test/java/com/baeldung/jersey/server/ItemsUnitTest.java +++ b/jersey/src/test/java/com/baeldung/jersey/server/ItemsUnitTest.java @@ -9,10 +9,14 @@ import org.glassfish.grizzly.http.server.HttpServer; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; +import org.junit.jupiter.api.Disabled; import com.baeldung.jersey.server.http.EmbeddedHttpServer; +@Disabled +@Ignore public class ItemsUnitTest { private HttpServer server; diff --git a/jgit/pom.xml b/jgit/pom.xml index ca58709583..91881fbec8 100644 --- a/jgit/pom.xml +++ b/jgit/pom.xml @@ -36,6 +36,7 @@ + 4.5.0.201609210915-r diff --git a/jhipster-5/bookstore-monolith/pom.xml b/jhipster-5/bookstore-monolith/pom.xml index ccf7a3c85e..ccaa802a39 100644 --- a/jhipster-5/bookstore-monolith/pom.xml +++ b/jhipster-5/bookstore-monolith/pom.xml @@ -94,10 +94,6 @@ org.apache.commons commons-lang3 - - mysql - mysql-connector-java - org.assertj assertj-core @@ -1175,7 +1171,7 @@ 2.1.1 - 2.0.8.RELEASE + 2.7.8 5.2.17.Final diff --git a/jhipster-modules/README.md b/jhipster-modules/README.md index 93322c146b..11c3d5397f 100644 --- a/jhipster-modules/README.md +++ b/jhipster-modules/README.md @@ -4,5 +4,4 @@ This module contains articles about JHipster. ### Relevant articles: -- [Intro to JHipster](https://www.baeldung.com/jhipster) -- [Building a Basic UAA-Secured JHipster Microservice](https://www.baeldung.com/jhipster-uaa-secured-micro-service) + diff --git a/jmeter/README.md b/jmeter/README.md index e53f411cdb..f01fa4eca5 100644 --- a/jmeter/README.md +++ b/jmeter/README.md @@ -54,4 +54,5 @@ Enjoy it :) - [Configure Jenkins to Run and Show JMeter Tests](https://www.baeldung.com/ops/jenkins-and-jmeter) - [Write Extracted Data to a File Using JMeter](https://www.baeldung.com/jmeter-write-to-file) - [Basic Authentication in JMeter](https://www.baeldung.com/jmeter-basic-auth) -- [JMeter: Latency vs. Load Time](https://www.baeldung.com/java-jmeter-latency-vs-load-time/) +- [JMeter: Latency vs. Load Time](https://www.baeldung.com/java-jmeter-latency-vs-load-time) +- [How Do I Generate a Dashboard Report in JMeter?](https://www.baeldung.com/jmeter-dashboard-report) diff --git a/jmeter/pom.xml b/jmeter/pom.xml index b2e4197dfc..acd823b74f 100644 --- a/jmeter/pom.xml +++ b/jmeter/pom.xml @@ -68,5 +68,96 @@ 2.6.0 + + + + dashboard + + + env + dash + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + launch-web-app + + start + + + com.baeldung.dashboard.DashboardApplication + + + + + + JMeter-Dashboard + + + + + com.lazerycode.jmeter + jmeter-maven-plugin + 3.7.0 + + + + configuration + + configure + + + + + jmeter-tests + + jmeter + results + + + + + ${project.basedir}/src/main/resources/dashboard + ${project.basedir}/src/main/resources/dashboard + true + true + true + + + + org.springframework.boot + spring-boot-maven-plugin + + + stop-web-app + + stop + + + + + + + + + 5.5 + + + \ No newline at end of file diff --git a/jmeter/src/main/java/com/baeldung/dashboard/DashboardApplication.java b/jmeter/src/main/java/com/baeldung/dashboard/DashboardApplication.java new file mode 100644 index 0000000000..6d62ad7e15 --- /dev/null +++ b/jmeter/src/main/java/com/baeldung/dashboard/DashboardApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.dashboard; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.Profile; + +@Profile("JMeter-Dashboard") +@SpringBootApplication(exclude = { SecurityAutoConfiguration.class, MongoAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class, MongoDataAutoConfiguration.class }) +public class DashboardApplication { + public static void main(String[] args) throws Exception { + SpringApplication.run(DashboardApplication.class, args); + } +} diff --git a/jmeter/src/main/java/com/baeldung/dashboard/controllers/Dashboard.java b/jmeter/src/main/java/com/baeldung/dashboard/controllers/Dashboard.java new file mode 100644 index 0000000000..8c749b21d8 --- /dev/null +++ b/jmeter/src/main/java/com/baeldung/dashboard/controllers/Dashboard.java @@ -0,0 +1,42 @@ +package com.baeldung.dashboard.controllers; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Random; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import com.baeldung.dashboard.models.Quotes; + +@Controller +public class Dashboard { + + @GetMapping("/greeting") + public String getGreeting(Model model) { + model.addAttribute("host", System.getProperty("os.name")); + return "greeting"; + } + + @GetMapping("/quote") + public String getQuote(Model model) throws InterruptedException { + Random r = new Random(); + int day = r.nextInt(7); + String quote = Quotes.list.get(day); + + int wait = r.nextInt(6); + Thread.currentThread().sleep(wait); + model.addAttribute("quote", quote); + + return "quote"; + } + + @GetMapping("/time") + public String getTime(Model model) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("hh:mm:ss a"); + LocalDateTime now = LocalDateTime.now(); + model.addAttribute("time", fmt.format(now)); + return "time"; + } +} diff --git a/jmeter/src/main/java/com/baeldung/dashboard/models/Quotes.java b/jmeter/src/main/java/com/baeldung/dashboard/models/Quotes.java new file mode 100644 index 0000000000..7c8e6a732d --- /dev/null +++ b/jmeter/src/main/java/com/baeldung/dashboard/models/Quotes.java @@ -0,0 +1,13 @@ +package com.baeldung.dashboard.models; + +import java.util.Arrays; +import java.util.List; + +public class Quotes { + public static final List list = Arrays.asList("The greatest glory in living lies not in never falling, but in rising every time we fall. -Nelson Mandela\r\n", + "The way to get started is to quit talking and begin doing. -Walt Disney\r\n", + "Your time is limited, so don't waste it living someone else's life. Don't be trapped by dogma – which is living with the results of other people's thinking. -Steve Jobs\r\n", + "If life were predictable it would cease to be life, and be without flavor. -Eleanor Roosevelt\r\n", + "If you look at what you have in life, you'll always have more. If you look at what you don't have in life, you'll never have enough. -Oprah Winfrey\r\n", + "If you set your goals ridiculously high and it's a failure, you will fail above everyone else's success. -James Cameron\r\n", "Life is what happens when you're busy making other plans. -John Lennon"); +} diff --git a/jmeter/src/main/resources/dashboard/ReportsDashboard.csv b/jmeter/src/main/resources/dashboard/ReportsDashboard.csv new file mode 100644 index 0000000000..046666ca2b --- /dev/null +++ b/jmeter/src/main/resources/dashboard/ReportsDashboard.csv @@ -0,0 +1,16 @@ +timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,URL,Latency,IdleTime,Connect +1674622105952,714,HTTP Request (/greeting),200,,Thread Group 1-4,text,true,,430,126,5,5,http://localhost:8080/greeting,705,0,7 +1674622105450,1216,HTTP Request (/greeting),200,,Thread Group 1-1,text,true,,430,126,5,5,http://localhost:8080/greeting,1207,0,54 +1674622105468,1198,HTTP Request (/greeting),200,,Thread Group 1-2,text,true,,430,126,5,5,http://localhost:8080/greeting,1189,0,36 +1674622106064,602,HTTP Request (/greeting),200,,Thread Group 1-5,text,true,,430,126,5,5,http://localhost:8080/greeting,593,0,2 +1674622105800,866,HTTP Request (/greeting),200,,Thread Group 1-3,text,true,,430,126,5,5,http://localhost:8080/greeting,857,0,1 +1674622106669,13,HTTP Request (/quote),200,,Thread Group 1-4,text,true,,515,123,5,5,http://localhost:8080/quote,12,0,0 +1674622106669,16,HTTP Request (/quote),200,,Thread Group 1-2,text,true,,548,123,5,5,http://localhost:8080/quote,16,0,0 +1674622106671,18,HTTP Request (/quote),200,,Thread Group 1-1,text,true,,629,123,5,5,http://localhost:8080/quote,18,0,0 +1674622106669,24,HTTP Request (/quote),200,,Thread Group 1-5,text,true,,602,123,5,5,http://localhost:8080/quote,24,0,0 +1674622106669,29,HTTP Request (/quote),200,,Thread Group 1-3,text,true,,515,123,5,5,http://localhost:8080/quote,29,0,0 +1674622106690,18,HTTP Request (/time),200,,Thread Group 1-1,text,true,,432,122,5,5,http://localhost:8080/time,18,0,0 +1674622106699,9,HTTP Request (/time),200,,Thread Group 1-3,text,true,,432,122,5,5,http://localhost:8080/time,9,0,0 +1674622106683,26,HTTP Request (/time),200,,Thread Group 1-4,text,true,,432,122,5,5,http://localhost:8080/time,25,0,0 +1674622106688,25,HTTP Request (/time),200,,Thread Group 1-2,text,true,,432,122,2,2,http://localhost:8080/time,25,0,0 +1674622106695,18,HTTP Request (/time),200,,Thread Group 1-5,text,true,,432,122,2,2,http://localhost:8080/time,17,0,0 diff --git a/jmeter/src/main/resources/dashboard/ReportsDashboard.jmx b/jmeter/src/main/resources/dashboard/ReportsDashboard.jmx new file mode 100644 index 0000000000..081920c671 --- /dev/null +++ b/jmeter/src/main/resources/dashboard/ReportsDashboard.jmx @@ -0,0 +1,127 @@ + + + + + + false + true + false + + + + + + + + Test Greetings Page + continue + + false + 1 + + 5 + 1 + false + + + true + + + + + + + localhost + 8080 + + + /greeting + GET + true + false + true + false + + + + + + + + + + localhost + 8080 + + + /quote + GET + true + false + true + false + + + + + + + + + + localhost + 8080 + + + /time + GET + true + false + true + false + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + dashapp + + + + + + diff --git a/jmeter/src/main/resources/static/index.html b/jmeter/src/main/resources/static/index.html new file mode 100644 index 0000000000..fe2e1bf095 --- /dev/null +++ b/jmeter/src/main/resources/static/index.html @@ -0,0 +1,15 @@ + + + + + Jmeter Dashboard Test APP + + + + +

Get your Quote here

+

Get your Time here

+

Get your greeting here

+ + + \ No newline at end of file diff --git a/jmeter/src/main/resources/templates/greeting.html b/jmeter/src/main/resources/templates/greeting.html new file mode 100644 index 0000000000..3b023db6b1 --- /dev/null +++ b/jmeter/src/main/resources/templates/greeting.html @@ -0,0 +1,10 @@ + + + + Jmeter Dashboard Test APP + + + +

+ + \ No newline at end of file diff --git a/jmeter/src/main/resources/templates/quote.html b/jmeter/src/main/resources/templates/quote.html new file mode 100644 index 0000000000..8d943c2a3d --- /dev/null +++ b/jmeter/src/main/resources/templates/quote.html @@ -0,0 +1,11 @@ + + + + Jmeter Dashboard Test APP + + + +

+

+ + \ No newline at end of file diff --git a/jmeter/src/main/resources/templates/time.html b/jmeter/src/main/resources/templates/time.html new file mode 100644 index 0000000000..d068bbe050 --- /dev/null +++ b/jmeter/src/main/resources/templates/time.html @@ -0,0 +1,10 @@ + + + + Jmeter Dashboard Test APP + + + +

+ + \ No newline at end of file diff --git a/jsf/pom.xml b/jsf/pom.xml index 88099ef9c4..4e17540557 100644 --- a/jsf/pom.xml +++ b/jsf/pom.xml @@ -15,6 +15,13 @@ + + + javax.annotation + javax.annotation-api + ${javax.annotation-api.version} + + com.sun.faces @@ -70,6 +77,10 @@ 2.2.14 3.0.0 + + 3.3.1 + + 1.3.1 \ No newline at end of file diff --git a/json-modules/gson/src/test/java/com/baeldung/gson/serialization/GsonSerializeUnitTest.java b/json-modules/gson/src/test/java/com/baeldung/gson/serialization/GsonSerializeUnitTest.java index d5051060c4..21d2bedd24 100644 --- a/json-modules/gson/src/test/java/com/baeldung/gson/serialization/GsonSerializeUnitTest.java +++ b/json-modules/gson/src/test/java/com/baeldung/gson/serialization/GsonSerializeUnitTest.java @@ -23,8 +23,8 @@ public class GsonSerializeUnitTest { ActorGson rudyYoungblood = new ActorGson("nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto", "Beatdown", "Wind Walkers")); Movie movie = new Movie("tt0472043", "Mel Gibson", Arrays.asList(rudyYoungblood)); - String expectedOutput = "{\"imdbId\":\"tt0472043\",\"director\":\"Mel Gibson\",\"actors\":[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"Sep 21, 1982 12:00:00 AM\",\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; - Assert.assertEquals(new Gson().toJson(movie), expectedOutput); + String expectedOutput = "{\"imdbId\":\"tt0472043\",\"director\":\"Mel Gibson\",\"actors\":[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"Sep 21, 1982, 12:00:00 AM\",\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; + Assert.assertEquals(expectedOutput, new Gson().toJson(movie)); } @Test diff --git a/json-modules/gson/src/test/java/com/baeldung/gson/serialization/test/GsonSerializationUnitTest.java b/json-modules/gson/src/test/java/com/baeldung/gson/serialization/test/GsonSerializationUnitTest.java index 3b8912d259..13fea27b24 100644 --- a/json-modules/gson/src/test/java/com/baeldung/gson/serialization/test/GsonSerializationUnitTest.java +++ b/json-modules/gson/src/test/java/com/baeldung/gson/serialization/test/GsonSerializationUnitTest.java @@ -1,7 +1,7 @@ package com.baeldung.gson.serialization.test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; + import java.lang.reflect.Type; import java.util.Collection; @@ -88,7 +88,7 @@ public class GsonSerializationUnitTest { String jsonDate = gson.toJson(sourceDate, sourceDateType); System.out.println("jsonDate:\n" + jsonDate); - String expectedResult = "\"Jan 1, 2000 12:00:00 AM\""; + String expectedResult = "\"Jan 1, 2000, 12:00:00 AM\""; assertEquals(expectedResult, jsonDate); } diff --git a/json-modules/json-2/README.md b/json-modules/json-2/README.md index 8087927ad3..750bb064c8 100644 --- a/json-modules/json-2/README.md +++ b/json-modules/json-2/README.md @@ -10,6 +10,7 @@ This module contains articles about JSON. - [Generate a Java Class From JSON](https://www.baeldung.com/java-generate-class-from-json) - [A Guide to FastJson](https://www.baeldung.com/fastjson) - [Check Whether a String is Valid JSON in Java](https://www.baeldung.com/java-validate-json-string) +- [Getting a Value in JSONObject](https://www.baeldung.com/java-jsonobject-get-value) - More Articles: [[<-- prev]](/json-modules/json) diff --git a/json-modules/json-2/pom.xml b/json-modules/json-2/pom.xml index ecffd719c7..82fe689ebf 100644 --- a/json-modules/json-2/pom.xml +++ b/json-modules/json-2/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 json-2 0.0.1-SNAPSHOT @@ -108,6 +107,22 @@ + + commons-io + commons-io + 2.11.0 + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + javax.annotation + javax.annotation-api + 1.3.2 + diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonvalidation/JacksonValidator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonvalidation/JacksonValidator.java index 8c339f46c8..4385b39bb3 100644 --- a/json-modules/json-2/src/main/java/com/baeldung/jsonvalidation/JacksonValidator.java +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonvalidation/JacksonValidator.java @@ -1,11 +1,15 @@ package com.baeldung.jsonvalidation; import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; public class JacksonValidator { - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = JsonMapper.builder() + .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) + .build(); public boolean isValid(String json) { try { diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetter.java b/json-modules/json-2/src/main/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetter.java new file mode 100644 index 0000000000..f8d38106fd --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetter.java @@ -0,0 +1,87 @@ +package com.baeldung.jsonvaluegetter; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class JSONObjectValueGetter { + + /** + * Get values associated with the provided key in the given JSONObject instance + * + * @param jsonObject JSONObject instance in which to search the key + * @param key Key we're interested in + * + * @return List of values associated with the given key, in the order of appearance. + * If the key is absent, empty list is returned. + */ + public List getValuesInObject(JSONObject jsonObject, String key) { + List accumulatedValues = new ArrayList<>(); + for (String currentKey : jsonObject.keySet()) { + Object value = jsonObject.get(currentKey); + if (currentKey.equals(key)) { + accumulatedValues.add(value.toString()); + } + + if (value instanceof JSONObject) { + accumulatedValues.addAll(getValuesInObject((JSONObject)value, key)); + } else if (value instanceof JSONArray) { + accumulatedValues.addAll(getValuesInArray((JSONArray)value, key)); + } + } + + return accumulatedValues; + } + + /** + * Get values associated with the provided key in the given JSONArray instance + * + * @param jsonArray JSONArray instance in which to search the key + * @param key Key we're interested in + * + * @return List of values associated with the given key, in the order of appearance. + * If the key is absent, empty list is returned. + */ + public List getValuesInArray(JSONArray jsonArray, String key) { + List accumulatedValues = new ArrayList<>(); + for (Object obj : jsonArray) { + if (obj instanceof JSONArray) { + accumulatedValues.addAll(getValuesInArray((JSONArray)obj, key)); + } else if (obj instanceof JSONObject) { + accumulatedValues.addAll(getValuesInObject((JSONObject)obj, key)); + } + } + + return accumulatedValues; + } + + /** + * Among all the values associated with the given key, get the N-th value + * + * @param jsonObject JSONObject instance in which to search the key + * @param key Key we're interested in + * @param N Index of the value to get + * + * @return N-th value associated with the key, or null if the key is absent or + * the number of values associated with the key is less than N + */ + public String getNthValue(JSONObject jsonObject, String key, int N) { + List values = getValuesInObject(jsonObject, key); + return (values.size() >= N) ? values.get(N - 1) : null; + } + + /** + * Count the number of values associated with the given key + * + * @param jsonObject JSONObject instance in which to count the key + * @param key Key we're interested in + * + * @return The number of values associated with the given key + */ + public int getCount(JSONObject jsonObject, String key) { + List values = getValuesInObject(jsonObject, key); + return values.size(); + } +} diff --git a/json-modules/json-2/src/test/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetterUnitTest.java b/json-modules/json-2/src/test/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetterUnitTest.java new file mode 100644 index 0000000000..fc17e700eb --- /dev/null +++ b/json-modules/json-2/src/test/java/com/baeldung/jsonvaluegetter/JSONObjectValueGetterUnitTest.java @@ -0,0 +1,69 @@ +package com.baeldung.jsonvaluegetter; + +import org.apache.commons.io.IOUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public class JSONObjectValueGetterUnitTest { + + private static JSONObject jsonObject; + private static JSONObjectValueGetter jsonObjectValueGetter = new JSONObjectValueGetter(); + + @BeforeAll + public static void loadJsonContent() throws IOException { + InputStream inputStream = JSONObjectValueGetterUnitTest.class.getClassLoader().getResourceAsStream("employee.json"); + String jsonString = IOUtils.toString(inputStream, "UTF-8"); + jsonObject = new JSONObject(jsonString); + } + + @Test + public void getValueDirectly() { + JSONArray family = jsonObject.getJSONArray("family"); + JSONObject sonObject = family.getJSONObject(1); + JSONObject sonData = sonObject.getJSONObject("son"); + String sonName = sonData.getString("name"); + Assertions.assertEquals(sonName, "Peter"); + } + + @Test + public void getAllAssociatedValuesRecursively() { + List values = jsonObjectValueGetter.getValuesInObject(jsonObject, "son"); + Assertions.assertEquals(values.size(), 1); + + String sonString = values.get(0); + Assertions.assertTrue(sonString.contains("Peter")); + Assertions.assertTrue(sonString.contains("Schoolboy")); + Assertions.assertTrue(sonString.contains("11")); + + values = jsonObjectValueGetter.getValuesInObject(jsonObject, "name"); + Assertions.assertEquals(values.size(), 3); + + Assertions.assertEquals(values.get(0), "Bob"); + Assertions.assertEquals(values.get(1), "Alice"); + Assertions.assertEquals(values.get(2), "Peter"); + } + + @Test + public void getNthValueRecursively() { + Assertions.assertEquals(jsonObjectValueGetter.getNthValue(jsonObject, "name", 1), "Bob"); + Assertions.assertEquals(jsonObjectValueGetter.getNthValue(jsonObject, "name", 2), "Alice"); + Assertions.assertEquals(jsonObjectValueGetter.getNthValue(jsonObject, "name", 3), "Peter"); + Assertions.assertNull(jsonObjectValueGetter.getNthValue(jsonObject, "nonExistingKey", 1)); + } + + @Test + public void getCountRecursively() { + Assertions.assertEquals(jsonObjectValueGetter.getCount(jsonObject, "name"), 3); + Assertions.assertEquals(jsonObjectValueGetter.getCount(jsonObject, "age"), 3); + Assertions.assertEquals(jsonObjectValueGetter.getCount(jsonObject, "occupation"), 1); + Assertions.assertEquals(jsonObjectValueGetter.getCount(jsonObject, "nonExistingKey"), 0); + } +} diff --git a/json-modules/json-2/src/test/resources/employee.json b/json-modules/json-2/src/test/resources/employee.json new file mode 100644 index 0000000000..095190212a --- /dev/null +++ b/json-modules/json-2/src/test/resources/employee.json @@ -0,0 +1,30 @@ +{ + "name" : "Bob", + "profession" : "Software engineer", + "department" : "Research", + "age" : 40, + "family" : [ + { + "wife" : { + "name" : "Alice", + "profession" : "Doctor", + "age" : 38 + } + }, + { + "son" : { + "name" : "Peter", + "occupation" : "Schoolboy", + "age" : 11 + } + } + ], + "performance" : [ + { + "2020" : 4.5 + }, + { + "2021" : 4.8 + } + ] +} \ No newline at end of file diff --git a/kubernetes-modules/kubernetes-spring/pom.xml b/kubernetes-modules/kubernetes-spring/pom.xml index d91e841bad..05532ab0b0 100644 --- a/kubernetes-modules/kubernetes-spring/pom.xml +++ b/kubernetes-modules/kubernetes-spring/pom.xml @@ -1,50 +1,53 @@ - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.7.5 - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - 11 - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-webflux - + + 4.0.0 + kubernetes-spring + 0.0.1-SNAPSHOT + kubernetes-spring + Intro to Kubernetes with Spring boot - - org.springframework.boot - spring-boot-starter-test - test - - - io.projectreactor - reactor-test - test - - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-webflux + - + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 11 + + + \ No newline at end of file diff --git a/kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/DemoApplicationTests.java b/kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/SpringContextTest.java similarity index 85% rename from kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/DemoApplicationTests.java rename to kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/SpringContextTest.java index 2778a6a7ea..86bb6c3038 100644 --- a/kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/DemoApplicationTests.java +++ b/kubernetes-modules/kubernetes-spring/src/test/java/com/example/demo/SpringContextTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class DemoApplicationTests { +class SpringContextTest { @Test void contextLoads() { diff --git a/kubernetes-modules/pom.xml b/kubernetes-modules/pom.xml index fe8ffab82a..e120f89019 100644 --- a/kubernetes-modules/pom.xml +++ b/kubernetes-modules/pom.xml @@ -15,6 +15,7 @@ k8s-intro k8s-admission-controller + \ No newline at end of file diff --git a/libraries-2/pom.xml b/libraries-2/pom.xml index ea1b2ca8b6..1d5cde75a2 100644 --- a/libraries-2/pom.xml +++ b/libraries-2/pom.xml @@ -12,22 +12,6 @@ 1.0.0-SNAPSHOT - - - jboss-public-repository-group - JBoss Public Repository Group - http://repository.jboss.org/nexus/content/groups/public/ - - true - never - - - true - daily - - - - org.mapdb @@ -82,6 +66,12 @@ edu.uci.ics crawler4j ${crawler4j.version} + + + com.sleepycat + je + + com.github.jknack @@ -119,22 +109,40 @@ spring-jdbc ${spring.version} + + com.sleepycat + je + 18.3.12 + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + --add-exports=java.base/jdk.internal.ref=ALL-UNNAMED --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED + + + + + - 3.0.7 - 4.8.28 - 6.0.0.Final - 3.9.6 - 3.17.2 + 3.0.8 + 4.8.153 + 7.1.0.Final + 4.7.0 + 3.24ea1 4.4.0 - 2.1.4.RELEASE - 0.28.3 + 2.7.8 + 1.11.0 1.1.0 - 4.1.2 - 6.17.0 - 5.1.9.RELEASE - 2.5.0 + 4.3.1 + 6.20.0 + 5.3.25 + 2.7.1 \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/parallel_collectors/ParallelCollectorsUnitTest.java b/libraries-2/src/test/java/com/baeldung/parallel_collectors/ParallelCollectorsUnitTest.java index adc753a8ad..e1ad2f7537 100644 --- a/libraries-2/src/test/java/com/baeldung/parallel_collectors/ParallelCollectorsUnitTest.java +++ b/libraries-2/src/test/java/com/baeldung/parallel_collectors/ParallelCollectorsUnitTest.java @@ -40,7 +40,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); CompletableFuture> results = ids.stream() - .collect(parallelToList(i -> fetchById(i), executor, 4)); + .collect(parallelToList(ParallelCollectorsUnitTest::fetchById, executor, 4)); System.out.println(results.join()); } @@ -52,7 +52,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); List results = ids.stream() - .collect(parallelToList(i -> fetchById(i), executor, 4)) + .collect(parallelToList(ParallelCollectorsUnitTest::fetchById, executor, 4)) .join(); System.out.println(results); // [user-1, user-2, user-3] @@ -92,7 +92,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); ids.stream() - .collect(parallel(i -> fetchByIdWithRandomDelay(i), executor, 4)) + .collect(parallel(ParallelCollectorsUnitTest::fetchByIdWithRandomDelay, executor, 4)) .forEach(System.out::println); } @@ -103,7 +103,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); ids.stream() - .collect(parallelOrdered(i -> fetchByIdWithRandomDelay(i), executor, 4)) + .collect(parallelOrdered(ParallelCollectorsUnitTest::fetchByIdWithRandomDelay, executor, 4)) .forEach(System.out::println); } @@ -114,7 +114,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); Map results = ids.stream() - .collect(parallelToMap(i -> i, i -> fetchById(i), executor, 4)) + .collect(parallelToMap(i -> i, ParallelCollectorsUnitTest::fetchById, executor, 4)) .join(); System.out.println(results); // {1=user-1, 2=user-2, 3=user-3} @@ -127,7 +127,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); Map results = ids.stream() - .collect(parallelToMap(i -> i, i -> fetchById(i), TreeMap::new, executor, 4)) + .collect(parallelToMap(i -> i, ParallelCollectorsUnitTest::fetchById, TreeMap::new, executor, 4)) .join(); System.out.println(results); // {1=user-1, 2=user-2, 3=user-3} @@ -140,7 +140,7 @@ public class ParallelCollectorsUnitTest { List ids = Arrays.asList(1, 2, 3); Map results = ids.stream() - .collect(parallelToMap(i -> i, i -> fetchById(i), TreeMap::new, (s1, s2) -> s1, executor, 4)) + .collect(parallelToMap(i -> i, ParallelCollectorsUnitTest::fetchById, TreeMap::new, (s1, s2) -> s1, executor, 4)) .join(); System.out.println(results); // {1=user-1, 2=user-2, 3=user-3} diff --git a/libraries-apache-commons-io/pom.xml b/libraries-apache-commons-io/pom.xml index b45572ddad..7cac50a8e2 100644 --- a/libraries-apache-commons-io/pom.xml +++ b/libraries-apache-commons-io/pom.xml @@ -26,7 +26,7 @@ - 1.9.0 + 1.10.0 \ No newline at end of file diff --git a/libraries-apache-commons-io/src/test/java/com/baeldung/commons/io/csv/CSVReaderWriterUnitTest.java b/libraries-apache-commons-io/src/test/java/com/baeldung/commons/io/csv/CSVReaderWriterUnitTest.java index b99f4e8bc3..b37613e962 100644 --- a/libraries-apache-commons-io/src/test/java/com/baeldung/commons/io/csv/CSVReaderWriterUnitTest.java +++ b/libraries-apache-commons-io/src/test/java/com/baeldung/commons/io/csv/CSVReaderWriterUnitTest.java @@ -1,9 +1,11 @@ package com.baeldung.commons.io.csv; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.CSVRecord; -import org.junit.Test; import java.io.FileReader; import java.io.IOException; @@ -13,9 +15,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; - -public class CSVReaderWriterUnitTest { +class CSVReaderWriterUnitTest { public static final Map AUTHOR_BOOK_MAP = Collections.unmodifiableMap(new LinkedHashMap() { { @@ -24,12 +24,24 @@ public class CSVReaderWriterUnitTest { } }); public static final String[] HEADERS = { "author", "title" }; + + enum BookHeaders{ + author, title + } + public static final String EXPECTED_FILESTREAM = "author,title\r\n" + "Dan Simmons,Hyperion\r\n" + "Douglas Adams,The Hitchhiker's Guide to the Galaxy"; @Test - public void givenCSVFile_whenRead_thenContentsAsExpected() throws IOException { + void givenCSVFile_whenReadWithArrayHeader_thenContentsAsExpected() throws IOException { Reader in = new FileReader("src/test/resources/book.csv"); - Iterable records = CSVFormat.DEFAULT.withHeader(HEADERS).withFirstRecordAsHeader().parse(in); + + CSVFormat csvFormat = CSVFormat.DEFAULT.builder() + .setHeader(HEADERS) + .setSkipHeaderRecord(true) + .build(); + + Iterable records = csvFormat.parse(in); + for (CSVRecord record : records) { String author = record.get("author"); String title = record.get("title"); @@ -38,9 +50,32 @@ public class CSVReaderWriterUnitTest { } @Test - public void givenAuthorBookMap_whenWrittenToStream_thenOutputStreamAsExpected() throws IOException { + void givenCSVFile_whenReadWithEnumHeader_thenContentsAsExpected() throws IOException { + Reader in = new FileReader("src/test/resources/book.csv"); + + CSVFormat csvFormat = CSVFormat.DEFAULT.builder() + .setHeader(BookHeaders.class) + .setSkipHeaderRecord(true) + .build(); + + Iterable records = csvFormat.parse(in); + + for (CSVRecord record : records) { + String author = record.get(BookHeaders.author); + String title = record.get(BookHeaders.title); + assertEquals(AUTHOR_BOOK_MAP.get(author), title); + } + } + + @Test + void givenAuthorBookMap_whenWrittenToStream_thenOutputStreamAsExpected() throws IOException { StringWriter sw = new StringWriter(); - try (final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withHeader(HEADERS))) { + + CSVFormat csvFormat = CSVFormat.DEFAULT.builder() + .setHeader(BookHeaders.class) + .build(); + + try (final CSVPrinter printer = new CSVPrinter(sw, csvFormat)) { AUTHOR_BOOK_MAP.forEach((author, title) -> { try { printer.printRecord(author, title); @@ -49,7 +84,8 @@ public class CSVReaderWriterUnitTest { } }); } - assertEquals(EXPECTED_FILESTREAM, sw.toString().trim()); + assertEquals(EXPECTED_FILESTREAM, sw.toString() + .trim()); } } diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index d5322267d0..f673ebd470 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -15,12 +15,12 @@ org.apache.flink - flink-connector-kafka-0.11_2.11 + flink-connector-kafka ${flink.version} org.apache.flink - flink-streaming-java_2.11 + flink-streaming-java ${flink.version} @@ -47,7 +47,7 @@ org.apache.flink - flink-test-utils_2.11 + flink-test-utils ${flink.version} test @@ -136,6 +136,21 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + nm-repo @@ -146,12 +161,12 @@ - 1.5.0 + 1.16.1 1.6.0 0.1.0 1.0.3 - 9.1.5.Final - 4.3.8.RELEASE + 14.0.6.Final + 5.3.25 4.0.0 1.1.0 3.0.0 diff --git a/libraries-data-db/pom.xml b/libraries-data-db/pom.xml index 8e5140458e..6c72a4902c 100644 --- a/libraries-data-db/pom.xml +++ b/libraries-data-db/pom.xml @@ -127,8 +127,8 @@ - mysql - mysql-connector-java + com.mysql + mysql-connector-j diff --git a/libraries-data-io/pom.xml b/libraries-data-io/pom.xml index 640bf1ba07..2e126610d4 100644 --- a/libraries-data-io/pom.xml +++ b/libraries-data-io/pom.xml @@ -46,9 +46,9 @@ ${google-sheets.version} - javax.xml.bind - jaxb-api - ${jaxb-api.version} + org.glassfish.jaxb + jaxb-runtime + ${jaxb-runtime.version} org.docx4j @@ -104,8 +104,8 @@ 4.1 1.23.0 v4-rev493-1.21.0 - 3.3.5 - 2.1 + 6.1.2 + 2.3.1 2.8.7 1.15 0.14.2 diff --git a/libraries-data/pom.xml b/libraries-data/pom.xml index 85edf8b69a..6ba48a9d66 100644 --- a/libraries-data/pom.xml +++ b/libraries-data/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 libraries-data libraries-data @@ -34,7 +34,7 @@ org.apache.ignite ignite-spring-data - ${ignite.version} + ${ignite-spring-data.version} com.google.code.gson @@ -58,6 +58,11 @@ crunch-core ${org.apache.crunch.crunch-core.version} + + org.javassist + javassist + ${javassist.version} + org.apache.hadoop hadoop-client @@ -133,11 +138,42 @@ com.googlecode.jmapper-framework jmapper-core ${jmapper.version} + + + com.thoughtworks.xstream + xstream + + + + com.thoughtworks.xstream + xstream + 1.4.16 + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED + --add-opens java.base/jdk.internal.misc=ALL-UNNAMED + --add-opens java.base/sun.nio.ch=ALL-UNNAMED + --add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED + --add-opens jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED + --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/java.nio=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + + + org.apache.maven.plugins maven-assembly-plugin @@ -166,11 +202,14 @@ + 11 + 11 2.3 3.1 1.2.2 3.3.1 - 2.4.0 + 2.14.0 + 2.9.1 2.9.1 1.1.1 1.5.0 @@ -178,6 +217,7 @@ 1.0.0 2.2.0 1.6.0.1 + 3.29.2-GA \ No newline at end of file diff --git a/libraries-data/src/test/java/com/baeldung/crunch/StopWordFilterUnitTest.java b/libraries-data/src/test/java/com/baeldung/crunch/StopWordFilterUnitTest.java index fffefc2bfb..0bb03016d8 100644 --- a/libraries-data/src/test/java/com/baeldung/crunch/StopWordFilterUnitTest.java +++ b/libraries-data/src/test/java/com/baeldung/crunch/StopWordFilterUnitTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue; import org.apache.crunch.FilterFn; import org.apache.crunch.PCollection; import org.apache.crunch.impl.mem.MemPipeline; +import org.junit.Ignore; import org.junit.Test; import com.google.common.collect.ImmutableList; diff --git a/libraries-data/src/test/java/com/baeldung/crunch/ToUpperCaseWithCounterFnUnitTest.java b/libraries-data/src/test/java/com/baeldung/crunch/ToUpperCaseWithCounterFnUnitTest.java index 76294d273d..00c508e605 100644 --- a/libraries-data/src/test/java/com/baeldung/crunch/ToUpperCaseWithCounterFnUnitTest.java +++ b/libraries-data/src/test/java/com/baeldung/crunch/ToUpperCaseWithCounterFnUnitTest.java @@ -6,6 +6,7 @@ import org.apache.crunch.PCollection; import org.apache.crunch.impl.mem.MemPipeline; import org.apache.crunch.types.writable.Writables; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import com.google.common.collect.ImmutableList; diff --git a/libraries-files/README.md b/libraries-files/README.md index 4157769a0d..feb09332df 100644 --- a/libraries-files/README.md +++ b/libraries-files/README.md @@ -2,3 +2,4 @@ ### Relevant Articles: - [How to Parse an INI File in Java](https://www.baeldung.com/java-parse-ini-file) +- [Using Watermarks with iText in Java](https://www.baeldung.com/java-watermarks-with-itext) diff --git a/libraries-files/output/aliceandpaul.pdf b/libraries-files/output/aliceandpaul.pdf new file mode 100644 index 0000000000..de71693db5 Binary files /dev/null and b/libraries-files/output/aliceandpaul.pdf differ diff --git a/libraries-files/output/alicepaulwithoutwatermark.pdf b/libraries-files/output/alicepaulwithoutwatermark.pdf new file mode 100644 index 0000000000..f291340bc1 --- /dev/null +++ b/libraries-files/output/alicepaulwithoutwatermark.pdf @@ -0,0 +1,43 @@ +%PDF-1.7 +% +5 0 obj +<>stream +x[o7+) l-ND@Y-+. 40[&g9sfx<.՚bsO:бY{0fzUk.379rQ#,=2^N:Vtx}IZNvq;Ovj} +]t:c+uƽJ̒:gǖd]̰8I4/l :7yTU "$|v4Dg=/_ֲDh٘TנB@.;QW#mvv|E+j*D]+yLme:v>)(hWuD=pI*qy,U>*4^{)h6:\9kIjIE@W@"+XZ>Zg(m!>qmsbZzZ @9[wյ<{iⱣxUe#jΡ1\W\èϿhCq~wUtyߎ0\x$8bI\pN|RE>>>/TrimBox[0 0 595 842]/Type/Page>> +endobj +1 0 obj +<> +endobj +3 0 obj +<> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +2 0 obj +<> +endobj +xref +0 8 +0000000000 65535 f +0000001238 00000 n +0000001611 00000 n +0000001283 00000 n +0000001096 00000 n +0000000015 00000 n +0000001433 00000 n +0000001523 00000 n +trailer +<<216b46f23ae9d6b57462e9f47fac0cc5>]/Info 3 0 R/Root 1 0 R/Size 8>> +%iText-Core-7.2.4 +startxref +1662 +%%EOF diff --git a/libraries-files/output/aliceupdated.pdf b/libraries-files/output/aliceupdated.pdf new file mode 100644 index 0000000000..13e1cbd91f Binary files /dev/null and b/libraries-files/output/aliceupdated.pdf differ diff --git a/libraries-files/pom.xml b/libraries-files/pom.xml index efb102712c..b36dc150a8 100644 --- a/libraries-files/pom.xml +++ b/libraries-files/pom.xml @@ -37,6 +37,18 @@ jackson-databind ${jackson.version} + + com.itextpdf + itext7-core + 7.2.4 + pom + + + org.assertj + assertj-core + 3.23.1 + test + diff --git a/libraries-files/src/main/java/com/baeldung/iTextPDF/StoryTime.java b/libraries-files/src/main/java/com/baeldung/iTextPDF/StoryTime.java new file mode 100644 index 0000000000..78977ea160 --- /dev/null +++ b/libraries-files/src/main/java/com/baeldung/iTextPDF/StoryTime.java @@ -0,0 +1,126 @@ +package com.baeldung.iTextPDF; + +import static com.itextpdf.layout.properties.TextAlignment.CENTER; +import static com.itextpdf.layout.properties.VerticalAlignment.TOP; +import static java.lang.Math.PI; + +import java.io.File; +import java.io.IOException; + +import com.itextpdf.io.font.constants.StandardFonts; +import com.itextpdf.kernel.font.PdfFont; +import com.itextpdf.kernel.font.PdfFontFactory; +import com.itextpdf.kernel.geom.PageSize; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfPage; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.canvas.PdfCanvas; +import com.itextpdf.kernel.pdf.extgstate.PdfExtGState; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.element.Text; + +public class StoryTime { + + public static final String OUTPUT_FILE = "output/aliceupdated.pdf"; + + public String alice = " Alice was a curious young girl who one day stumbled upon a strange, talking rabbit." + " The rabbit, in a hurry, invited Alice to follow him down a rabbit hole." + + "Alice, not one to turn down an adventure, eagerly followed the rabbit and found herself tumbling down a long, dark tunnel.As she fell, Alice passed through a small door and into a fantastical world filled with talking animals and peculiar characters." + + "She met the Cheshire Cat, who seemed to appear and disappear at will, and the Mad Hatter, who invited her to a tea party." + + "Alice also encountered the tyrannical Queen of Hearts, who was quick to anger and ordered the beheading of anyone who crossed her." + + "Despite the dangers, Alice remained determined to find her way home and eventually stumbled upon the key to the door that would take her back to the real world." + + " As Alice stepped through the door and back into reality, she couldn't help but wonder if it had all been a dream. But the memories of her adventures in Wonderland stayed with her forever, and she often found herself longing to return to that strange and magical place."; + + public String paul = " Paulinho is a Brazilian professional footballer who currently plays as a midfielder for Guangzhou Evergrande Taobao in the Chinese Super League." + + "He has also played for several top clubs around the world, including Barcelona, Tottenham Hotspur, and Guangzhou Evergrande. Paulinho has represented Brazil at the international level and has won several accolades throughout his career, including the Copa America and the Chinese Super League title." + + "He is known for his strong work ethic and powerful offensive play."; + + public static void main(String[] args) throws IOException { + File file = new File(OUTPUT_FILE); + file.getParentFile() + .mkdirs(); + + // new StoryTime().createPdf(); + new StoryTime().addWatermarkToExistingPdf(); + + } + + public void createPdf() throws IOException { + StoryTime storyTime = new StoryTime(); + String waterMark = "CONFIDENTIAL"; + PdfWriter writer = new PdfWriter(storyTime.OUTPUT_FILE); + PdfDocument pdf = new PdfDocument(writer); + + try (Document document = new Document(pdf)) { + + document.add(new Paragraph(storyTime.alice).setFont(PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN))); + document.add(new Paragraph(storyTime.paul)); + + Paragraph paragraph = storyTime.createWatermarkParagraph(waterMark); + for (int i = 1; i <= document.getPdfDocument() + .getNumberOfPages(); i++) { + + storyTime.addWatermarkToPage(document, i, paragraph, 0f); + } + } + } + + public void addWatermarkToExistingPdf() throws IOException { + StoryTime storyTime = new StoryTime(); + String outputPdf = "output/aliceupdated.pdf"; + String watermark = "CONFIDENTIAL"; + + try (PdfDocument pdfDocument = new PdfDocument(new PdfReader("output/alicepaulwithoutwatermark.pdf"), new PdfWriter(outputPdf))) { + Document document = new Document(pdfDocument); + + Paragraph paragraph = storyTime.createWatermarkParagraph(watermark); + PdfExtGState transparentGraphicState = new PdfExtGState().setFillOpacity(0.5f); + for (int i = 1; i <= document.getPdfDocument() + .getNumberOfPages(); i++) { + storyTime.addWatermarkToExistingPage(document, i, paragraph, transparentGraphicState, 0f); + } + } + } + + public Paragraph createWatermarkParagraph(String watermark) throws IOException { + PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA); + Text text = new Text(watermark); + text.setFont(font); + text.setFontSize(56); + text.setOpacity(0.5f); + + return new Paragraph(text); + } + + public void addWatermarkToPage(Document document, int pageIndex, Paragraph paragraph, float verticalOffset) { + PdfPage pdfPage = document.getPdfDocument() + .getPage(pageIndex); + PageSize pageSize = (PageSize) pdfPage.getPageSizeWithRotation(); + + float x = (pageSize.getLeft() + pageSize.getRight()) / 2; + float y = (pageSize.getTop() + pageSize.getBottom()) / 2; + float xOffset = 100f / 2; + float rotationInRadians = (float) (PI / 180 * 45f); + document.showTextAligned(paragraph, x - xOffset, y + verticalOffset, pageIndex, CENTER, TOP, rotationInRadians); + } + + public void addWatermarkToExistingPage(Document document, int pageIndex, Paragraph paragraph, PdfExtGState graphicState, float verticalOffset) { + PdfDocument pdfDoc = document.getPdfDocument(); + PdfPage pdfPage = pdfDoc.getPage(pageIndex); + PageSize pageSize = (PageSize) pdfPage.getPageSizeWithRotation(); + + float x = (pageSize.getLeft() + pageSize.getRight()) / 2; + float y = (pageSize.getTop() + pageSize.getBottom()) / 2; + PdfCanvas over = new PdfCanvas(pdfDoc.getPage(pageIndex)); + over.saveState(); + over.setExtGState(graphicState); + float xOffset = 100f / 2; + float rotationInRadians = (float) (PI / 180 * 45f); + document.showTextAligned(paragraph, x - xOffset, y + verticalOffset, pageIndex, CENTER, TOP, rotationInRadians); + document.flush(); + over.restoreState(); + over.release(); + } + +} diff --git a/libraries-files/src/test/java/com/baeldung/iTextPDFTest/AddWaterMarkToExistingPdfUnitTest.java b/libraries-files/src/test/java/com/baeldung/iTextPDFTest/AddWaterMarkToExistingPdfUnitTest.java new file mode 100644 index 0000000000..4e45fe4281 --- /dev/null +++ b/libraries-files/src/test/java/com/baeldung/iTextPDFTest/AddWaterMarkToExistingPdfUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.iTextPDFTest; + +import static com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor.getTextFromPage; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.baeldung.iTextPDF.StoryTime; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy; +import com.itextpdf.kernel.pdf.extgstate.PdfExtGState; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Paragraph; + +class AddWaterMarkToExistingPdfUnitTest { + + @Test + public void givenAnExistingPDF_whenManipulatedPDFWithIText_thenGeneratePDFwithWatermarks() throws IOException { + StoryTime storyTime = new StoryTime(); + String outputPdf = "output/aliceupdated.pdf"; + String watermark = "CONFIDENTIAL"; + + LocationTextExtractionStrategy extStrategy = new LocationTextExtractionStrategy(); + try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(outputPdf))) { + for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) { + String textFromPage = getTextFromPage(pdfDocument.getPage(i), extStrategy); + assertThat(textFromPage).contains(watermark); + } + } + + } + +} diff --git a/libraries-files/src/test/java/com/baeldung/iTextPDFTest/GenerateNewPdfWithWatermarkUnitTest.java b/libraries-files/src/test/java/com/baeldung/iTextPDFTest/GenerateNewPdfWithWatermarkUnitTest.java new file mode 100644 index 0000000000..0d383d2f38 --- /dev/null +++ b/libraries-files/src/test/java/com/baeldung/iTextPDFTest/GenerateNewPdfWithWatermarkUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.iTextPDFTest; + +import static com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor.getTextFromPage; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import com.baeldung.iTextPDF.StoryTime; +import com.itextpdf.io.font.constants.StandardFonts; +import com.itextpdf.kernel.font.PdfFontFactory; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Paragraph; + +class GenerateNewPdfWithWatermarkUnitTest { + + @Test + public void givenNewTexts_whenGeneratingNewPDFWithIText_thenGeneratePDFwithWatermarks() throws IOException { + StoryTime storyTime = new StoryTime(); + String waterMark = "CONFIDENTIAL"; + + LocationTextExtractionStrategy extStrategy = new LocationTextExtractionStrategy(); + try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(storyTime.OUTPUT_FILE))) { + for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) { + String textFromPage = getTextFromPage(pdfDocument.getPage(i), extStrategy); + assertThat(textFromPage).contains(waterMark); + } + } + + } + +} diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index 6d3bbcd26c..62c476a82c 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -96,8 +96,26 @@ + + org.glassfish.jaxb + jaxb-runtime + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + 5.6.0 1.3.1 diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java new file mode 100644 index 0000000000..cc0da187b9 --- /dev/null +++ b/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java @@ -0,0 +1,86 @@ +package com.baeldung.digitalsignature; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; + +import javax.crypto.Cipher; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.*; +import java.security.cert.Certificate; +import java.util.Arrays; + +public class DigitalSignatureUtils { + + public static PrivateKey getPrivateKey(String file, char[] password, String storeType, String alias) throws Exception { + KeyStore keyStore = KeyStore.getInstance(storeType); + keyStore.load(new FileInputStream(file), password); + return (PrivateKey) keyStore.getKey(alias, password); + } + + public static PublicKey getPublicKey(String file, char[] password, String storeType, String alias) throws Exception { + KeyStore keyStore = KeyStore.getInstance(storeType); + keyStore.load(new FileInputStream(file), password); + Certificate certificate = keyStore.getCertificate(alias); + return certificate.getPublicKey(); + } + + public static byte[] sign(byte[] message, String signingAlgorithm, PrivateKey signingKey) throws SecurityException { + try { + Signature signature = Signature.getInstance(signingAlgorithm); + signature.initSign(signingKey); + signature.update(message); + return signature.sign(); + } catch (GeneralSecurityException exp) { + throw new SecurityException("Error during signature generation", exp); + } + } + + public static boolean verify(byte[] messageBytes, String signingAlgorithm, PublicKey publicKey, byte[] signedData) { + try { + Signature signature = Signature.getInstance(signingAlgorithm); + signature.initVerify(publicKey); + signature.update(messageBytes); + return signature.verify(signedData); + } catch (GeneralSecurityException exp) { + throw new SecurityException("Error during verifying", exp); + } + } + + public static byte[] signWithMessageDigestAndCipher(byte[] messageBytes, String hashingAlgorithm, PrivateKey privateKey) { + try { + MessageDigest md = MessageDigest.getInstance(hashingAlgorithm); + byte[] messageHash = md.digest(messageBytes); + DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new DefaultDigestAlgorithmIdentifierFinder(); + AlgorithmIdentifier hashingAlgorithmIdentifier = hashAlgorithmFinder.find(hashingAlgorithm); + DigestInfo digestInfo = new DigestInfo(hashingAlgorithmIdentifier, messageHash); + byte[] hashToEncrypt = digestInfo.getEncoded(); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + return cipher.doFinal(hashToEncrypt); + } catch (GeneralSecurityException | IOException exp) { + throw new SecurityException("Error during signature generation", exp); + } + } + + public static boolean verifyWithMessageDigestAndCipher(byte[] messageBytes, String hashingAlgorithm, PublicKey publicKey, byte[] encryptedMessageHash) { + try { + MessageDigest md = MessageDigest.getInstance(hashingAlgorithm); + byte[] newMessageHash = md.digest(messageBytes); + DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new DefaultDigestAlgorithmIdentifierFinder(); + AlgorithmIdentifier hashingAlgorithmIdentifier = hashAlgorithmFinder.find(hashingAlgorithm); + DigestInfo digestInfo = new DigestInfo(hashingAlgorithmIdentifier, newMessageHash); + byte[] hashToEncrypt = digestInfo.getEncoded(); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + byte[] decryptedMessageHash = cipher.doFinal(encryptedMessageHash); + return Arrays.equals(decryptedMessageHash, hashToEncrypt); + } catch (GeneralSecurityException | IOException exp) { + throw new SecurityException("Error during verifying", exp); + } + } +} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java deleted file mode 100644 index 9f1e5808c3..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.digitalsignature; - -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; - -public class Utils { - - private static final String STORE_TYPE = "PKCS12"; - private static final char[] PASSWORD = "changeit".toCharArray(); - private static final String SENDER_KEYSTORE = "sender_keystore.p12"; - private static final String SENDER_ALIAS = "senderKeyPair"; - - public static final String SIGNING_ALGORITHM = "SHA256withRSA"; - - private static final String RECEIVER_KEYSTORE = "receiver_keystore.p12"; - private static final String RECEIVER_ALIAS = "receiverKeyPair"; - - public static PrivateKey getPrivateKey() throws Exception { - KeyStore keyStore = KeyStore.getInstance(STORE_TYPE); - keyStore.load(new FileInputStream(SENDER_KEYSTORE), PASSWORD); - return (PrivateKey) keyStore.getKey(SENDER_ALIAS, PASSWORD); - } - - public static PublicKey getPublicKey() throws Exception { - KeyStore keyStore = KeyStore.getInstance(STORE_TYPE); - keyStore.load(new FileInputStream(RECEIVER_KEYSTORE), PASSWORD); - Certificate certificate = keyStore.getCertificate(RECEIVER_ALIAS); - return certificate.getPublicKey(); - } -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java deleted file mode 100644 index 78d40dd365..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.digitalsignature.level1; - -import com.baeldung.digitalsignature.Utils; - -import javax.crypto.Cipher; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.PrivateKey; - -public class DigitalSignatureWithMessageDigestAndCipherSigning { - - public static void main(String[] args) throws Exception { - - PrivateKey privateKey = Utils.getPrivateKey(); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] messageHash = md.digest(messageBytes); - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - byte[] digitalSignature = cipher.doFinal(messageHash); - - Files.write(Paths.get("target/digital_signature_1"), digitalSignature); - } -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java deleted file mode 100644 index 0b242a44fb..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.digitalsignature.level1; - -import com.baeldung.digitalsignature.Utils; - -import javax.crypto.Cipher; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.PublicKey; -import java.util.Arrays; - -public class DigitalSignatureWithMessageDigestAndCipherVerifying { - - public static void main(String[] args) throws Exception { - - PublicKey publicKey = Utils.getPublicKey(); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] newMessageHash = md.digest(messageBytes); - - byte[] encryptedMessageHash = Files.readAllBytes(Paths.get("target/digital_signature_1")); - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - byte[] decryptedMessageHash = cipher.doFinal(encryptedMessageHash); - - boolean isCorrect = Arrays.equals(decryptedMessageHash, newMessageHash); - System.out.println("Signature " + (isCorrect ? "correct" : "incorrect")); - } - -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java deleted file mode 100644 index afc8fd1045..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.digitalsignature.level2; - -import com.baeldung.digitalsignature.Utils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.PrivateKey; -import java.security.Signature; - -public class DigitalSignatureWithSignatureSigning { - - public static void main(String[] args) throws Exception { - - PrivateKey privateKey = Utils.getPrivateKey(); - - Signature signature = Signature.getInstance(Utils.SIGNING_ALGORITHM); - signature.initSign(privateKey); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - signature.update(messageBytes); - byte[] digitalSignature = signature.sign(); - - Files.write(Paths.get("target/digital_signature_2"), digitalSignature); - } - -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java deleted file mode 100644 index ee34be989c..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.digitalsignature.level2; - -import com.baeldung.digitalsignature.Utils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.PublicKey; -import java.security.Signature; - -public class DigitalSignatureWithSignatureVerifying { - - public static void main(String[] args) throws Exception { - - PublicKey publicKey = Utils.getPublicKey(); - - byte[] sig = Files.readAllBytes(Paths.get("target/digital_signature_2")); - - Signature signature = Signature.getInstance(Utils.SIGNING_ALGORITHM); - signature.initVerify(publicKey); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - signature.update(messageBytes); - - boolean isCorrect = signature.verify(sig); - System.out.println("Signature " + (isCorrect ? "correct" : "incorrect")); - } -} diff --git a/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java b/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java new file mode 100644 index 0000000000..65058dca52 --- /dev/null +++ b/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.digitalsignature; + +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.PrivateKey; +import java.security.PublicKey; + +import static org.junit.Assert.assertTrue; + +public class DigitalSignatureUnitTest { + + String messagePath = "src/test/resources/digitalsignature/message.txt"; + String senderKeyStore = "src/test/resources/digitalsignature/sender_keystore.jks"; + String receiverKeyStore = "src/test/resources/digitalsignature/receiver_keystore.jks"; + String storeType = "JKS"; + String senderAlias = "senderKeyPair"; + String receiverAlias = "receiverKeyPair"; + char[] password = "changeit".toCharArray(); + String signingAlgorithm = "SHA256withRSA"; + String hashingAlgorithm = "SHA-256"; + + @Test + public void givenMessageData_whenSignWithSignatureSigning_thenVerify() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] digitalSignature = DigitalSignatureUtils.sign(messageBytes, signingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verify(messageBytes, signingAlgorithm, publicKey, digitalSignature); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithMessageDigestAndCipher_thenVerify() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] encryptedMessageHash = DigitalSignatureUtils.signWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verifyWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, publicKey, encryptedMessageHash); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithSignatureSigning_thenVerifyWithMessageDigestAndCipher() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] digitalSignature = DigitalSignatureUtils.sign(messageBytes, signingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verifyWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, publicKey, digitalSignature); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithMessageDigestAndCipher_thenVerifyWithSignature() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] encryptedMessageHash = DigitalSignatureUtils.signWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verify(messageBytes, signingAlgorithm, publicKey, encryptedMessageHash); + + assertTrue(isCorrect); + } + +} diff --git a/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks b/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks new file mode 100644 index 0000000000..184b5b8600 Binary files /dev/null and b/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks differ diff --git a/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer b/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer new file mode 100644 index 0000000000..98e306bd49 --- /dev/null +++ b/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICxTCCAa2gAwIBAgIEala2gjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhC +YWVsZHVuZzAeFw0yMzAyMTkwNjA5NTdaFw0yNDAyMTkwNjA5NTdaMBMxETAPBgNV +BAMTCEJhZWxkdW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAifku +JnJM3U/x3jWpjpUZeSVpbdUTirdB2Ta0mwXXaZmGwtrwZvS8pXdmegFUMnYB92RJ +98j4iYjivXElwwjFIc4YRa7hQicqMfa1H3BUtDwIpqlXM1jISr5TYAE/t/wpkrVH +A1QPNv7Fb07ormWKwktTMWyUoLo0chInv07Ip3m6F3X3O0jZFjE8N+7Fnv9oMdsN +sAAq+f/7jJSdzo/vzHebR0XUxB1YP6sTWRH6nlNw2h+0kTMf33CkXyDG1Y1qsBRK +MoOia10bi21B7Yd+lJo0ZnT1JNei4eEdPYxWQa43JMY6PnpJI9d5WKvye2NewXvO +pLap8WR3dgX6n6bUtwIDAQABoyEwHzAdBgNVHQ4EFgQUQVqwZ6AlNlPeeUOmw89A +u86n09gwDQYJKoZIhvcNAQELBQADggEBAGoV1ECn0h0IYEoQ8pxF1zbXnt35XEO4 +ZPbq8cPuYj92X3c9TWeHJIHGO3ZYMS7eaBRL5HhCTqG3YjAsm6+bea9cBffeZwG3 +EAl0u7e8CI6Ri6065Og4s0c7Y3ZJIJ4i6c5bVqPep8Oj3IFUUAwxz+95c2LX9cfL +hxzH8N2RzWvGoJBrmWNeQUuKVlMBVBX6n/EcWmCS/VYORw0mwJ9vdmPhGU3hGggG +S0rAVnQlIdvzWsaNllNWf6ETrrHceCflKsOuettjODZUAqiZ9aEd9WMDGHLtZw94 +zONYICWg2o3Sx9/F26wHdjHn+gxB2Z45Dvd0rBMuCHqwJELxyvofc1E= +-----END CERTIFICATE----- diff --git a/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks b/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks new file mode 100644 index 0000000000..1ad4db895b Binary files /dev/null and b/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks differ diff --git a/libraries-server-2/pom.xml b/libraries-server-2/pom.xml index 7377fa3fa9..cf5d016d9f 100644 --- a/libraries-server-2/pom.xml +++ b/libraries-server-2/pom.xml @@ -73,6 +73,7 @@ 9.4.27.v20200227 8.1.11.v20170118 + 3.2.2 \ No newline at end of file diff --git a/libraries-testing/pom.xml b/libraries-testing/pom.xml index 15b454d5c6..9274c292ba 100644 --- a/libraries-testing/pom.xml +++ b/libraries-testing/pom.xml @@ -179,17 +179,16 @@ 1.9.9 1.9.0 1.9.0 - 1.9.27 + 3.6.12 1.5.0 3.0.0 0.8.1 4.3.8.RELEASE - 4.1.1 + 5.3.0 2.0.0.0 2.7.0 0.14.1 1.0.0 - 1.4.200 \ No newline at end of file diff --git a/libraries-testing/serenity.properties b/libraries-testing/serenity.properties index c77df9c0f7..9d8c664e2c 100644 --- a/libraries-testing/serenity.properties +++ b/libraries-testing/serenity.properties @@ -1,4 +1,7 @@ jira.url= jira.project= jira.username= -jira.password= \ No newline at end of file +jira.password= +# The path must point to the chromedriver location on your workstation +# The chromedriver must be compatible with your browser version +webdriver.chrome.driver=PATH\\chromedriver.exe \ No newline at end of file diff --git a/libraries-testing/src/test/java/com/baeldung/dbunit/ConnectionSettings.java b/libraries-testing/src/test/java/com/baeldung/dbunit/ConnectionSettings.java index cc29d9c58a..0ac5dff496 100644 --- a/libraries-testing/src/test/java/com/baeldung/dbunit/ConnectionSettings.java +++ b/libraries-testing/src/test/java/com/baeldung/dbunit/ConnectionSettings.java @@ -2,7 +2,7 @@ package com.baeldung.dbunit; public class ConnectionSettings { public static final String JDBC_DRIVER = org.h2.Driver.class.getName(); - public static final String JDBC_URL = "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;init=runscript from 'classpath:dbunit/schema.sql'"; + public static final String JDBC_URL = "jdbc:h2:mem:default;MODE=LEGACY;DB_CLOSE_DELAY=-1;init=runscript from 'classpath:dbunit/schema.sql'"; public static final String USER = "sa"; public static final String PASSWORD = ""; } diff --git a/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java index 57bb7c1242..16df26c6b6 100644 --- a/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java +++ b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java @@ -1,7 +1,9 @@ package com.baeldung.serenity; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.thucydides.core.annotations.Managed; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; +import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated; + import org.junit.Test; import org.junit.runner.RunWith; import org.openqa.selenium.By; @@ -9,13 +11,17 @@ import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.WebDriverWait; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; -import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.thucydides.core.annotations.Managed; @RunWith(SerenityRunner.class) public class GoogleSearchLiveTest { + /* The selectors must be appropriate for your own context. + you can inspect the desired element on the web page you are testing to get the appropriate selector */ + private static String SELECTOR_EUGEN_TEXT = ".haz7je"; + private static String SELECTOR_VALIDATE_COOKIES_DIALOG = "button[id='L2AGLb'] div[role='none']"; + @Managed(driver = "chrome") private WebDriver browser; @@ -23,11 +29,14 @@ public class GoogleSearchLiveTest { public void whenGoogleBaeldungThenShouldSeeEugen() { browser.get("https://www.google.com/ncr"); + // If your browser displays cookie settings dialog, uncomment the line below + // browser.findElement(By.cssSelector(SELECTOR_VALIDATE_COOKIES_DIALOG)).click(); + browser.findElement(By.name("q")).sendKeys("baeldung", Keys.ENTER); - new WebDriverWait(browser, 5).until(visibilityOfElementLocated(By.cssSelector("._ksh"))); + new WebDriverWait(browser, 5).until(visibilityOfElementLocated(By.cssSelector(SELECTOR_EUGEN_TEXT))); - assertThat(browser.findElement(By.cssSelector("._ksh")).getText(), containsString("Eugen (Baeldung)")); + assertThat(browser.findElement(By.cssSelector(SELECTOR_EUGEN_TEXT)).getText(), containsString("Eugen (Baeldung)")); } } diff --git a/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java index 47fcdd5403..0a20dcd13a 100644 --- a/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java +++ b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java @@ -19,6 +19,9 @@ public class GoogleSearchPageObjectLiveTest { public void whenGoogleBaeldungThenShouldSeeEugen() { googleSearch.open(); + // If your browser displays cookie settings dialog, uncomment the line below + // googleSearch.validateCookies(); + googleSearch.searchFor("baeldung"); googleSearch.resultMatches("Eugen (Baeldung)"); diff --git a/libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java b/libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java index d922ea8c85..11e7d08248 100644 --- a/libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java +++ b/libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java @@ -13,12 +13,18 @@ import static org.hamcrest.MatcherAssert.assertThat; @DefaultUrl("https://www.google.com/ncr") public class GoogleSearchPageObject extends PageObject { + /* The selectors "q", "._ksh" and "button[id='L2AGLb'] div[role='none']" must be appropriate for your own context. + you can inspect the desired element on the web page you are testing to get the appropriate selector */ + @FindBy(name = "q") private WebElement search; @FindBy(css = "._ksh") private WebElement result; + @FindBy(css = "button[id='L2AGLb'] div[role='none']") + private WebElement validateCookies; + public void searchFor(String keyword) { search.sendKeys(keyword, Keys.ENTER); } @@ -28,4 +34,7 @@ public class GoogleSearchPageObject extends PageObject { assertThat(result.getText(), containsString(expected)); } + public void validateCookies() { + validateCookies.click(); + } } diff --git a/lightrun/tasks-service/pom.xml b/lightrun/tasks-service/pom.xml index 2b3b37e51b..c3542b0089 100644 --- a/lightrun/tasks-service/pom.xml +++ b/lightrun/tasks-service/pom.xml @@ -24,6 +24,10 @@ org.springframework.boot spring-boot-starter-artemis + + org.springframework.boot + spring-boot-starter-cache + org.springframework.boot spring-boot-starter-data-jpa diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java new file mode 100644 index 0000000000..bf8bb6ad6e --- /dev/null +++ b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/SimpleCacheCustomizer.java @@ -0,0 +1,16 @@ +package com.baeldung.tasksservice; + +import java.util.List; + +import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.stereotype.Component; + +@Component +public class SimpleCacheCustomizer implements CacheManagerCustomizer { + + @Override + public void customize(ConcurrentMapCacheManager cacheManager) { + cacheManager.setCacheNames(List.of("tasks")); + } +} \ No newline at end of file diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java index dfd9859674..84a8ed7967 100644 --- a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java +++ b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/TasksServiceApplication.java @@ -2,8 +2,10 @@ package com.baeldung.tasksservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication +@EnableCaching public class TasksServiceApplication { public static void main(String[] args) { diff --git a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java index 3539dbbc3c..107bf56bb9 100644 --- a/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java +++ b/lightrun/tasks-service/src/main/java/com/baeldung/tasksservice/service/TasksService.java @@ -19,6 +19,7 @@ import java.util.UUID; import javax.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.baeldung.tasksservice.adapters.repository.TaskRecord; @@ -29,6 +30,7 @@ public class TasksService { @Autowired private TasksRepository tasksRepository; + @Cacheable("tasks") public TaskRecord getTaskById(String id) { return tasksRepository.findById(id) .orElseThrow(() -> new UnknownTaskException(id)); diff --git a/logging-modules/flogger/pom.xml b/logging-modules/flogger/pom.xml index c814d31767..05413a3952 100644 --- a/logging-modules/flogger/pom.xml +++ b/logging-modules/flogger/pom.xml @@ -61,7 +61,6 @@ 0.4 - 1.2.17 \ No newline at end of file diff --git a/logging-modules/log4j/pom.xml b/logging-modules/log4j/pom.xml index ac7c8620cd..fda2dd7157 100644 --- a/logging-modules/log4j/pom.xml +++ b/logging-modules/log4j/pom.xml @@ -45,7 +45,6 @@ - 1.2.17 2.17.1 2.17.1 3.3.6 diff --git a/logging-modules/log4j2/pom.xml b/logging-modules/log4j2/pom.xml index 02530055e1..c3a3f4e0f9 100644 --- a/logging-modules/log4j2/pom.xml +++ b/logging-modules/log4j2/pom.xml @@ -113,7 +113,6 @@ 2.1.1 2.17.1 yyyyMMddHHmmss - 1.4.200 \ No newline at end of file diff --git a/logging-modules/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java b/logging-modules/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java index 73b323f335..c084fc44b9 100644 --- a/logging-modules/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java +++ b/logging-modules/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java @@ -16,7 +16,7 @@ public class ConnectionFactory { private ConnectionFactory() { dataSource = new BasicDataSource(); dataSource.setDriver(new Driver()); - dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"); + dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;NON_KEYWORDS=WHEN"); } public static Connection getConnection() throws SQLException { diff --git a/logging-modules/logback/pom.xml b/logging-modules/logback/pom.xml index ab778e954e..bef4b25f1b 100644 --- a/logging-modules/logback/pom.xml +++ b/logging-modules/logback/pom.xml @@ -24,6 +24,11 @@ logback-classic ${logback.version} + + ch.qos.logback + logback-core + ${logback.version} + ch.qos.logback.contrib logback-json-classic @@ -34,6 +39,11 @@ logback-jackson ${logback.contrib.version} + + org.slf4j + slf4j-api + ${slf4j.version} + com.fasterxml.jackson.core jackson-databind @@ -55,14 +65,14 @@ - javax.mail - mail - ${javax.mail.version} + org.eclipse.angus + angus-mail + ${angus.mail.version} - javax.activation - activation - ${javax.activation.version} + org.eclipse.angus + angus-activation + ${angus.activation.version} runtime @@ -106,8 +116,10 @@ 20180130 0.1.5 3.3.5 - 1.4.7 - 1.1.1 + 2.0.1 + 2.0.0 + 1.3.5 + 2.0.4 \ No newline at end of file diff --git a/logging-modules/pom.xml b/logging-modules/pom.xml index c7a770891d..5a1bd32288 100644 --- a/logging-modules/pom.xml +++ b/logging-modules/pom.xml @@ -19,6 +19,7 @@ log4j2 logback log-mdc + tinylog2 \ No newline at end of file diff --git a/logging-modules/tinylog2/README.md b/logging-modules/tinylog2/README.md new file mode 100644 index 0000000000..880ff8e65f --- /dev/null +++ b/logging-modules/tinylog2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Lightweight Logging With tinylog 2](https://www.baeldung.com/java-logging-tinylog-guide) diff --git a/logging-modules/tinylog2/pom.xml b/logging-modules/tinylog2/pom.xml new file mode 100644 index 0000000000..df9dcca7ab --- /dev/null +++ b/logging-modules/tinylog2/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + tinylog2 + 0.1-SNAPSHOT + tinylog2 + + + com.baeldung + logging-modules + 1.0.0-SNAPSHOT + + + + + org.tinylog + tinylog-api + ${tinylog.version} + + + org.tinylog + tinylog-impl + ${tinylog.version} + + + + + 2.5.0 + + + \ No newline at end of file diff --git a/logging-modules/tinylog2/src/main/java/com/baeldung/tinylog/TinylogExamples.java b/logging-modules/tinylog2/src/main/java/com/baeldung/tinylog/TinylogExamples.java new file mode 100644 index 0000000000..3e0e8d79d4 --- /dev/null +++ b/logging-modules/tinylog2/src/main/java/com/baeldung/tinylog/TinylogExamples.java @@ -0,0 +1,43 @@ +package com.baeldung.tinylog; + +import org.tinylog.Logger; + +public class TinylogExamples { + + public static void main(String[] args) { + /* Static text */ + + Logger.info("Hello World!"); + + /* Placeholders */ + + Logger.info("Hello {}!", "Alice"); + Logger.info("π = {0.00}", Math.PI); + + /* Lazy Logging */ + + Logger.debug("Expensive computation: {}", () -> compute()); // Visible in log files but not on the console + + /* Exceptions */ + + int a = 42; + int b = 0; + + try { + int i = a / b; + } catch (Exception ex) { + Logger.error(ex, "Cannot divide {} by {}", a, b); + } + + try { + int i = a / b; + } catch (Exception ex) { + Logger.error(ex); + } + } + + private static int compute() { + return 42; // In real applications, we would perform an expensive computation here + } + +} diff --git a/logging-modules/tinylog2/src/main/resources/tinylog.properties b/logging-modules/tinylog2/src/main/resources/tinylog.properties new file mode 100644 index 0000000000..303aac129a --- /dev/null +++ b/logging-modules/tinylog2/src/main/resources/tinylog.properties @@ -0,0 +1,13 @@ +writer1 = console +writer1.level = info +writer1.format = {date: HH:mm:ss.SSS} [{level}] {class}: {message} + +writer2 = rolling file +writer2.file = logs/myapp_{date: yyyy-MM-dd}_{count}.log +writer2.buffered = true +writer2.policies = startup, daily: 06:00 +writer2.format = {class} [{thread}] {level}: {message} +writer2.convert = gzip +writer2.backups = 100 + +writingthread = true diff --git a/logging-modules/tinylog2/src/test/java/com/baeldung/tinylog/TinylogIntegrationTest.java b/logging-modules/tinylog2/src/test/java/com/baeldung/tinylog/TinylogIntegrationTest.java new file mode 100644 index 0000000000..74637366e8 --- /dev/null +++ b/logging-modules/tinylog2/src/test/java/com/baeldung/tinylog/TinylogIntegrationTest.java @@ -0,0 +1,72 @@ +package com.baeldung.tinylog; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.tinylog.Logger; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TinylogIntegrationTest { + + private ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream(); + + @BeforeEach + public void init() throws UnsupportedEncodingException { + System.setOut(new PrintStream(consoleOutput, false, "UTF-8")); + } + + @Test + public void whenLoggingStaticText_thenOutputIt() throws UnsupportedEncodingException { + Logger.info("Hello World!"); + + String outputLog = consoleOutput.toString("UTF-8"); + assertThat(outputLog).isEqualToIgnoringNewLines("Hello World!"); + } + + @Test + public void whenLoggingParamizedText_thenOutputItResolved() throws UnsupportedEncodingException { + Logger.info("Hello {}!", "Alice"); + + String outputLog = consoleOutput.toString("UTF-8"); + assertThat(outputLog).isEqualToIgnoringNewLines("Hello Alice!"); + } + + @Test + public void whenLoggingNumberWithFormatPattern_thenOutputItFormatted() throws UnsupportedEncodingException { + Logger.info("π = {0.00}", Math.PI); + + String outputLog = consoleOutput.toString("UTF-8"); + assertThat(outputLog).isEqualToIgnoringNewLines("π = 3.14"); + } + + @Test + public void whenLoggingExceptionWithMessage_thenOutputMessageAndException() throws UnsupportedEncodingException { + int a = 42; + int b = 0; + try { + int i = a / b; + } catch (Exception ex) { + Logger.error(ex, "Cannot divide {} by {}", a, b); + } + + String outputLog = consoleOutput.toString("UTF-8"); + assertThat(outputLog).startsWith("Cannot divide 42 by 0: java.lang.ArithmeticException"); + } + + @Test + public void whenLoggingExceptionWithoutMessage_thenOutputExceptionOnly() throws UnsupportedEncodingException { + try { + int i = 42 / 0; + } catch (Exception ex) { + Logger.error(ex); + } + + String outputLog = consoleOutput.toString("UTF-8"); + assertThat(outputLog).startsWith("java.lang.ArithmeticException"); + } + +} diff --git a/logging-modules/tinylog2/src/test/resources/tinylog.properties b/logging-modules/tinylog2/src/test/resources/tinylog.properties new file mode 100644 index 0000000000..4534555b06 --- /dev/null +++ b/logging-modules/tinylog2/src/test/resources/tinylog.properties @@ -0,0 +1,4 @@ +writer = console +writer.level = info +writer.stream = out +writer.format = {message} diff --git a/lombok-modules/lombok-2/README.md b/lombok-modules/lombok-2/README.md index 632d676567..d3b1287346 100644 --- a/lombok-modules/lombok-2/README.md +++ b/lombok-modules/lombok-2/README.md @@ -8,4 +8,5 @@ This module contains articles about Project Lombok. - [Declaring Val and Var Variables in Lombok](https://www.baeldung.com/java-lombok-val-var) - [Lombok Using @With Annotations](https://www.baeldung.com/lombok-with-annotations) - [Lombok’s @ToString Annotation](https://www.baeldung.com/lombok-tostring) +- [Jackson’s Deserialization With Lombok](https://www.baeldung.com/java-jackson-deserialization-lombok) - More articles: [[<-- prev]](../lombok) diff --git a/lombok-modules/lombok-2/pom.xml b/lombok-modules/lombok-2/pom.xml index 23c907b4a1..0a7ad27ad6 100644 --- a/lombok-modules/lombok-2/pom.xml +++ b/lombok-modules/lombok-2/pom.xml @@ -27,8 +27,4 @@ - - 2.14.1 - - \ No newline at end of file diff --git a/mapstruct/pom.xml b/mapstruct/pom.xml index 4696a46abb..62c9ca5870 100644 --- a/mapstruct/pom.xml +++ b/mapstruct/pom.xml @@ -49,10 +49,7 @@ org.apache.maven.plugins maven-compiler-plugin - ${maven-compiler-plugin.version} - ${maven.compiler.source} - ${maven.compiler.target} org.mapstruct @@ -76,10 +73,8 @@ - 1.4.2.Final + 1.5.3.Final 4.3.4.RELEASE - 1.8 - 1.8 0.2.0 diff --git a/maven-modules/maven-repositories/maven-download-artifacts/pom.xml b/maven-modules/maven-repositories/maven-download-artifacts/pom.xml index 15173f8d60..53db99e59a 100644 --- a/maven-modules/maven-repositories/maven-download-artifacts/pom.xml +++ b/maven-modules/maven-repositories/maven-download-artifacts/pom.xml @@ -13,6 +13,19 @@ 1.0.0-SNAPSHOT + + + com.baeldung + maven-release-repository + 1.0.0 + + + com.baeldung + maven-snapshot-repository + 1.0.0-SNAPSHOT + + + nexus-snapshot @@ -35,18 +48,4 @@ - - - com.baeldung - maven-release-repository - 1.0.0 - - - - com.baeldung - maven-snapshot-repository - 1.0.0-SNAPSHOT - - - \ No newline at end of file diff --git a/maven-modules/multimodulemavenproject/daomodule/pom.xml b/maven-modules/multimodulemavenproject/maven-daomodule/pom.xml similarity index 95% rename from maven-modules/multimodulemavenproject/daomodule/pom.xml rename to maven-modules/multimodulemavenproject/maven-daomodule/pom.xml index 626a6f707a..474cc20adb 100644 --- a/maven-modules/multimodulemavenproject/daomodule/pom.xml +++ b/maven-modules/multimodulemavenproject/maven-daomodule/pom.xml @@ -4,7 +4,7 @@ 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.daomodule - daomodule + maven-daomodule 1.0 jar diff --git a/maven-modules/multimodulemavenproject/daomodule/src/main/java/com/baeldung/daomodule/Dao.java b/maven-modules/multimodulemavenproject/maven-daomodule/src/main/java/com/baeldung/daomodule/Dao.java similarity index 100% rename from maven-modules/multimodulemavenproject/daomodule/src/main/java/com/baeldung/daomodule/Dao.java rename to maven-modules/multimodulemavenproject/maven-daomodule/src/main/java/com/baeldung/daomodule/Dao.java diff --git a/maven-modules/multimodulemavenproject/daomodule/src/main/java/module-info.java b/maven-modules/multimodulemavenproject/maven-daomodule/src/main/java/module-info.java similarity index 100% rename from maven-modules/multimodulemavenproject/daomodule/src/main/java/module-info.java rename to maven-modules/multimodulemavenproject/maven-daomodule/src/main/java/module-info.java diff --git a/maven-modules/multimodulemavenproject/entitymodule/pom.xml b/maven-modules/multimodulemavenproject/maven-entitymodule/pom.xml similarity index 95% rename from maven-modules/multimodulemavenproject/entitymodule/pom.xml rename to maven-modules/multimodulemavenproject/maven-entitymodule/pom.xml index e2a453b9c2..a9b169a8b9 100644 --- a/maven-modules/multimodulemavenproject/entitymodule/pom.xml +++ b/maven-modules/multimodulemavenproject/maven-entitymodule/pom.xml @@ -4,7 +4,7 @@ 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.entitymodule - entitymodule + maven-entitymodule 1.0 jar diff --git a/maven-modules/multimodulemavenproject/entitymodule/src/main/java/com/baeldung/entitymodule/User.java b/maven-modules/multimodulemavenproject/maven-entitymodule/src/main/java/com/baeldung/entitymodule/User.java similarity index 100% rename from maven-modules/multimodulemavenproject/entitymodule/src/main/java/com/baeldung/entitymodule/User.java rename to maven-modules/multimodulemavenproject/maven-entitymodule/src/main/java/com/baeldung/entitymodule/User.java diff --git a/maven-modules/multimodulemavenproject/entitymodule/src/main/java/module-info.java b/maven-modules/multimodulemavenproject/maven-entitymodule/src/main/java/module-info.java similarity index 100% rename from maven-modules/multimodulemavenproject/entitymodule/src/main/java/module-info.java rename to maven-modules/multimodulemavenproject/maven-entitymodule/src/main/java/module-info.java diff --git a/maven-modules/multimodulemavenproject/mainappmodule/pom.xml b/maven-modules/multimodulemavenproject/maven-mainappmodule/pom.xml similarity index 88% rename from maven-modules/multimodulemavenproject/mainappmodule/pom.xml rename to maven-modules/multimodulemavenproject/maven-mainappmodule/pom.xml index c376a2b04e..0dd11ef991 100644 --- a/maven-modules/multimodulemavenproject/mainappmodule/pom.xml +++ b/maven-modules/multimodulemavenproject/maven-mainappmodule/pom.xml @@ -4,7 +4,7 @@ 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.mainappmodule - mainappmodule + maven-mainappmodule 1.0 jar @@ -17,17 +17,17 @@ com.baeldung.entitymodule - entitymodule + maven-entitymodule ${entitymodule.version} com.baeldung.daomodule - daomodule + maven-daomodule ${daomodule.version} com.baeldung.userdaomodule - userdaomodule + maven-userdaomodule ${userdaomodule.version} diff --git a/maven-modules/multimodulemavenproject/mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java b/maven-modules/multimodulemavenproject/maven-mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java similarity index 100% rename from maven-modules/multimodulemavenproject/mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java rename to maven-modules/multimodulemavenproject/maven-mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java diff --git a/maven-modules/multimodulemavenproject/mainappmodule/src/main/java/module-info.java b/maven-modules/multimodulemavenproject/maven-mainappmodule/src/main/java/module-info.java similarity index 100% rename from maven-modules/multimodulemavenproject/mainappmodule/src/main/java/module-info.java rename to maven-modules/multimodulemavenproject/maven-mainappmodule/src/main/java/module-info.java diff --git a/maven-modules/multimodulemavenproject/userdaomodule/pom.xml b/maven-modules/multimodulemavenproject/maven-userdaomodule/pom.xml similarity index 96% rename from maven-modules/multimodulemavenproject/userdaomodule/pom.xml rename to maven-modules/multimodulemavenproject/maven-userdaomodule/pom.xml index 4df29457c5..c7ceada17d 100644 --- a/maven-modules/multimodulemavenproject/userdaomodule/pom.xml +++ b/maven-modules/multimodulemavenproject/maven-userdaomodule/pom.xml @@ -4,7 +4,7 @@ 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.userdaomodule - userdaomodule + maven-userdaomodule 1.0 jar diff --git a/maven-modules/multimodulemavenproject/userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java b/maven-modules/multimodulemavenproject/maven-userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java similarity index 100% rename from maven-modules/multimodulemavenproject/userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java rename to maven-modules/multimodulemavenproject/maven-userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java diff --git a/maven-modules/multimodulemavenproject/userdaomodule/src/main/java/module-info.java b/maven-modules/multimodulemavenproject/maven-userdaomodule/src/main/java/module-info.java similarity index 100% rename from maven-modules/multimodulemavenproject/userdaomodule/src/main/java/module-info.java rename to maven-modules/multimodulemavenproject/maven-userdaomodule/src/main/java/module-info.java diff --git a/maven-modules/multimodulemavenproject/pom.xml b/maven-modules/multimodulemavenproject/pom.xml index fbafa7ebff..db0bda3e6e 100644 --- a/maven-modules/multimodulemavenproject/pom.xml +++ b/maven-modules/multimodulemavenproject/pom.xml @@ -17,10 +17,10 @@ - entitymodule - daomodule - userdaomodule - mainappmodule + maven-entitymodule + maven-daomodule + maven-userdaomodule + maven-mainappmodule diff --git a/maven-modules/version-collision/pom.xml b/maven-modules/version-collision/pom.xml index 9c1b9641c8..820689abfa 100644 --- a/maven-modules/version-collision/pom.xml +++ b/maven-modules/version-collision/pom.xml @@ -13,8 +13,8 @@ - project-a - project-b + version-collision-project-a + version-collision-project-b project-collision diff --git a/maven-modules/version-collision/project-collision/pom.xml b/maven-modules/version-collision/project-collision/pom.xml index 74f117cdbb..1ef4440719 100644 --- a/maven-modules/version-collision/project-collision/pom.xml +++ b/maven-modules/version-collision/project-collision/pom.xml @@ -14,7 +14,7 @@ com.baeldung - project-a + version-collision-project-a 0.0.1-SNAPSHOT @@ -26,7 +26,7 @@ com.baeldung - project-b + version-collision-project-b 0.0.1-SNAPSHOT diff --git a/maven-modules/version-collision/project-a/pom.xml b/maven-modules/version-collision/version-collision-project-a/pom.xml similarity index 90% rename from maven-modules/version-collision/project-a/pom.xml rename to maven-modules/version-collision/version-collision-project-a/pom.xml index ca06c7daca..6130334b2c 100644 --- a/maven-modules/version-collision/project-a/pom.xml +++ b/maven-modules/version-collision/version-collision-project-a/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 - project-a + version-collision-project-a version-collision diff --git a/maven-modules/version-collision/project-b/pom.xml b/maven-modules/version-collision/version-collision-project-b/pom.xml similarity index 90% rename from maven-modules/version-collision/project-b/pom.xml rename to maven-modules/version-collision/version-collision-project-b/pom.xml index a7185ab22d..e2e7294cd2 100644 --- a/maven-modules/version-collision/project-b/pom.xml +++ b/maven-modules/version-collision/version-collision-project-b/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 - project-b + version-collision-project-b version-collision diff --git a/maven-modules/version-overriding-plugins/pom.xml b/maven-modules/version-overriding-plugins/pom.xml index 79109a83e1..b98a444bd4 100644 --- a/maven-modules/version-overriding-plugins/pom.xml +++ b/maven-modules/version-overriding-plugins/pom.xml @@ -13,8 +13,8 @@ - child-a - child-b + version-overriding-child-a + version-overriding-child-b diff --git a/maven-modules/version-overriding-plugins/child-a/pom.xml b/maven-modules/version-overriding-plugins/version-overriding-child-a/pom.xml similarity index 95% rename from maven-modules/version-overriding-plugins/child-a/pom.xml rename to maven-modules/version-overriding-plugins/version-overriding-child-a/pom.xml index 45098ccef0..48b5782f72 100644 --- a/maven-modules/version-overriding-plugins/child-a/pom.xml +++ b/maven-modules/version-overriding-plugins/version-overriding-child-a/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 - child-a + version-overriding-child-a pom diff --git a/maven-modules/version-overriding-plugins/child-b/pom.xml b/maven-modules/version-overriding-plugins/version-overriding-child-b/pom.xml similarity index 87% rename from maven-modules/version-overriding-plugins/child-b/pom.xml rename to maven-modules/version-overriding-plugins/version-overriding-child-b/pom.xml index f86a3c2096..8e52b34dbc 100644 --- a/maven-modules/version-overriding-plugins/child-b/pom.xml +++ b/maven-modules/version-overriding-plugins/version-overriding-child-b/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 - child-b + version-overriding-child-b version-overriding-plugins diff --git a/jgroups/README.md b/messaging-modules/jgroups/README.md similarity index 100% rename from jgroups/README.md rename to messaging-modules/jgroups/README.md diff --git a/jgroups/pom.xml b/messaging-modules/jgroups/pom.xml similarity index 88% rename from jgroups/pom.xml rename to messaging-modules/jgroups/pom.xml index 370d8a349a..12939c86b1 100644 --- a/jgroups/pom.xml +++ b/messaging-modules/jgroups/pom.xml @@ -4,15 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 jgroups - 0.1-SNAPSHOT jgroups jar Reliable Messaging with JGroups Tutorial com.baeldung - parent-modules - 1.0.0-SNAPSHOT + messaging-modules + 0.0.1-SNAPSHOT diff --git a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java b/messaging-modules/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java similarity index 100% rename from jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java rename to messaging-modules/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java diff --git a/jgroups/src/main/resources/logback.xml b/messaging-modules/jgroups/src/main/resources/logback.xml similarity index 100% rename from jgroups/src/main/resources/logback.xml rename to messaging-modules/jgroups/src/main/resources/logback.xml diff --git a/jgroups/src/main/resources/udp.xml b/messaging-modules/jgroups/src/main/resources/udp.xml similarity index 100% rename from jgroups/src/main/resources/udp.xml rename to messaging-modules/jgroups/src/main/resources/udp.xml diff --git a/messaging-modules/pom.xml b/messaging-modules/pom.xml new file mode 100644 index 0000000000..8bda46f5cd --- /dev/null +++ b/messaging-modules/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + messaging-modules + messaging-modules + pom + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + jgroups + rabbitmq + spring-amqp + spring-jms + + + \ No newline at end of file diff --git a/rabbitmq/README.md b/messaging-modules/rabbitmq/README.md similarity index 83% rename from rabbitmq/README.md rename to messaging-modules/rabbitmq/README.md index d91d268b2b..93bb795d7b 100644 --- a/rabbitmq/README.md +++ b/messaging-modules/rabbitmq/README.md @@ -7,4 +7,5 @@ This module contains articles about RabbitMQ. - [Exchanges, Queues, and Bindings in RabbitMQ](https://www.baeldung.com/java-rabbitmq-exchanges-queues-bindings) - [Pub-Sub vs. Message Queues](https://www.baeldung.com/pub-sub-vs-message-queues) - [Channels and Connections in RabbitMQ](https://www.baeldung.com/java-rabbitmq-channels-connections) +- [Create Dynamic Queues in RabbitMQ](https://www.baeldung.com/rabbitmq-dynamic-queues) diff --git a/rabbitmq/docker-compose.yaml b/messaging-modules/rabbitmq/docker-compose.yaml similarity index 100% rename from rabbitmq/docker-compose.yaml rename to messaging-modules/rabbitmq/docker-compose.yaml diff --git a/rabbitmq/pom.xml b/messaging-modules/rabbitmq/pom.xml similarity index 93% rename from rabbitmq/pom.xml rename to messaging-modules/rabbitmq/pom.xml index c7a299b74f..69476ba31b 100644 --- a/rabbitmq/pom.xml +++ b/messaging-modules/rabbitmq/pom.xml @@ -9,9 +9,8 @@ com.baeldung - parent-boot-2 + messaging-modules 0.0.1-SNAPSHOT - ../parent-boot-2 diff --git a/rabbitmq/src/main/java/com/baeldung/benchmark/ConnectionPerChannelPublisher.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/ConnectionPerChannelPublisher.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/benchmark/ConnectionPerChannelPublisher.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/ConnectionPerChannelPublisher.java diff --git a/rabbitmq/src/main/java/com/baeldung/benchmark/SharedConnectionPublisher.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SharedConnectionPublisher.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/benchmark/SharedConnectionPublisher.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SharedConnectionPublisher.java diff --git a/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisher.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisher.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisher.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisher.java diff --git a/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisherNio.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisherNio.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisherNio.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/SingleConnectionPublisherNio.java diff --git a/rabbitmq/src/main/java/com/baeldung/benchmark/Worker.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/Worker.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/benchmark/Worker.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/benchmark/Worker.java diff --git a/rabbitmq/src/main/java/com/baeldung/consumer/Receiver.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/consumer/Receiver.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/consumer/Receiver.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/consumer/Receiver.java diff --git a/rabbitmq/src/main/java/com/baeldung/producer/Publisher.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/producer/Publisher.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/producer/Publisher.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/producer/Publisher.java diff --git a/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/ClientApplication.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/ClientApplication.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/pubsubmq/client/ClientApplication.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/ClientApplication.java diff --git a/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/Consumer.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/Consumer.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/pubsubmq/client/Consumer.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/client/Consumer.java diff --git a/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/Publisher.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/Publisher.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/pubsubmq/server/Publisher.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/Publisher.java diff --git a/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/ServerApplication.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/ServerApplication.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/pubsubmq/server/ServerApplication.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/pubsubmq/server/ServerApplication.java diff --git a/messaging-modules/rabbitmq/src/main/java/com/baeldung/queue/dynamic/DynamicQueueCreation.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/queue/dynamic/DynamicQueueCreation.java new file mode 100644 index 0000000000..f62660bf81 --- /dev/null +++ b/messaging-modules/rabbitmq/src/main/java/com/baeldung/queue/dynamic/DynamicQueueCreation.java @@ -0,0 +1,34 @@ +package com.baeldung.queue.dynamic; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class DynamicQueueCreation { + + private static final Logger log = LoggerFactory.getLogger(DynamicQueueCreation.class); + + private static final String QUEUE_NAME = "baeldung-queue"; + + public static void main(String[] args) throws IOException, TimeoutException { + + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + + try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { + AMQP.Queue.DeclareOk declareOk = channel.queueDeclare(QUEUE_NAME, true, false, false, null); + log.info(declareOk.getQueue()); + + AMQP.Queue.DeclareOk declareOkExists = channel.queueDeclarePassive(QUEUE_NAME); + log.info(declareOkExists.getQueue()); + } + } + +} diff --git a/rabbitmq/src/main/java/com/baeldung/setup/Setup.java b/messaging-modules/rabbitmq/src/main/java/com/baeldung/setup/Setup.java similarity index 100% rename from rabbitmq/src/main/java/com/baeldung/setup/Setup.java rename to messaging-modules/rabbitmq/src/main/java/com/baeldung/setup/Setup.java diff --git a/netty/src/main/resources/logback.xml b/messaging-modules/rabbitmq/src/main/resources/logback.xml similarity index 100% rename from netty/src/main/resources/logback.xml rename to messaging-modules/rabbitmq/src/main/resources/logback.xml diff --git a/rabbitmq/src/rabbitmq/20-mem.conf b/messaging-modules/rabbitmq/src/rabbitmq/20-mem.conf similarity index 100% rename from rabbitmq/src/rabbitmq/20-mem.conf rename to messaging-modules/rabbitmq/src/rabbitmq/20-mem.conf diff --git a/rabbitmq/src/test/java/com/baeldung/benchmark/ConnectionPerChannelPublisherLiveTest.java b/messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/ConnectionPerChannelPublisherLiveTest.java similarity index 100% rename from rabbitmq/src/test/java/com/baeldung/benchmark/ConnectionPerChannelPublisherLiveTest.java rename to messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/ConnectionPerChannelPublisherLiveTest.java diff --git a/rabbitmq/src/test/java/com/baeldung/benchmark/SingleConnectionPublisherLiveTest.java b/messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/SingleConnectionPublisherLiveTest.java similarity index 100% rename from rabbitmq/src/test/java/com/baeldung/benchmark/SingleConnectionPublisherLiveTest.java rename to messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/SingleConnectionPublisherLiveTest.java diff --git a/messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/queue/dynamic/DynamicQueueCreationLiveTest.java b/messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/queue/dynamic/DynamicQueueCreationLiveTest.java new file mode 100644 index 0000000000..aa430035ef --- /dev/null +++ b/messaging-modules/rabbitmq/src/test/java/com/baeldung/benchmark/queue/dynamic/DynamicQueueCreationLiveTest.java @@ -0,0 +1,71 @@ +package com.baeldung.benchmark.queue.dynamic; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class DynamicQueueCreationLiveTest { + + private static final String QUEUE_NAME = "baeldung-queue"; + private static final String QUEUE_NAME_NEW = "baeldung-queue-new"; + + private static Connection connection; + + @BeforeAll + public static void setUpConnection() throws IOException, TimeoutException { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + connection = factory.newConnection(); + } + + @Test + void givenQueueName_whenCreatingQueue_thenCheckingIfQueueCreated() throws IOException, TimeoutException { + + try (Channel channel = connection.createChannel()) { + AMQP.Queue.DeclareOk declareOk = channel.queueDeclare(QUEUE_NAME, true, false, false, null); + + assertNotNull(declareOk); + assertEquals(QUEUE_NAME, declareOk.getQueue()); + } + } + + @Test + void givenQueueName_whenCreatingQueue_thenCheckingIfQueueExists() throws IOException, TimeoutException { + + try (Channel channel = connection.createChannel()) { + channel.queueDeclare(QUEUE_NAME, true, false, false, null); + + AMQP.Queue.DeclareOk declareOk = channel.queueDeclarePassive(QUEUE_NAME); + + assertNotNull(declareOk); + assertEquals(QUEUE_NAME, declareOk.getQueue()); + } + } + + @Test + void givenQueueName_whenQueueDoesNotExist_thenCheckingIfQueueExists() throws IOException, TimeoutException { + + try (Channel channel = connection.createChannel()) { + assertThrows(IOException.class, () -> { + channel.queueDeclarePassive(QUEUE_NAME_NEW); + }); + } + } + + @AfterAll + public static void destroyConnection() throws IOException { + connection.close(); + } +} diff --git a/spring-amqp/README.md b/messaging-modules/spring-amqp/README.md similarity index 100% rename from spring-amqp/README.md rename to messaging-modules/spring-amqp/README.md diff --git a/spring-amqp/pom.xml b/messaging-modules/spring-amqp/pom.xml similarity index 88% rename from spring-amqp/pom.xml rename to messaging-modules/spring-amqp/pom.xml index 1a0b78c26e..7b2f7d518c 100755 --- a/spring-amqp/pom.xml +++ b/messaging-modules/spring-amqp/pom.xml @@ -10,9 +10,8 @@ com.baeldung - parent-boot-2 + messaging-modules 0.0.1-SNAPSHOT - ../parent-boot-2 diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastConfig.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastConfig.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastConfig.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastConfig.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastMessageApp.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastMessageApp.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastMessageApp.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/broadcast/BroadcastMessageApp.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/ErrorHandlingApp.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/ErrorHandlingApp.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/ErrorHandlingApp.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/ErrorHandlingApp.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXCustomAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXCustomAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXCustomAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXCustomAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXParkingLotAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXParkingLotAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXParkingLotAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/DLXParkingLotAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/FatalExceptionStrategyAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/FatalExceptionStrategyAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/FatalExceptionStrategyAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/FatalExceptionStrategyAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/ListenerErrorHandlerAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/ListenerErrorHandlerAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/ListenerErrorHandlerAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/ListenerErrorHandlerAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/RoutingKeyDLQAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/RoutingKeyDLQAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/RoutingKeyDLQAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/RoutingKeyDLQAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/SimpleDLQAmqpConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/SimpleDLQAmqpConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/SimpleDLQAmqpConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/configuration/SimpleDLQAmqpConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/DLQCustomAmqpContainer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/DLQCustomAmqpContainer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/DLQCustomAmqpContainer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/DLQCustomAmqpContainer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/MessagesConsumer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/MessagesConsumer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/MessagesConsumer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/MessagesConsumer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/ParkingLotDLQAmqpContainer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/ParkingLotDLQAmqpContainer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/ParkingLotDLQAmqpContainer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/ParkingLotDLQAmqpContainer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/RoutingDLQAmqpContainer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/RoutingDLQAmqpContainer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/RoutingDLQAmqpContainer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/RoutingDLQAmqpContainer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/SimpleDLQAmqpContainer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/SimpleDLQAmqpContainer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/SimpleDLQAmqpContainer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/consumer/SimpleDLQAmqpContainer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/BusinessException.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/BusinessException.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/BusinessException.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/BusinessException.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomErrorHandler.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomErrorHandler.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomErrorHandler.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomErrorHandler.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomFatalExceptionStrategy.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomFatalExceptionStrategy.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomFatalExceptionStrategy.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/errorhandler/CustomFatalExceptionStrategy.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/producer/MessageProducer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/producer/MessageProducer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/producer/MessageProducer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/errorhandling/producer/MessageProducer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffApp.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffApp.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffApp.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffApp.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ObservableRejectAndDontRequeueRecoverer.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ObservableRejectAndDontRequeueRecoverer.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ObservableRejectAndDontRequeueRecoverer.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/ObservableRejectAndDontRequeueRecoverer.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RabbitConfiguration.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RabbitConfiguration.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RabbitConfiguration.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RabbitConfiguration.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueues.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueues.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueues.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueues.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueuesInterceptor.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueuesInterceptor.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueuesInterceptor.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/exponentialbackoff/RetryQueuesInterceptor.java diff --git a/spring-amqp/src/main/java/com/baeldung/springamqp/simple/HelloWorldMessageApp.java b/messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/simple/HelloWorldMessageApp.java similarity index 100% rename from spring-amqp/src/main/java/com/baeldung/springamqp/simple/HelloWorldMessageApp.java rename to messaging-modules/spring-amqp/src/main/java/com/baeldung/springamqp/simple/HelloWorldMessageApp.java diff --git a/spring-amqp/src/main/resources/application.properties b/messaging-modules/spring-amqp/src/main/resources/application.properties similarity index 100% rename from spring-amqp/src/main/resources/application.properties rename to messaging-modules/spring-amqp/src/main/resources/application.properties diff --git a/spring-amqp/src/test/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffLiveTest.java b/messaging-modules/spring-amqp/src/test/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffLiveTest.java similarity index 100% rename from spring-amqp/src/test/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffLiveTest.java rename to messaging-modules/spring-amqp/src/test/java/com/baeldung/springamqp/exponentialbackoff/ExponentialBackoffLiveTest.java diff --git a/spring-amqp/src/test/resources/logback-test.xml b/messaging-modules/spring-amqp/src/test/resources/logback-test.xml similarity index 100% rename from spring-amqp/src/test/resources/logback-test.xml rename to messaging-modules/spring-amqp/src/test/resources/logback-test.xml diff --git a/messaging-modules/spring-apache-camel/.gitignore b/messaging-modules/spring-apache-camel/.gitignore new file mode 100644 index 0000000000..f137d908d6 --- /dev/null +++ b/messaging-modules/spring-apache-camel/.gitignore @@ -0,0 +1,2 @@ +/src/test/destination-folder/* +/output/ \ No newline at end of file diff --git a/spring-apache-camel/README.md b/messaging-modules/spring-apache-camel/README.md similarity index 62% rename from spring-apache-camel/README.md rename to messaging-modules/spring-apache-camel/README.md index 6a16e1da05..535c61cbef 100644 --- a/spring-apache-camel/README.md +++ b/messaging-modules/spring-apache-camel/README.md @@ -4,17 +4,19 @@ This module contains articles about Spring with Apache Camel ### Relevant Articles -- [Apache Camel](http://camel.apache.org/) -- [Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/toc.html) - [Introduction To Apache Camel](http://www.baeldung.com/apache-camel-intro) - [Integration Patterns With Apache Camel](http://www.baeldung.com/camel-integration-patterns) - [Using Apache Camel with Spring](http://www.baeldung.com/spring-apache-camel-tutorial) - [Unmarshalling a JSON Array Using camel-jackson](https://www.baeldung.com/java-camel-jackson-json-array) +- [Apache Camel with Spring Boot](https://www.baeldung.com/apache-camel-spring-boot) +- [Apache Camel Routes Testing in Spring Boot](https://www.baeldung.com/spring-boot-apache-camel-routes-testing) +- [Apache Camel Conditional Routing](https://www.baeldung.com/spring-apache-camel-conditional-routing) +- [Apache Camel Exception Handling](https://www.baeldung.com/java-apache-camel-exception-handling) ### Framework Versions: -- Spring 4.2.4 -- Apache Camel 2.16.1 +- Spring 5.3.25 +- Apache Camel 3.14.7 ### Build and Run Application diff --git a/messaging-modules/spring-apache-camel/pom.xml b/messaging-modules/spring-apache-camel/pom.xml new file mode 100644 index 0000000000..ec7557666c --- /dev/null +++ b/messaging-modules/spring-apache-camel/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + org.baeldung.apache.camel + spring-apache-camel + spring-apache-camel + jar + http://maven.apache.org + + + com.baeldung + messaging-modules + 0.0.1-SNAPSHOT + + + + + org.apache.camel + camel-core + ${env.camel.version} + + + org.apache.camel + camel-spring + ${env.camel.version} + + + commons-logging + commons-logging + + + + + org.apache.camel + camel-stream + ${env.camel.version} + + + org.springframework + spring-context + ${env.spring.version} + + + org.apache.camel + camel-spring-javaconfig + ${env.camel.version} + + + org.apache.camel + camel-jackson + ${env.camel.version} + + + org.apache.camel + camel-test + ${env.camel.version} + test + + + org.apache.camel.springboot + camel-servlet-starter + ${camel.version} + + + org.apache.camel.springboot + camel-jackson-starter + ${camel.version} + + + org.apache.camel.springboot + camel-swagger-java-starter + ${camel.version} + + + org.apache.camel.springboot + camel-spring-boot-starter + ${camel.version} + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.camel + camel-test-spring-junit5 + ${camel.version} + test + + + + + 3.14.7 + 5.3.25 + 3.15.0 + + + + + spring-boot + + spring-boot:run + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + com.baeldung.camel.boot.boot.testing.GreetingsFileSpringApplication + + + + + + + + + + \ No newline at end of file diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/ContentBasedFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/ContentBasedFileRouter.java similarity index 94% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/ContentBasedFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/ContentBasedFileRouter.java index 9106e996c3..2a3f7e5c7b 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/ContentBasedFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/ContentBasedFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/DeadLetterChannelFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/DeadLetterChannelFileRouter.java similarity index 94% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/DeadLetterChannelFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/DeadLetterChannelFileRouter.java index fdcad99f02..37a81af458 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/DeadLetterChannelFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/DeadLetterChannelFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.LoggingLevel; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/FileProcessor.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java similarity index 93% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/FileProcessor.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index 1ea2cad188..ce4d92e8ab 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/FileProcessor.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/FileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java similarity index 91% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/FileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java index 5216c9a595..760f37677b 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/FileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/MessageTranslatorFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MessageTranslatorFileRouter.java similarity index 92% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/MessageTranslatorFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MessageTranslatorFileRouter.java index b99de99dac..5e65c24c40 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/MessageTranslatorFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MessageTranslatorFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/MulticastFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MulticastFileRouter.java similarity index 95% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/MulticastFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MulticastFileRouter.java index 75a6e81d45..6f6aad177d 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/MulticastFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/MulticastFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/SplitterFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/SplitterFileRouter.java similarity index 93% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/SplitterFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/SplitterFileRouter.java index 551f9c9685..471dfa7a46 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/SplitterFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/SplitterFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file; +package com.baeldung.camel.apache.file; import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/file/cfg/ContentBasedFileRouterConfig.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java similarity index 84% rename from spring-apache-camel/src/main/java/com/baeldung/camel/file/cfg/ContentBasedFileRouterConfig.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java index ceb68dfa3b..2b24cf2a51 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/file/cfg/ContentBasedFileRouterConfig.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.file.cfg; +package com.baeldung.camel.apache.file.cfg; import java.util.Arrays; import java.util.List; @@ -8,7 +8,7 @@ import org.apache.camel.spring.javaconfig.CamelConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import com.baeldung.camel.file.ContentBasedFileRouter; +import com.baeldung.camel.apache.file.ContentBasedFileRouter; @Configuration public class ContentBasedFileRouterConfig extends CamelConfiguration { diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/Fruit.java similarity index 87% rename from spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/Fruit.java index 1932131ddd..d46eb0afd5 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/Fruit.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/Fruit.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.jackson; +package com.baeldung.camel.apache.jackson; public class Fruit { diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/FruitList.java similarity index 84% rename from spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/FruitList.java index 02f2b6feb0..f8678c6a1e 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/jackson/FruitList.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/jackson/FruitList.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.jackson; +package com.baeldung.camel.apache.jackson; import java.util.List; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/main/App.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/main/App.java similarity index 91% rename from spring-apache-camel/src/main/java/com/baeldung/camel/main/App.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/main/App.java index ac0605a215..6071db0580 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/main/App.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/main/App.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.main; +package com.baeldung.camel.apache.main; import org.springframework.context.support.ClassPathXmlApplicationContext; diff --git a/spring-apache-camel/src/main/java/com/baeldung/camel/processor/FileProcessor.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/processor/FileProcessor.java similarity index 89% rename from spring-apache-camel/src/main/java/com/baeldung/camel/processor/FileProcessor.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/processor/FileProcessor.java index 971dd206cd..5ca61a382a 100644 --- a/spring-apache-camel/src/main/java/com/baeldung/camel/processor/FileProcessor.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/processor/FileProcessor.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.processor; +package com.baeldung.camel.apache.processor; import org.apache.camel.Exchange; import org.apache.camel.Processor; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/Application.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/Application.java similarity index 97% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/Application.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/Application.java index 48294e9c56..797ad57202 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/Application.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/Application.java @@ -1,4 +1,4 @@ -package com.baeldung.camel; +package com.baeldung.camel.boot; import javax.ws.rs.core.MediaType; @@ -22,7 +22,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Component; @SpringBootApplication(exclude = { WebSocketServletAutoConfiguration.class, AopAutoConfiguration.class, OAuth2ResourceServerAutoConfiguration.class, EmbeddedWebServerFactoryCustomizerAutoConfiguration.class }) -@ComponentScan(basePackages = "com.baeldung.camel") +@ComponentScan(basePackages = "com.baeldung.camel.boot") public class Application { @Value("${server.port}") diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/ExampleServices.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/ExampleServices.java similarity index 90% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/ExampleServices.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/ExampleServices.java index ec8f368e68..6fe5a1ed32 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/ExampleServices.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/ExampleServices.java @@ -1,4 +1,4 @@ -package com.baeldung.camel; +package com.baeldung.camel.boot; /** * a Mock class to show how some other layer diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/MyBean.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/MyBean.java similarity index 90% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/MyBean.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/MyBean.java index 5368e40c93..759fb06459 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/MyBean.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/MyBean.java @@ -1,4 +1,4 @@ -package com.baeldung.camel; +package com.baeldung.camel.boot; public class MyBean { private Integer id; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileRouter.java similarity index 89% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileRouter.java index 670af5e08c..381a0a61a5 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.boot.testing; +package com.baeldung.camel.boot.boot.testing; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileSpringApplication.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileSpringApplication.java similarity index 87% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileSpringApplication.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileSpringApplication.java index a4e862e65d..1d20d1977a 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/boot/testing/GreetingsFileSpringApplication.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/boot/testing/GreetingsFileSpringApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.boot.testing; +package com.baeldung.camel.boot.boot.testing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBeanRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBeanRouter.java similarity index 93% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBeanRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBeanRouter.java index 8a03f6ef18..a747ba1f66 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBeanRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBeanRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.conditional; +package com.baeldung.camel.boot.conditional; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBodyRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBodyRouter.java similarity index 93% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBodyRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBodyRouter.java index 99d23c747b..ea4f77cb9a 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalBodyRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalBodyRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.conditional; +package com.baeldung.camel.boot.conditional; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalHeaderRouter.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalHeaderRouter.java similarity index 93% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalHeaderRouter.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalHeaderRouter.java index e723f97ef1..93371b06b6 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalHeaderRouter.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalHeaderRouter.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.conditional; +package com.baeldung.camel.boot.conditional; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalRoutingSpringApplication.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalRoutingSpringApplication.java similarity index 88% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalRoutingSpringApplication.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalRoutingSpringApplication.java index f20d23068a..f11b4302c7 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/ConditionalRoutingSpringApplication.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/ConditionalRoutingSpringApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.conditional; +package com.baeldung.camel.boot.conditional; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/FruitBean.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/FruitBean.java similarity index 84% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/FruitBean.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/FruitBean.java index 080e3393b6..a3481361bd 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/conditional/FruitBean.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/conditional/FruitBean.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.conditional; +package com.baeldung.camel.boot.conditional; import org.apache.camel.Exchange; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingSpringApplication.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingSpringApplication.java similarity index 88% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingSpringApplication.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingSpringApplication.java index df4550d9d5..bfa08a5c7a 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingSpringApplication.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingSpringApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRoute.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithDoTryRoute.java similarity index 94% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRoute.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithDoTryRoute.java index ce3cfc129b..d4c365d25c 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRoute.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithDoTryRoute.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import java.io.IOException; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRoute.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithExceptionClauseRoute.java similarity index 94% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRoute.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithExceptionClauseRoute.java index 3a438e2402..e2ee3252de 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRoute.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionHandlingWithExceptionClauseRoute.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import org.apache.camel.builder.RouteBuilder; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionLoggingProcessor.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionLoggingProcessor.java similarity index 94% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionLoggingProcessor.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionLoggingProcessor.java index 84e4072888..66add64441 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionLoggingProcessor.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionLoggingProcessor.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import java.util.Map; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionThrowingRoute.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionThrowingRoute.java similarity index 95% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionThrowingRoute.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionThrowingRoute.java index 752aabaf1a..bf4d464c23 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/ExceptionThrowingRoute.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/ExceptionThrowingRoute.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import org.apache.camel.Exchange; import org.apache.camel.Processor; diff --git a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessor.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/IllegalArgumentExceptionThrowingProcessor.java similarity index 93% rename from spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessor.java rename to messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/IllegalArgumentExceptionThrowingProcessor.java index 461a4e6553..db229418d2 100644 --- a/spring-boot-modules/spring-boot-camel/src/main/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessor.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/boot/exception/IllegalArgumentExceptionThrowingProcessor.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.exception; +package com.baeldung.camel.boot.exception; import org.apache.camel.Exchange; import org.apache.camel.Processor; diff --git a/spring-boot-modules/spring-boot-camel/src/main/resources/application.properties b/messaging-modules/spring-apache-camel/src/main/resources/application.properties similarity index 100% rename from spring-boot-modules/spring-boot-camel/src/main/resources/application.properties rename to messaging-modules/spring-apache-camel/src/main/resources/application.properties diff --git a/spring-boot-modules/spring-boot-camel/src/main/resources/application.yml b/messaging-modules/spring-apache-camel/src/main/resources/application.yml similarity index 100% rename from spring-boot-modules/spring-boot-camel/src/main/resources/application.yml rename to messaging-modules/spring-apache-camel/src/main/resources/application.yml diff --git a/spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml similarity index 82% rename from spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml index d6d3e62f1c..e93b9fb144 100644 --- a/spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-ContentBasedFileRouterTest.xml @@ -4,7 +4,7 @@ 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"> - + diff --git a/spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml similarity index 91% rename from spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml index ef61174b32..b9db0a189f 100644 --- a/spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-DeadLetterChannelFileRouter.xml @@ -4,7 +4,7 @@ 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"> - + diff --git a/spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml similarity index 91% rename from spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml index 7ab988ca8a..fcb9e2b8be 100644 --- a/spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-MessageTranslatorFileRouterTest.xml @@ -4,7 +4,7 @@ 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"> - + diff --git a/spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml similarity index 83% rename from spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml index 6f7e7cbb60..73adecbc98 100644 --- a/spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-MulticastFileRouterTest.xml @@ -4,7 +4,7 @@ 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"> - + diff --git a/spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml similarity index 83% rename from spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml index 9d4a890cc6..a2ebe76e63 100644 --- a/spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-SplitterFileRouter.xml @@ -4,7 +4,7 @@ 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"> - + diff --git a/spring-apache-camel/src/main/resources/camel-context-test.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-test.xml similarity index 75% rename from spring-apache-camel/src/main/resources/camel-context-test.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context-test.xml index e6435db9e5..f306574868 100644 --- a/spring-apache-camel/src/main/resources/camel-context-test.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context-test.xml @@ -4,8 +4,8 @@ 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"> - - + + diff --git a/spring-apache-camel/src/main/resources/camel-context.xml b/messaging-modules/spring-apache-camel/src/main/resources/camel-context.xml similarity index 89% rename from spring-apache-camel/src/main/resources/camel-context.xml rename to messaging-modules/spring-apache-camel/src/main/resources/camel-context.xml index 63ef406fdf..721ccab95c 100644 --- a/spring-apache-camel/src/main/resources/camel-context.xml +++ b/messaging-modules/spring-apache-camel/src/main/resources/camel-context.xml @@ -35,5 +35,5 @@ - + \ No newline at end of file diff --git a/rabbitmq/src/main/resources/logback.xml b/messaging-modules/spring-apache-camel/src/main/resources/logback.xml similarity index 100% rename from rabbitmq/src/main/resources/logback.xml rename to messaging-modules/spring-apache-camel/src/main/resources/logback.xml diff --git a/spring-apache-camel/src/test/data/sampleInputFile/file.txt b/messaging-modules/spring-apache-camel/src/test/data/sampleInputFile/file.txt similarity index 100% rename from spring-apache-camel/src/test/data/sampleInputFile/file.txt rename to messaging-modules/spring-apache-camel/src/test/data/sampleInputFile/file.txt diff --git a/spring-apache-camel/src/test/java/com/baeldung/SpringContextTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/SpringContextTest.java similarity index 67% rename from spring-apache-camel/src/test/java/com/baeldung/SpringContextTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/SpringContextTest.java index 14e7de2095..56969da1d7 100644 --- a/spring-apache-camel/src/test/java/com/baeldung/SpringContextTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/SpringContextTest.java @@ -1,8 +1,8 @@ -package com.baeldung; +package com.apache.baeldung; import org.junit.Test; -import com.baeldung.camel.main.App; +import com.baeldung.camel.apache.main.App; public class SpringContextTest { diff --git a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java similarity index 95% rename from spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index 4810d7370e..bc0025b263 100644 --- a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.jackson; +package com.apache.baeldung.camel.jackson; import java.io.IOException; import java.net.URISyntaxException; @@ -13,6 +13,8 @@ import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.test.junit4.CamelTestSupport; import org.junit.Test; +import com.baeldung.camel.apache.jackson.Fruit; + public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { @Test diff --git a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java similarity index 93% rename from spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index b5647f02f9..2d15ebf46b 100644 --- a/spring-apache-camel/src/test/java/com/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.camel.jackson; +package com.apache.baeldung.camel.jackson; import java.io.IOException; import java.net.URISyntaxException; @@ -13,6 +13,9 @@ import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.test.junit4.CamelTestSupport; import org.junit.Test; +import com.baeldung.camel.apache.jackson.Fruit; +import com.baeldung.camel.apache.jackson.FruitList; + public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { @Test diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java similarity index 96% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java index 23f5787e4e..1fc3ee7515 100644 --- a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/ContentBasedFileRouterIntegrationTest.java @@ -11,7 +11,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.baeldung.camel.file.cfg.ContentBasedFileRouterConfig; +import com.baeldung.camel.apache.file.cfg.ContentBasedFileRouterConfig; @RunWith(JUnit4.class) public class ContentBasedFileRouterIntegrationTest { diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/DeadLetterChannelFileRouterIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/DeadLetterChannelFileRouterIntegrationTest.java similarity index 100% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/DeadLetterChannelFileRouterIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/DeadLetterChannelFileRouterIntegrationTest.java diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java similarity index 97% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index 1d88e8aeb4..bc5de17537 100644 --- a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -9,7 +9,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.baeldung.camel.file.FileProcessor; +import com.baeldung.camel.apache.file.FileProcessor; public class FileProcessorIntegrationTest { diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MessageTranslatorFileRouterIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MessageTranslatorFileRouterIntegrationTest.java similarity index 100% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/MessageTranslatorFileRouterIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MessageTranslatorFileRouterIntegrationTest.java diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MulticastFileRouterIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MulticastFileRouterIntegrationTest.java similarity index 100% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/MulticastFileRouterIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/MulticastFileRouterIntegrationTest.java diff --git a/spring-apache-camel/src/test/java/com/apache/camel/file/processor/SplitterFileRouterIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/SplitterFileRouterIntegrationTest.java similarity index 100% rename from spring-apache-camel/src/test/java/com/apache/camel/file/processor/SplitterFileRouterIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/file/processor/SplitterFileRouterIntegrationTest.java diff --git a/spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java similarity index 96% rename from spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java index b33e6a3b29..cef387dc14 100644 --- a/spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/apache/camel/main/AppIntegrationTest.java @@ -1,6 +1,6 @@ package com.apache.camel.main; -import com.baeldung.camel.main.App; +import com.baeldung.camel.apache.main.App; import junit.framework.TestCase; import org.apache.camel.util.FileUtil; import org.junit.After; diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/SpringContextTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/SpringContextTest.java similarity index 85% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/SpringContextTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/SpringContextTest.java index ce743e0f77..527877f47e 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/SpringContextTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/SpringContextTest.java @@ -1,11 +1,11 @@ -package com.baeldung; +package com.boot; 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.camel.Application; +import com.baeldung.camel.boot.Application; @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/boot/testing/GreetingsFileRouterUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/boot/testing/GreetingsFileRouterUnitTest.java similarity index 71% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/boot/testing/GreetingsFileRouterUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/boot/testing/GreetingsFileRouterUnitTest.java index baeb1fd39c..0f4d71f23b 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/boot/testing/GreetingsFileRouterUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/boot/testing/GreetingsFileRouterUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.boot.testing; +package com.boot.camel.boot.testing; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -8,10 +10,14 @@ import org.apache.camel.test.spring.junit5.MockEndpoints; 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; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest @MockEndpoints("file:output") +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class GreetingsFileRouterUnitTest { @Autowired @@ -21,6 +27,7 @@ class GreetingsFileRouterUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendBody_thenGreetingReceivedSuccessfully() throws InterruptedException { mock.expectedBodiesReceived("Hello Baeldung Readers!"); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBeanRouterUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBeanRouterUnitTest.java similarity index 70% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBeanRouterUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBeanRouterUnitTest.java index bba1f21392..46a5bb5eb9 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBeanRouterUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBeanRouterUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.conditional; +package com.boot.camel.conditional; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -7,9 +9,13 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ConditionalBeanRouterUnitTest { @Autowired @@ -19,6 +25,7 @@ class ConditionalBeanRouterUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendBodyWithFruit_thenFavouriteHeaderReceivedSuccessfully() throws InterruptedException { mock.expectedHeaderReceived("favourite", "Apples"); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBodyRouterUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBodyRouterUnitTest.java similarity index 70% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBodyRouterUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBodyRouterUnitTest.java index 22c12a741f..745b9993ee 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalBodyRouterUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalBodyRouterUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.conditional; +package com.boot.camel.conditional; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -7,9 +9,13 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ConditionalBodyRouterUnitTest { @Autowired @@ -19,6 +25,7 @@ class ConditionalBodyRouterUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendBodyWithBaeldung_thenGoodbyeMessageReceivedSuccessfully() throws InterruptedException { mock.expectedBodiesReceived("Goodbye, Baeldung!"); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalHeaderRouterUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalHeaderRouterUnitTest.java similarity index 70% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalHeaderRouterUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalHeaderRouterUnitTest.java index 63fbf6682a..b2803f5682 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/conditional/ConditionalHeaderRouterUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/conditional/ConditionalHeaderRouterUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.conditional; +package com.boot.camel.conditional; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -7,9 +9,13 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ConditionalHeaderRouterUnitTest { @Autowired @@ -19,6 +25,7 @@ class ConditionalHeaderRouterUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendBodyWithFruit_thenFavouriteHeaderReceivedSuccessfully() throws InterruptedException { mock.expectedHeaderReceived("favourite", "Banana"); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java similarity index 70% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java index 23d3b1a392..68deb46883 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithDoTryRouteUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.exception; +package com.boot.camel.exception; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -7,9 +9,13 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ExceptionHandlingWithDoTryRouteUnitTest { @Autowired @@ -19,6 +25,7 @@ class ExceptionHandlingWithDoTryRouteUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendHeaders_thenExceptionRaisedAndHandledSuccessfully() throws Exception { mock.expectedMessageCount(1); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java similarity index 70% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java index 28d672bd64..25052f2c10 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionHandlingWithExceptionClauseRouteUnitTest.java @@ -1,4 +1,6 @@ -package com.baeldung.camel.exception; +package com.boot.camel.exception; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; @@ -7,9 +9,13 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ExceptionHandlingWithExceptionClauseRouteUnitTest { @Autowired @@ -19,6 +25,7 @@ class ExceptionHandlingWithExceptionClauseRouteUnitTest { private MockEndpoint mock; @Test + @DirtiesContext void whenSendHeaders_thenExceptionRaisedAndHandledSuccessfully() throws Exception { mock.expectedMessageCount(1); diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionThrowingRouteUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionThrowingRouteUnitTest.java similarity index 78% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionThrowingRouteUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionThrowingRouteUnitTest.java index 6e6944fce8..a547e84a0b 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/ExceptionThrowingRouteUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/ExceptionThrowingRouteUnitTest.java @@ -1,7 +1,8 @@ -package com.baeldung.camel.exception; +package com.boot.camel.exception; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; @@ -11,15 +12,20 @@ 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.test.annotation.DirtiesContext; -@SpringBootTest +import com.baeldung.camel.boot.Application; + +@SpringBootTest(classes = Application.class) @CamelSpringBootTest +@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) class ExceptionThrowingRouteUnitTest { @Autowired private ProducerTemplate template; @Test + @DirtiesContext void whenSendBody_thenExceptionRaisedSuccessfully() { CamelContext context = template.getCamelContext(); Exchange exchange = context.getEndpoint("direct:start-exception") diff --git a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java similarity index 76% rename from spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java rename to messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java index a95abdfd27..9d15f70547 100644 --- a/spring-boot-modules/spring-boot-camel/src/test/java/com/baeldung/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java +++ b/messaging-modules/spring-apache-camel/src/test/java/com/boot/camel/exception/IllegalArgumentExceptionThrowingProcessorUnitTest.java @@ -1,9 +1,11 @@ -package com.baeldung.camel.exception; +package com.boot.camel.exception; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; +import com.baeldung.camel.boot.exception.IllegalArgumentExceptionThrowingProcessor; + class IllegalArgumentExceptionThrowingProcessorUnitTest { @Test diff --git a/spring-apache-camel/src/test/resources/json/fruit-array.json b/messaging-modules/spring-apache-camel/src/test/resources/json/fruit-array.json similarity index 100% rename from spring-apache-camel/src/test/resources/json/fruit-array.json rename to messaging-modules/spring-apache-camel/src/test/resources/json/fruit-array.json diff --git a/spring-apache-camel/src/test/resources/json/fruit-list.json b/messaging-modules/spring-apache-camel/src/test/resources/json/fruit-list.json similarity index 100% rename from spring-apache-camel/src/test/resources/json/fruit-list.json rename to messaging-modules/spring-apache-camel/src/test/resources/json/fruit-list.json diff --git a/spring-jms/README.md b/messaging-modules/spring-jms/README.md similarity index 100% rename from spring-jms/README.md rename to messaging-modules/spring-jms/README.md diff --git a/spring-jms/pom.xml b/messaging-modules/spring-jms/pom.xml similarity index 93% rename from spring-jms/pom.xml rename to messaging-modules/spring-jms/pom.xml index ab202402f3..b94a31c0c5 100644 --- a/spring-jms/pom.xml +++ b/messaging-modules/spring-jms/pom.xml @@ -4,15 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-jms - 0.0.1-SNAPSHOT spring-jms war Introduction to Spring JMS com.baeldung - parent-modules - 1.0.0-SNAPSHOT + messaging-modules + 0.0.1-SNAPSHOT diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/Employee.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/Employee.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/Employee.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/Employee.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleMessageConverter.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleMessageConverter.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/SampleMessageConverter.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/SampleMessageConverter.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java b/messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java similarity index 100% rename from spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java rename to messaging-modules/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java diff --git a/spring-jms/src/main/resources/EmbeddedActiveMQ.xml b/messaging-modules/spring-jms/src/main/resources/EmbeddedActiveMQ.xml similarity index 100% rename from spring-jms/src/main/resources/EmbeddedActiveMQ.xml rename to messaging-modules/spring-jms/src/main/resources/EmbeddedActiveMQ.xml diff --git a/spring-jms/src/main/resources/applicationContext.xml b/messaging-modules/spring-jms/src/main/resources/applicationContext.xml similarity index 100% rename from spring-jms/src/main/resources/applicationContext.xml rename to messaging-modules/spring-jms/src/main/resources/applicationContext.xml diff --git a/saas/src/main/resources/logback.xml b/messaging-modules/spring-jms/src/main/resources/logback.xml similarity index 100% rename from saas/src/main/resources/logback.xml rename to messaging-modules/spring-jms/src/main/resources/logback.xml diff --git a/spring-jms/src/main/webapp/META-INF/MANIFEST.MF b/messaging-modules/spring-jms/src/main/webapp/META-INF/MANIFEST.MF similarity index 100% rename from spring-jms/src/main/webapp/META-INF/MANIFEST.MF rename to messaging-modules/spring-jms/src/main/webapp/META-INF/MANIFEST.MF diff --git a/spring-jms/src/test/java/com/baeldung/SpringContextTest.java b/messaging-modules/spring-jms/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-jms/src/test/java/com/baeldung/SpringContextTest.java rename to messaging-modules/spring-jms/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java b/messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java similarity index 100% rename from spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java rename to messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java b/messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java similarity index 100% rename from spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java rename to messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqLiveTest.java b/messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqLiveTest.java similarity index 100% rename from spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqLiveTest.java rename to messaging-modules/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqLiveTest.java diff --git a/microservices-modules/open-liberty/pom.xml b/microservices-modules/open-liberty/pom.xml index b914d4bc05..c4b0fd0b82 100644 --- a/microservices-modules/open-liberty/pom.xml +++ b/microservices-modules/open-liberty/pom.xml @@ -121,7 +121,6 @@ 9080 9443 7070 - 5.8.1 \ No newline at end of file diff --git a/microservices-modules/pom.xml b/microservices-modules/pom.xml index 4c7079f3cd..a9cd8d2cd9 100644 --- a/microservices-modules/pom.xml +++ b/microservices-modules/pom.xml @@ -19,6 +19,7 @@ microprofile msf4j open-liberty + rest-express \ No newline at end of file diff --git a/microservices-modules/rest-express/README.md b/microservices-modules/rest-express/README.md new file mode 100644 index 0000000000..a3340b238d --- /dev/null +++ b/microservices-modules/rest-express/README.md @@ -0,0 +1,6 @@ +## RestExpress + +This module contains articles about RestExpress. + +### Relevant articles +- [RESTful Microservices With RestExpress](https://www.baeldung.com/java-restexpress-guide) diff --git a/microservices-modules/rest-express/pom.xml b/microservices-modules/rest-express/pom.xml new file mode 100644 index 0000000000..f222998340 --- /dev/null +++ b/microservices-modules/rest-express/pom.xml @@ -0,0 +1,153 @@ + + + + microservices-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + rest-express + + A Basic, MongoDB-backed Service Suite + https://github.com/RestExpress/RestExpress-Scaffold + 1.0.0-SNAPSHOT + rest-express + jar + + + 0.3.3 + 3.1.2 + 2.6 + 0.11.3 + 1.0 + 0.4.8 + 4.11 + + + + + com.strategicgains + RestExpress + ${RestExpress.version} + + + com.strategicgains + Syntaxe + ${Syntaxe.version} + + + com.strategicgains.repoexpress + repoexpress-mongodb + ${repoexpress-mongodb.version} + + + com.strategicgains.plugin-express + CacheControlPlugin + ${RestExpress.plugin.version} + + + com.strategicgains + HyperExpressPlugin + ${HyperExpressPlugin.version} + + + com.strategicgains.plugin-express + MetricsPlugin + ${RestExpress.plugin.version} + + + com.strategicgains.plugin-express + SwaggerPlugin + ${RestExpress.plugin.version} + + + com.strategicgains.plugin-express + CORSPlugin + ${RestExpress.plugin.version} + + + io.dropwizard.metrics + metrics-graphite + ${metrics-graphite.version} + + + junit + junit + ${junit4.version} + jar + test + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.8 + 1.8 + UTF-8 + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + com.baeldung.restexpress.Main + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.1 + + false + + + *:* + + + + + + package + + shade + + + + + com.baeldung.restexpress.Main + + + + + + + + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.0 + + + + diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Configuration.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Configuration.java new file mode 100644 index 0000000000..22161a265b --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Configuration.java @@ -0,0 +1,75 @@ +package com.baeldung.restexpress; + +import com.baeldung.restexpress.objectid.SampleOidEntityController; +import com.baeldung.restexpress.objectid.SampleOidEntityRepository; +import com.baeldung.restexpress.objectid.SampleOidEntityService; +import com.baeldung.restexpress.uuid.SampleUuidEntityController; +import com.baeldung.restexpress.uuid.SampleUuidEntityRepository; +import com.baeldung.restexpress.uuid.SampleUuidEntityService; +import com.strategicgains.repoexpress.mongodb.MongoConfig; +import com.strategicgains.restexpress.plugin.metrics.MetricsConfig; +import org.restexpress.RestExpress; +import org.restexpress.util.Environment; + +import java.util.Properties; + +public class Configuration + extends Environment { + private static final String DEFAULT_EXECUTOR_THREAD_POOL_SIZE = "20"; + + private static final String PORT_PROPERTY = "port"; + private static final String BASE_URL_PROPERTY = "base.url"; + private static final String EXECUTOR_THREAD_POOL_SIZE = "executor.threadPool.size"; + + private int port; + private String baseUrl; + private int executorThreadPoolSize; + private MetricsConfig metricsSettings; + + private SampleUuidEntityController sampleUuidController; + private SampleOidEntityController sampleOidController; + + @Override + protected void fillValues(Properties p) { + this.port = Integer.parseInt(p.getProperty(PORT_PROPERTY, String.valueOf(RestExpress.DEFAULT_PORT))); + this.baseUrl = p.getProperty(BASE_URL_PROPERTY, "http://localhost:" + String.valueOf(port)); + this.executorThreadPoolSize = Integer.parseInt(p.getProperty(EXECUTOR_THREAD_POOL_SIZE, DEFAULT_EXECUTOR_THREAD_POOL_SIZE)); + this.metricsSettings = new MetricsConfig(p); + MongoConfig mongo = new MongoConfig(p); + initialize(mongo); + } + + private void initialize(MongoConfig mongo) { + SampleUuidEntityRepository samplesUuidRepository = new SampleUuidEntityRepository(mongo.getClient(), mongo.getDbName()); + SampleUuidEntityService sampleUuidService = new SampleUuidEntityService(samplesUuidRepository); + sampleUuidController = new SampleUuidEntityController(sampleUuidService); + + SampleOidEntityRepository samplesOidRepository = new SampleOidEntityRepository(mongo.getClient(), mongo.getDbName()); + SampleOidEntityService sampleOidService = new SampleOidEntityService(samplesOidRepository); + sampleOidController = new SampleOidEntityController(sampleOidService); + } + + public int getPort() { + return port; + } + + public String getBaseUrl() { + return baseUrl; + } + + public int getExecutorThreadPoolSize() { + return executorThreadPoolSize; + } + + public MetricsConfig getMetricsConfig() { + return metricsSettings; + } + + public SampleUuidEntityController getSampleUuidEntityController() { + return sampleUuidController; + } + + public SampleOidEntityController getSampleOidEntityController() { + return sampleOidController; + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Constants.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Constants.java new file mode 100644 index 0000000000..914c0a0a07 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Constants.java @@ -0,0 +1,23 @@ +package com.baeldung.restexpress; + +public class Constants { + /** + * These define the URL parmaeters used in the route definition strings (e.g. '{userId}'). + */ + public class Url { + //TODO: Your URL parameter names here... + public static final String SAMPLE_ID = "uuid"; + } + + /** + * These define the route names used in naming each route definitions. These names are used + * to retrieve URL patterns within the controllers by name to create links in responses. + */ + public class Routes { + //TODO: Your Route names here... + public static final String SINGLE_UUID_SAMPLE = "sample.single.route.uuid"; + public static final String SAMPLE_UUID_COLLECTION = "sample.collection.route.uuid"; + public static final String SINGLE_OID_SAMPLE = "sample.single.route.oid"; + public static final String SAMPLE_OID_COLLECTION = "sample.collection.route.oid"; + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/LastModifiedHeaderPostprocessor.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/LastModifiedHeaderPostprocessor.java new file mode 100644 index 0000000000..81314679a4 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/LastModifiedHeaderPostprocessor.java @@ -0,0 +1,33 @@ +package com.baeldung.restexpress; + +import com.strategicgains.repoexpress.domain.Timestamped; +import com.strategicgains.util.date.DateAdapter; +import com.strategicgains.util.date.HttpHeaderTimestampAdapter; +import org.restexpress.Request; +import org.restexpress.Response; +import org.restexpress.pipeline.Postprocessor; + +import static io.netty.handler.codec.http.HttpHeaders.Names.LAST_MODIFIED; + +/** + * Assigns the Last-Modified HTTP header on the response for GET responses, if applicable. + * + * @author toddf + * @since May 15, 2012 + */ +public class LastModifiedHeaderPostprocessor + implements Postprocessor { + DateAdapter fmt = new HttpHeaderTimestampAdapter(); + + @Override + public void process(Request request, Response response) { + if (!request.isMethodGet()) return; + if (!response.hasBody()) return; + + Object body = response.getBody(); + + if (!response.hasHeader(LAST_MODIFIED) && body.getClass().isAssignableFrom(Timestamped.class)) { + response.addHeader(LAST_MODIFIED, fmt.format(((Timestamped) body).getUpdatedAt())); + } + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Main.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Main.java new file mode 100644 index 0000000000..1c02402d89 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Main.java @@ -0,0 +1,11 @@ +package com.baeldung.restexpress; + +import org.restexpress.util.Environment; + +public class Main { + public static void main(String[] args) throws Exception { + Configuration config = Environment.load(args, Configuration.class); + Server server = new Server(config); + server.start().awaitShutdown(); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Relationships.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Relationships.java new file mode 100644 index 0000000000..4a94e96952 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Relationships.java @@ -0,0 +1,55 @@ +package com.baeldung.restexpress; + +import com.baeldung.restexpress.objectid.SampleOidEntity; +import com.baeldung.restexpress.uuid.SampleUuidEntity; +import com.strategicgains.hyperexpress.HyperExpress; +import com.strategicgains.hyperexpress.RelTypes; +import org.restexpress.RestExpress; +import org.restexpress.common.exception.ConfigurationException; + +import java.util.Map; + +public abstract class Relationships { + private static Map ROUTES; + + public static void define(RestExpress server) { + ROUTES = server.getRouteUrlsByName(); + + HyperExpress.relationships() + .forCollectionOf(SampleUuidEntity.class) + .rel(RelTypes.SELF, href(Constants.Routes.SAMPLE_UUID_COLLECTION)) + .withQuery("limit={limit}") + .withQuery("offset={offset}") + .rel(RelTypes.NEXT, href(Constants.Routes.SAMPLE_UUID_COLLECTION) + "?offset={nextOffset}") + .withQuery("limit={limit}") + .optional() + .rel(RelTypes.PREV, href(Constants.Routes.SAMPLE_UUID_COLLECTION) + "?offset={prevOffset}") + .withQuery("limit={limit}") + .optional() + + .forClass(SampleUuidEntity.class) + .rel(RelTypes.SELF, href(Constants.Routes.SINGLE_UUID_SAMPLE)) + .rel(RelTypes.UP, href(Constants.Routes.SAMPLE_UUID_COLLECTION)) + + .forCollectionOf(SampleOidEntity.class) + .rel(RelTypes.SELF, href(Constants.Routes.SAMPLE_OID_COLLECTION)) + .withQuery("limit={limit}") + .withQuery("offset={offset}") + .rel(RelTypes.NEXT, href(Constants.Routes.SAMPLE_OID_COLLECTION) + "?offset={nextOffset}") + .withQuery("limit={limit}") + .optional() + .rel(RelTypes.PREV, href(Constants.Routes.SAMPLE_OID_COLLECTION) + "?offset={prevOffset}") + .withQuery("limit={limit}") + .optional() + + .forClass(SampleOidEntity.class) + .rel(RelTypes.SELF, href(Constants.Routes.SINGLE_OID_SAMPLE)) + .rel(RelTypes.UP, href(Constants.Routes.SAMPLE_OID_COLLECTION)); + } + + private static String href(String name) { + String href = ROUTES.get(name); + if (href == null) throw new ConfigurationException("Route name not found: " + name); + return href; + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Routes.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Routes.java new file mode 100644 index 0000000000..a510dd24fa --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Routes.java @@ -0,0 +1,30 @@ +package com.baeldung.restexpress; + +import io.netty.handler.codec.http.HttpMethod; +import org.restexpress.RestExpress; + +public abstract class Routes { + public static void define(Configuration config, RestExpress server) { + // TODO: Your routes here... + server.uri("/samples/uuid/{uuid}.{format}", config.getSampleUuidEntityController()) + .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE) + .name(Constants.Routes.SINGLE_UUID_SAMPLE); + + server.uri("/samples/uuid.{format}", config.getSampleUuidEntityController()) + .action("readAll", HttpMethod.GET) + .method(HttpMethod.POST) + .name(Constants.Routes.SAMPLE_UUID_COLLECTION); + + server.uri("/samples/oid/{uuid}.{format}", config.getSampleOidEntityController()) + .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE) + .name(Constants.Routes.SINGLE_OID_SAMPLE); + + server.uri("/samples/oid.{format}", config.getSampleOidEntityController()) + .action("readAll", HttpMethod.GET) + .method(HttpMethod.POST) + .name(Constants.Routes.SAMPLE_OID_COLLECTION); + + // or REGEX matching routes... + // server.regex("/some.regex", config.getRouteController()); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Server.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Server.java new file mode 100644 index 0000000000..d5864e607d --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/Server.java @@ -0,0 +1,129 @@ +package com.baeldung.restexpress; + +import com.baeldung.restexpress.serialization.SerializationProvider; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.graphite.Graphite; +import com.codahale.metrics.graphite.GraphiteReporter; +import com.strategicgains.repoexpress.adapter.Identifiers; +import com.strategicgains.repoexpress.exception.DuplicateItemException; +import com.strategicgains.repoexpress.exception.InvalidObjectIdException; +import com.strategicgains.repoexpress.exception.ItemNotFoundException; +import com.strategicgains.restexpress.plugin.cache.CacheControlPlugin; +import com.strategicgains.restexpress.plugin.cors.CorsHeaderPlugin; +import com.strategicgains.restexpress.plugin.metrics.MetricsConfig; +import com.strategicgains.restexpress.plugin.metrics.MetricsPlugin; +import com.strategicgains.restexpress.plugin.swagger.SwaggerPlugin; +import com.strategicgains.syntaxe.ValidationException; +import org.restexpress.Flags; +import org.restexpress.RestExpress; +import org.restexpress.exception.BadRequestException; +import org.restexpress.exception.ConflictException; +import org.restexpress.exception.NotFoundException; +import org.restexpress.pipeline.SimpleConsoleLogMessageObserver; +import org.restexpress.plugin.hyperexpress.HyperExpressPlugin; +import org.restexpress.plugin.hyperexpress.Linkable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +import static io.netty.handler.codec.http.HttpHeaders.Names.*; +import static org.restexpress.Flags.Auth.PUBLIC_ROUTE; + +public class Server { + private static final String SERVICE_NAME = "TODO: Enter service name"; + private static final Logger LOG = LoggerFactory.getLogger(SERVICE_NAME); + + private RestExpress server; + private Configuration config; + private boolean isStarted = false; + + public Server(Configuration config) { + this.config = config; + RestExpress.setDefaultSerializationProvider(new SerializationProvider()); + Identifiers.UUID.useShortUUID(true); + + this.server = new RestExpress() + .setName(SERVICE_NAME) + .setBaseUrl(config.getBaseUrl()) + .setExecutorThreadCount(config.getExecutorThreadPoolSize()) + .addMessageObserver(new SimpleConsoleLogMessageObserver()); + + Routes.define(config, server); + Relationships.define(server); + configurePlugins(config, server); + mapExceptions(server); + } + + public Server start() { + if (!isStarted) { + server.bind(config.getPort()); + isStarted = true; + } + + return this; + } + + public void awaitShutdown() { + if (isStarted) server.awaitShutdown(); + } + + public void shutdown() { + if (isStarted) server.shutdown(); + } + + private void configurePlugins(Configuration config, RestExpress server) { + configureMetrics(config, server); + + new SwaggerPlugin() + .flag(Flags.Auth.PUBLIC_ROUTE) + .register(server); + + new CacheControlPlugin() + .register(server); + + new HyperExpressPlugin(Linkable.class) + .register(server); + + new CorsHeaderPlugin("*") + .flag(PUBLIC_ROUTE) + .allowHeaders(CONTENT_TYPE, ACCEPT, AUTHORIZATION, REFERER, LOCATION) + .exposeHeaders(LOCATION) + .register(server); + } + + private void configureMetrics(Configuration config, RestExpress server) { + MetricsConfig mc = config.getMetricsConfig(); + + if (mc.isEnabled()) { + MetricRegistry registry = new MetricRegistry(); + new MetricsPlugin(registry) + .register(server); + + if (mc.isGraphiteEnabled()) { + final Graphite graphite = new Graphite(new InetSocketAddress(mc.getGraphiteHost(), mc.getGraphitePort())); + final GraphiteReporter reporter = GraphiteReporter.forRegistry(registry) + .prefixedWith(mc.getPrefix()) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .filter(MetricFilter.ALL) + .build(graphite); + reporter.start(mc.getPublishSeconds(), TimeUnit.SECONDS); + } else { + LOG.warn("*** Graphite Metrics Publishing is Disabled ***"); + } + } else { + LOG.warn("*** Metrics Generation is Disabled ***"); + } + } + + private void mapExceptions(RestExpress server) { + server + .mapException(ItemNotFoundException.class, NotFoundException.class) + .mapException(DuplicateItemException.class, ConflictException.class) + .mapException(ValidationException.class, BadRequestException.class) + .mapException(InvalidObjectIdException.class, BadRequestException.class); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntity.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntity.java new file mode 100644 index 0000000000..f92e56889b --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntity.java @@ -0,0 +1,32 @@ +package com.baeldung.restexpress.objectid; + +import com.baeldung.restexpress.Constants; +import com.strategicgains.hyperexpress.annotation.BindToken; +import com.strategicgains.hyperexpress.annotation.TokenBindings; +import com.strategicgains.repoexpress.mongodb.AbstractMongodbEntity; +import org.restexpress.plugin.hyperexpress.Linkable; + +/** + * This is a sample entity identified by a MongoDB ObjectID (instead of a UUID). + * It also contains createdAt and updatedAt properties that are automatically maintained + * by the persistence layer (SampleOidEntityRepository). + */ +@TokenBindings({ + @BindToken(value = Constants.Url.SAMPLE_ID, field = "id") +}) +public class SampleOidEntity + extends AbstractMongodbEntity + implements Linkable { + private String name; + + public SampleOidEntity() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityController.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityController.java new file mode 100644 index 0000000000..1997ad9e10 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityController.java @@ -0,0 +1,80 @@ +package com.baeldung.restexpress.objectid; + +import com.baeldung.restexpress.Constants; +import com.strategicgains.hyperexpress.builder.DefaultTokenResolver; +import com.strategicgains.hyperexpress.builder.DefaultUrlBuilder; +import com.strategicgains.hyperexpress.builder.UrlBuilder; +import com.strategicgains.repoexpress.mongodb.Identifiers; +import io.netty.handler.codec.http.HttpMethod; +import org.restexpress.Request; +import org.restexpress.Response; +import org.restexpress.common.query.QueryFilter; +import org.restexpress.common.query.QueryOrder; +import org.restexpress.common.query.QueryRange; +import org.restexpress.query.QueryFilters; +import org.restexpress.query.QueryOrders; +import org.restexpress.query.QueryRanges; + +import java.util.List; + +/** + * This is the 'controller' layer, where HTTP details are converted to domain concepts and passed to the service layer. + * Then service layer response information is enhanced with HTTP details, if applicable, for the response. + *

+ * This controller demonstrates how to process an entity that is identified by a MongoDB ObjectId. + */ +public class SampleOidEntityController { + private static final UrlBuilder LOCATION_BUILDER = new DefaultUrlBuilder(); + private SampleOidEntityService service; + + public SampleOidEntityController(SampleOidEntityService sampleService) { + super(); + this.service = sampleService; + } + + public SampleOidEntity create(Request request, Response response) { + SampleOidEntity entity = request.getBodyAs(SampleOidEntity.class, "Resource details not provided"); + SampleOidEntity saved = service.create(entity); + + // Construct the response for create... + response.setResponseCreated(); + + // Include the Location header... + String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.SINGLE_OID_SAMPLE); + response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, new DefaultTokenResolver())); + + // Return the newly-created resource... + return saved; + } + + public SampleOidEntity read(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + SampleOidEntity entity = service.read(Identifiers.MONGOID.parse(id)); + + return entity; + } + + public List readAll(Request request, Response response) { + QueryFilter filter = QueryFilters.parseFrom(request); + QueryOrder order = QueryOrders.parseFrom(request); + QueryRange range = QueryRanges.parseFrom(request, 20); + List entities = service.readAll(filter, range, order); + long count = service.count(filter); + response.setCollectionResponse(range, entities.size(), count); + return entities; + } + + public void update(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + SampleOidEntity entity = request.getBodyAs(SampleOidEntity.class, "Resource details not provided"); + entity.setId(Identifiers.MONGOID.parse(id)); + service.update(entity); + response.setResponseNoContent(); + } + + public void delete(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + service.delete(Identifiers.MONGOID.parse(id)); + response.setResponseNoContent(); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityRepository.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityRepository.java new file mode 100644 index 0000000000..d003e04254 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.restexpress.objectid; + +import com.mongodb.MongoClient; +import com.strategicgains.repoexpress.mongodb.MongodbEntityRepository; + +public class SampleOidEntityRepository + extends MongodbEntityRepository { + @SuppressWarnings("unchecked") + public SampleOidEntityRepository(MongoClient mongo, String dbName) { + super(mongo, dbName, SampleOidEntity.class); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityService.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityService.java new file mode 100644 index 0000000000..076fa57e6b --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/objectid/SampleOidEntityService.java @@ -0,0 +1,48 @@ +package com.baeldung.restexpress.objectid; + +import com.strategicgains.repoexpress.domain.Identifier; +import com.strategicgains.syntaxe.ValidationEngine; +import org.restexpress.common.query.QueryFilter; +import org.restexpress.common.query.QueryOrder; +import org.restexpress.common.query.QueryRange; + +import java.util.List; + +/** + * This is the 'service' or 'business logic' layer, where business logic, syntactic and semantic + * domain validation occurs, along with calls to the persistence layer. + */ +public class SampleOidEntityService { + private SampleOidEntityRepository samples; + + public SampleOidEntityService(SampleOidEntityRepository samplesRepository) { + super(); + this.samples = samplesRepository; + } + + public SampleOidEntity create(SampleOidEntity entity) { + ValidationEngine.validateAndThrow(entity); + return samples.create(entity); + } + + public SampleOidEntity read(Identifier id) { + return samples.read(id); + } + + public void update(SampleOidEntity entity) { + ValidationEngine.validateAndThrow(entity); + samples.update(entity); + } + + public void delete(Identifier id) { + samples.delete(id); + } + + public List readAll(QueryFilter filter, QueryRange range, QueryOrder order) { + return samples.readAll(filter, range, order); + } + + public long count(QueryFilter filter) { + return samples.count(filter); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/JsonSerializationProcessor.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/JsonSerializationProcessor.java new file mode 100644 index 0000000000..e9487878f0 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/JsonSerializationProcessor.java @@ -0,0 +1,35 @@ +package com.baeldung.restexpress.serialization; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.strategicgains.hyperexpress.domain.hal.HalResource; +import com.strategicgains.hyperexpress.serialization.jackson.HalResourceDeserializer; +import com.strategicgains.hyperexpress.serialization.jackson.HalResourceSerializer; +import org.bson.types.ObjectId; +import org.restexpress.ContentType; +import org.restexpress.serialization.json.JacksonJsonProcessor; + +import java.util.UUID; + +public class JsonSerializationProcessor + extends JacksonJsonProcessor { + public JsonSerializationProcessor() { + super(); + addSupportedMediaTypes(ContentType.HAL_JSON); + } + + @Override + protected void initializeModule(SimpleModule module) { + super.initializeModule(module); + // For UUID as entity identifiers... + module.addDeserializer(UUID.class, new UuidDeserializer()); + module.addSerializer(UUID.class, new UuidSerializer()); + + // For MongoDB ObjectId as entity identifiers... + module.addDeserializer(ObjectId.class, new ObjectIdDeserializer()); + module.addSerializer(ObjectId.class, new ObjectIdSerializer()); + + // Support HalResource (de)serialization. + module.addDeserializer(HalResource.class, new HalResourceDeserializer()); + module.addSerializer(HalResource.class, new HalResourceSerializer()); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdDeserializer.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdDeserializer.java new file mode 100644 index 0000000000..84c1aca83b --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdDeserializer.java @@ -0,0 +1,19 @@ +package com.baeldung.restexpress.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.strategicgains.repoexpress.mongodb.Identifiers; +import org.bson.types.ObjectId; + +import java.io.IOException; + +public class ObjectIdDeserializer + extends JsonDeserializer { + @Override + public ObjectId deserialize(JsonParser json, DeserializationContext context) + throws IOException, JsonProcessingException { + return (ObjectId) Identifiers.MONGOID.parse(json.getText()).primaryKey(); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdSerializer.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdSerializer.java new file mode 100644 index 0000000000..8c3e63b7f8 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/ObjectIdSerializer.java @@ -0,0 +1,18 @@ +package com.baeldung.restexpress.serialization; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.bson.types.ObjectId; + +import java.io.IOException; + +public class ObjectIdSerializer + extends JsonSerializer { + @Override + public void serialize(ObjectId objectId, JsonGenerator json, SerializerProvider provider) + throws IOException, JsonProcessingException { + json.writeString(objectId.toString()); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/SerializationProvider.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/SerializationProvider.java new file mode 100644 index 0000000000..cb619be84f --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/SerializationProvider.java @@ -0,0 +1,29 @@ +package com.baeldung.restexpress.serialization; + +import org.restexpress.response.ErrorResponseWrapper; +import org.restexpress.response.ResponseWrapper; +import org.restexpress.serialization.AbstractSerializationProvider; +import org.restexpress.serialization.SerializationProcessor; + +public class SerializationProvider + extends AbstractSerializationProvider { + // SECTION: CONSTANTS + + private static final SerializationProcessor JSON_SERIALIZER = new JsonSerializationProcessor(); + private static final SerializationProcessor XML_SERIALIZER = new XmlSerializationProcessor(); + private static final ResponseWrapper RESPONSE_WRAPPER = new ErrorResponseWrapper(); + + public SerializationProvider() { + super(); + add(JSON_SERIALIZER, RESPONSE_WRAPPER, true); + add(XML_SERIALIZER, RESPONSE_WRAPPER); + } + + public static SerializationProcessor json() { + return JSON_SERIALIZER; + } + + public static SerializationProcessor xml() { + return XML_SERIALIZER; + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidDeserializer.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidDeserializer.java new file mode 100644 index 0000000000..ce676edff5 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidDeserializer.java @@ -0,0 +1,19 @@ +package com.baeldung.restexpress.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.strategicgains.repoexpress.util.UuidConverter; + +import java.io.IOException; +import java.util.UUID; + +public class UuidDeserializer + extends JsonDeserializer { + @Override + public UUID deserialize(JsonParser json, DeserializationContext context) + throws IOException, JsonProcessingException { + return UuidConverter.parse(json.getText()); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidFormatter.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidFormatter.java new file mode 100644 index 0000000000..c337dbeafd --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidFormatter.java @@ -0,0 +1,14 @@ +package com.baeldung.restexpress.serialization; + +import com.strategicgains.hyperexpress.annotation.TokenFormatter; +import com.strategicgains.repoexpress.util.UuidConverter; + +import java.util.UUID; + +public class UuidFormatter + implements TokenFormatter { + @Override + public String format(Object field) { + return UuidConverter.format((UUID) field); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidSerializer.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidSerializer.java new file mode 100644 index 0000000000..4349e6d144 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/UuidSerializer.java @@ -0,0 +1,19 @@ +package com.baeldung.restexpress.serialization; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.strategicgains.repoexpress.util.UuidConverter; + +import java.io.IOException; +import java.util.UUID; + +public class UuidSerializer + extends JsonSerializer { + @Override + public void serialize(UUID objectId, JsonGenerator json, SerializerProvider provider) + throws IOException, JsonProcessingException { + json.writeString(UuidConverter.format(objectId)); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XmlSerializationProcessor.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XmlSerializationProcessor.java new file mode 100644 index 0000000000..e1bdd229c1 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XmlSerializationProcessor.java @@ -0,0 +1,18 @@ +package com.baeldung.restexpress.serialization; + +import com.baeldung.restexpress.uuid.SampleUuidEntity; +import org.restexpress.serialization.xml.XstreamXmlProcessor; + +public class XmlSerializationProcessor + extends XstreamXmlProcessor { + public XmlSerializationProcessor() { + super(); + alias("sample", SampleUuidEntity.class); +// alias("element_name", Element.class); +// alias("element_name", Element.class); +// alias("element_name", Element.class); +// alias("element_name", Element.class); + registerConverter(new XstreamUuidConverter()); + registerConverter(new XstreamOidConverter()); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamOidConverter.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamOidConverter.java new file mode 100644 index 0000000000..5eb53814fb --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamOidConverter.java @@ -0,0 +1,28 @@ +package com.baeldung.restexpress.serialization; + +import com.strategicgains.repoexpress.mongodb.Identifiers; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import org.bson.types.ObjectId; + +/** + * @author toddf + * @since Feb 16, 2011 + */ +public class XstreamOidConverter + implements SingleValueConverter { + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(Class aClass) { + return ObjectId.class.isAssignableFrom(aClass); + } + + @Override + public Object fromString(String value) { + return (ObjectId) Identifiers.MONGOID.parse(value).primaryKey(); + } + + @Override + public String toString(Object objectId) { + return ((ObjectId) objectId).toString(); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamUuidConverter.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamUuidConverter.java new file mode 100644 index 0000000000..82f34bc36d --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/serialization/XstreamUuidConverter.java @@ -0,0 +1,29 @@ +package com.baeldung.restexpress.serialization; + +import com.strategicgains.repoexpress.util.UuidConverter; +import com.thoughtworks.xstream.converters.SingleValueConverter; + +import java.util.UUID; + +/** + * @author toddf + * @since Feb 16, 2011 + */ +public class XstreamUuidConverter + implements SingleValueConverter { + @SuppressWarnings("rawtypes") + @Override + public boolean canConvert(Class aClass) { + return UUID.class.isAssignableFrom(aClass); + } + + @Override + public Object fromString(String value) { + return UuidConverter.parse(value); + } + + @Override + public String toString(Object objectId) { + return UuidConverter.format((UUID) objectId); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntity.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntity.java new file mode 100644 index 0000000000..724e681700 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntity.java @@ -0,0 +1,23 @@ +package com.baeldung.restexpress.uuid; + +import com.baeldung.restexpress.Constants; +import com.baeldung.restexpress.serialization.UuidFormatter; +import com.strategicgains.hyperexpress.annotation.BindToken; +import com.strategicgains.hyperexpress.annotation.TokenBindings; +import com.strategicgains.repoexpress.mongodb.AbstractUuidMongodbEntity; +import org.restexpress.plugin.hyperexpress.Linkable; + +/** + * This is a sample entity identified by a UUID (instead of a MongoDB ObjectID). + * It also contains createdAt and updatedAt properties that are automatically maintained + * by the persistence layer (SampleUuidEntityRepository). + */ +@TokenBindings({ + @BindToken(value = Constants.Url.SAMPLE_ID, field = "id", formatter = UuidFormatter.class) +}) +public class SampleUuidEntity + extends AbstractUuidMongodbEntity + implements Linkable { + public SampleUuidEntity() { + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityController.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityController.java new file mode 100644 index 0000000000..addd94ee3b --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityController.java @@ -0,0 +1,79 @@ +package com.baeldung.restexpress.uuid; + +import com.baeldung.restexpress.Constants; +import com.strategicgains.hyperexpress.builder.DefaultTokenResolver; +import com.strategicgains.hyperexpress.builder.DefaultUrlBuilder; +import com.strategicgains.hyperexpress.builder.UrlBuilder; +import com.strategicgains.repoexpress.adapter.Identifiers; +import io.netty.handler.codec.http.HttpMethod; +import org.restexpress.Request; +import org.restexpress.Response; +import org.restexpress.common.query.QueryFilter; +import org.restexpress.common.query.QueryOrder; +import org.restexpress.common.query.QueryRange; +import org.restexpress.query.QueryFilters; +import org.restexpress.query.QueryOrders; +import org.restexpress.query.QueryRanges; + +import java.util.List; + +/** + * This is the 'controller' layer, where HTTP details are converted to domain concepts and passed to the service layer. + * Then service layer response information is enhanced with HTTP details, if applicable, for the response. + *

+ * This controller demonstrates how to process a MongoDB entity that is identified by a UUID. + */ +public class SampleUuidEntityController { + private static final UrlBuilder LOCATION_BUILDER = new DefaultUrlBuilder(); + private SampleUuidEntityService service; + + public SampleUuidEntityController(SampleUuidEntityService sampleService) { + super(); + this.service = sampleService; + } + + public SampleUuidEntity create(Request request, Response response) { + SampleUuidEntity entity = request.getBodyAs(SampleUuidEntity.class, "Resource details not provided"); + SampleUuidEntity saved = service.create(entity); + + // Construct the response for create... + response.setResponseCreated(); + + // Include the Location header... + String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.SINGLE_UUID_SAMPLE); + response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, new DefaultTokenResolver())); + + // Return the newly-created resource... + return saved; + } + + public SampleUuidEntity read(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + SampleUuidEntity entity = service.read(Identifiers.UUID.parse(id)); + return entity; + } + + public List readAll(Request request, Response response) { + QueryFilter filter = QueryFilters.parseFrom(request); + QueryOrder order = QueryOrders.parseFrom(request); + QueryRange range = QueryRanges.parseFrom(request, 20); + List entities = service.readAll(filter, range, order); + long count = service.count(filter); + response.setCollectionResponse(range, entities.size(), count); + return entities; + } + + public void update(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + SampleUuidEntity entity = request.getBodyAs(SampleUuidEntity.class, "Resource details not provided"); + entity.setId(Identifiers.UUID.parse(id)); + service.update(entity); + response.setResponseNoContent(); + } + + public void delete(Request request, Response response) { + String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied"); + service.delete(Identifiers.UUID.parse(id)); + response.setResponseNoContent(); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityRepository.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityRepository.java new file mode 100644 index 0000000000..0b5eef1ea6 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.restexpress.uuid; + +import com.mongodb.MongoClient; +import com.strategicgains.repoexpress.mongodb.MongodbUuidEntityRepository; + +public class SampleUuidEntityRepository + extends MongodbUuidEntityRepository { + @SuppressWarnings("unchecked") + public SampleUuidEntityRepository(MongoClient mongo, String dbName) { + super(mongo, dbName, SampleUuidEntity.class); + } +} diff --git a/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityService.java b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityService.java new file mode 100644 index 0000000000..57a1c18d05 --- /dev/null +++ b/microservices-modules/rest-express/src/main/java/com/baeldung/restexpress/uuid/SampleUuidEntityService.java @@ -0,0 +1,48 @@ +package com.baeldung.restexpress.uuid; + +import com.strategicgains.repoexpress.domain.Identifier; +import com.strategicgains.syntaxe.ValidationEngine; +import org.restexpress.common.query.QueryFilter; +import org.restexpress.common.query.QueryOrder; +import org.restexpress.common.query.QueryRange; + +import java.util.List; + +/** + * This is the 'service' or 'business logic' layer, where business logic, syntactic and semantic + * domain validation occurs, along with calls to the persistence layer. + */ +public class SampleUuidEntityService { + private SampleUuidEntityRepository samples; + + public SampleUuidEntityService(SampleUuidEntityRepository samplesRepository) { + super(); + this.samples = samplesRepository; + } + + public SampleUuidEntity create(SampleUuidEntity entity) { + ValidationEngine.validateAndThrow(entity); + return samples.create(entity); + } + + public SampleUuidEntity read(Identifier id) { + return samples.read(id); + } + + public void update(SampleUuidEntity entity) { + ValidationEngine.validateAndThrow(entity); + samples.update(entity); + } + + public void delete(Identifier id) { + samples.delete(id); + } + + public List readAll(QueryFilter filter, QueryRange range, QueryOrder order) { + return samples.readAll(filter, range, order); + } + + public long count(QueryFilter filter) { + return samples.count(filter); + } +} diff --git a/microservices-modules/rest-express/src/main/resources/config/dev/environment.properties b/microservices-modules/rest-express/src/main/resources/config/dev/environment.properties new file mode 100644 index 0000000000..b81f9a84cb --- /dev/null +++ b/microservices-modules/rest-express/src/main/resources/config/dev/environment.properties @@ -0,0 +1,22 @@ +# Default is 8081 +port = 8081 + +# The size of the executor thread pool (that can handle blocking back-end processing). +executor.threadPool.size = 20 + +# A MongoDB URI/Connection string +# see: http://docs.mongodb.org/manual/reference/connection-string/ +mongodb.uri = mongodb://localhost:27017/scaffolding_mongodb + +# The base URL, used as a prefix for links returned in data +# default is http://localhost: +#base.url = http://localhost:8081 + +#Configuration for the MetricsPlugin/Graphite +metrics.isEnabled = true +#metrics.machineName = +metrics.prefix = web1.example.com +metrics.graphite.isEnabled = false +metrics.graphite.host = graphite.example.com +metrics.graphite.port = 2003 +metrics.graphite.publishSeconds = 60 \ No newline at end of file diff --git a/orika/pom.xml b/orika/pom.xml index c18bb58a51..5ff898e6bd 100644 --- a/orika/pom.xml +++ b/orika/pom.xml @@ -21,6 +21,21 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + 1.5.0 diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index 115589b1b0..a1f16c4a64 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -24,6 +24,11 @@ pom import + + mysql + mysql-connector-java + ${mysql-connector-java.version} + org.springframework.boot spring-boot-dependencies @@ -89,8 +94,9 @@ 3.3.0 1.0.22.RELEASE - 2.7.5 + 2.7.8 1.9.1 + 8.0.31 \ No newline at end of file diff --git a/parent-boot-3/pom.xml b/parent-boot-3/pom.xml index 8f891ec788..44f7d97310 100644 --- a/parent-boot-3/pom.xml +++ b/parent-boot-3/pom.xml @@ -223,29 +223,6 @@ - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - 3.2.0 3.10.1 @@ -253,9 +230,8 @@ 3.3.0 2.22.2 - 3.0.0-M3 + 3.0.0 5.8.2 - 3.0.0-M7 0.9.17 17 ${java.version} diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml index 3525522ea7..80a8c7d77d 100644 --- a/parent-spring-5/pom.xml +++ b/parent-spring-5/pom.xml @@ -24,9 +24,9 @@ - 5.3.23 + 5.3.24 5.7.3 1.5.10.RELEASE - \ No newline at end of file + diff --git a/patterns-modules/README.md b/patterns-modules/README.md index 8cf237defd..654beb4cd7 100644 --- a/patterns-modules/README.md +++ b/patterns-modules/README.md @@ -2,4 +2,3 @@ This module contains articles about design patterns. -- [Coupling in Java](https://www.baeldung.com/java-coupling-classes-tight-loose) diff --git a/patterns-modules/coupling/README.md b/patterns-modules/coupling/README.md new file mode 100644 index 0000000000..2d39e74474 --- /dev/null +++ b/patterns-modules/coupling/README.md @@ -0,0 +1,2 @@ + +- [Coupling in Java](https://www.baeldung.com/java-coupling-classes-tight-loose) diff --git a/patterns-modules/design-patterns-architectural/pom.xml b/patterns-modules/design-patterns-architectural/pom.xml index 80c9b65b41..2d6117a406 100644 --- a/patterns-modules/design-patterns-architectural/pom.xml +++ b/patterns-modules/design-patterns-architectural/pom.xml @@ -74,4 +74,4 @@ 3.14.0 - + \ No newline at end of file diff --git a/patterns-modules/design-patterns-behavioral/src/test/java/com/baeldung/state/StatePatternUnitTest.java b/patterns-modules/design-patterns-behavioral/src/test/java/com/baeldung/state/StatePatternUnitTest.java index 731974f92b..98babf0ccd 100644 --- a/patterns-modules/design-patterns-behavioral/src/test/java/com/baeldung/state/StatePatternUnitTest.java +++ b/patterns-modules/design-patterns-behavioral/src/test/java/com/baeldung/state/StatePatternUnitTest.java @@ -1,11 +1,9 @@ package com.baeldung.state; import com.baeldung.state.Package; +import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.Assert.assertThat; -import static org.hamcrest.CoreMatchers.instanceOf; - -import org.junit.Test; +import org.junit.jupiter.api.Test; public class StatePatternUnitTest { @@ -13,13 +11,13 @@ public class StatePatternUnitTest { public void givenNewPackage_whenPackageReceived_thenStateReceived() { Package pkg = new Package(); - assertThat(pkg.getState(), instanceOf(OrderedState.class)); + assertTrue(pkg.getState() instanceof OrderedState); pkg.nextState(); - assertThat(pkg.getState(), instanceOf(DeliveredState.class)); + assertTrue(pkg.getState() instanceof DeliveredState); pkg.nextState(); - assertThat(pkg.getState(), instanceOf(ReceivedState.class)); + assertTrue(pkg.getState() instanceof ReceivedState); } @Test @@ -28,6 +26,6 @@ public class StatePatternUnitTest { pkg.setState(new DeliveredState()); pkg.previousState(); - assertThat(pkg.getState(), instanceOf(OrderedState.class)); + assertTrue(pkg.getState() instanceof OrderedState); } } diff --git a/patterns-modules/design-patterns-cloud/pom.xml b/patterns-modules/design-patterns-cloud/pom.xml index f166a02fba..acd3e64ed5 100644 --- a/patterns-modules/design-patterns-cloud/pom.xml +++ b/patterns-modules/design-patterns-cloud/pom.xml @@ -1,23 +1,24 @@ - 4.0.0 - design-patterns-cloud - design-patterns-cloud - jar + 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 + design-patterns-cloud + design-patterns-cloud + jar - - com.baeldung - patterns-modules - 1.0.0-SNAPSHOT - + + com.baeldung + patterns-modules + 1.0.0-SNAPSHOT + - - - io.github.resilience4j - resilience4j-retry - 1.7.1 - - - + + + io.github.resilience4j + resilience4j-retry + 1.7.1 + + + + \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational-2/README.md b/patterns-modules/design-patterns-creational-2/README.md new file mode 100644 index 0000000000..dc5b2a1861 --- /dev/null +++ b/patterns-modules/design-patterns-creational-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [The Factory Design Pattern in Java](https://www.baeldung.com/java-factory-pattern) diff --git a/patterns-modules/design-patterns-creational-2/pom.xml b/patterns-modules/design-patterns-creational-2/pom.xml new file mode 100644 index 0000000000..fe79052a99 --- /dev/null +++ b/patterns-modules/design-patterns-creational-2/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + design-patterns-creational-2 + design-patterns-creational-2 + jar + + + patterns-modules + com.baeldung + 1.0.0-SNAPSHOT + + + \ No newline at end of file diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/Corporation.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/Corporation.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/Corporation.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/Corporation.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/ElectricVehicle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/ElectricVehicle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/ElectricVehicle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/ElectricVehicle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleCorporation.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleCorporation.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleCorporation.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleCorporation.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleElectricCar.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleElectricCar.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleElectricCar.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleElectricCar.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleMotorcycle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleMotorcycle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleMotorcycle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/FutureVehicleMotorcycle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/MotorVehicle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/MotorVehicle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/MotorVehicle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/MotorVehicle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenCorporation.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenCorporation.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenCorporation.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenCorporation.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenElectricCar.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenElectricCar.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenElectricCar.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenElectricCar.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenMotorcycle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenMotorcycle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenMotorcycle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/abstract_factory/NextGenMotorcycle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/Car.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/Car.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/Car.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/Car.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/CarFactory.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/CarFactory.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/CarFactory.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/CarFactory.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorVehicle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorVehicle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorVehicle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorVehicle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorVehicleFactory.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorVehicleFactory.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorVehicleFactory.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorVehicleFactory.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/Motorcycle.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/Motorcycle.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/Motorcycle.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/Motorcycle.java diff --git a/patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorcycleFactory.java b/patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorcycleFactory.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/main/java/com/baeldung/factory_pattern/method/MotorcycleFactory.java rename to patterns-modules/design-patterns-creational-2/src/main/java/com/baeldung/factory_pattern/method/MotorcycleFactory.java diff --git a/patterns-modules/design-patterns-creational/src/test/java/com/baeldung/factory_pattern/abstract_factory/AbstractFactoryUnitTest.java b/patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/factory_pattern/abstract_factory/AbstractFactoryUnitTest.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/test/java/com/baeldung/factory_pattern/abstract_factory/AbstractFactoryUnitTest.java rename to patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/factory_pattern/abstract_factory/AbstractFactoryUnitTest.java diff --git a/patterns-modules/design-patterns-creational/src/test/java/com/baeldung/factory_pattern/method/FactoryMethodUnitTest.java b/patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/factory_pattern/method/FactoryMethodUnitTest.java similarity index 100% rename from patterns-modules/design-patterns-creational/src/test/java/com/baeldung/factory_pattern/method/FactoryMethodUnitTest.java rename to patterns-modules/design-patterns-creational-2/src/test/java/com/baeldung/factory_pattern/method/FactoryMethodUnitTest.java diff --git a/patterns-modules/design-patterns-singleton/README.md b/patterns-modules/design-patterns-singleton/README.md new file mode 100644 index 0000000000..edec116b93 --- /dev/null +++ b/patterns-modules/design-patterns-singleton/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [How to Serialize a Singleton in Java](https://www.baeldung.com/java-serialize-singleton) diff --git a/patterns-modules/design-patterns-singleton/pom.xml b/patterns-modules/design-patterns-singleton/pom.xml new file mode 100644 index 0000000000..362f7f83c1 --- /dev/null +++ b/patterns-modules/design-patterns-singleton/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + design-patterns-singleton + 1.0 + design-patterns-singleton + jar + + + com.baeldung + patterns-modules + 1.0.0-SNAPSHOT + + + \ No newline at end of file diff --git a/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/EnumSingleton.java b/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/EnumSingleton.java new file mode 100644 index 0000000000..4259211934 --- /dev/null +++ b/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/EnumSingleton.java @@ -0,0 +1,20 @@ +package com.baeldung.serializable_singleton; + +public enum EnumSingleton { + + INSTANCE("State Zero"); + + private String state; + + private EnumSingleton(String state) { + this.state = state; + } + + public static EnumSingleton getInstance() { + return INSTANCE; + } + + public String getState() { return this.state; } + + public void setState(String state) { this.state = state; } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/Singleton.java b/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/Singleton.java new file mode 100644 index 0000000000..6605d5dcf7 --- /dev/null +++ b/patterns-modules/design-patterns-singleton/src/main/java/com/baeldung/serializable_singleton/Singleton.java @@ -0,0 +1,28 @@ +package com.baeldung.serializable_singleton; + +import java.io.Serializable; + +public class Singleton implements Serializable { + + private static Singleton INSTANCE; + private String state = "State Zero"; + + private Singleton() { + } + + public static Singleton getInstance() { + if(INSTANCE == null) { + INSTANCE = new Singleton(); + } + + return INSTANCE; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/EnumSingletonUnitTest.java b/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/EnumSingletonUnitTest.java new file mode 100644 index 0000000000..7fdcb20850 --- /dev/null +++ b/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/EnumSingletonUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.serializable_singleton; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +// Unit test for the EnumSingleton class. +public class EnumSingletonUnitTest { + + private static final String ENUM_SINGLETON_TEST_TXT = "enum_singleton_test.txt"; + + // Checks that when an EnumSingleton instance is serialized + // and then deserialized, its state is preserved. + @Test + public void givenEnumSingleton_whenSerializedAndDeserialized_thenStatePreserved() { + EnumSingleton es1 = EnumSingleton.getInstance(); + + es1.setState("State One"); + + try (FileOutputStream fos = new FileOutputStream(ENUM_SINGLETON_TEST_TXT); + ObjectOutputStream oos = new ObjectOutputStream(fos); + FileInputStream fis = new FileInputStream(ENUM_SINGLETON_TEST_TXT); + ObjectInputStream ois = new ObjectInputStream(fis)) { + + // Serializing. + oos.writeObject(es1); + + // Deserializing. + EnumSingleton es2 = (EnumSingleton) ois.readObject(); + + // Checking if the state is preserved. + assertEquals(es1.getState(), es2.getState()); + + } catch (Exception e) { + System.out.println(e); + } + } + + // Checking that when an EnumSingleton instance is serialized + // and then deserialized, then there is still one instance + // of the EnumSingleton class in memory. + @Test + public void givenEnumSingleton_whenSerializedAndDeserialized_thenOneInstance() { + EnumSingleton es1 = EnumSingleton.getInstance(); + + try (FileOutputStream fos = new FileOutputStream(ENUM_SINGLETON_TEST_TXT); + ObjectOutputStream oos = new ObjectOutputStream(fos); + FileInputStream fis = new FileInputStream(ENUM_SINGLETON_TEST_TXT); + ObjectInputStream ois = new ObjectInputStream(fis)) { + + // Serializing. + oos.writeObject(es1); + + // Deserializing. + EnumSingleton es2 = (EnumSingleton) ois.readObject(); + + // Checking if es1 and es2 are pointing to + // the same instance in memory. + assertEquals(es1, es2); + + } catch (Exception e) { + System.out.println(e); + } + } + + @AfterAll + public static void cleanUp() { + final File removeFile = new File(ENUM_SINGLETON_TEST_TXT); + if (removeFile.exists()) { + removeFile.deleteOnExit(); + } + } +} diff --git a/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/SingletonUnitTest.java b/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/SingletonUnitTest.java new file mode 100644 index 0000000000..a46288cc8f --- /dev/null +++ b/patterns-modules/design-patterns-singleton/src/test/java/com/baeldung/serializable_singleton/SingletonUnitTest.java @@ -0,0 +1,78 @@ +package com.baeldung.serializable_singleton; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +// Unit test for the Singleton class. +public class SingletonUnitTest { + + private static final String SINGLETON_TEST_TXT = "singleton_test.txt"; + + // Checks that when a Singleton instance is serialized + // and then deserialized, its state is preserved. + @Test + public void givenSingleton_whenSerializedAndDeserialized_thenStatePreserved() { + Singleton s1 = Singleton.getInstance(); + + s1.setState("State One"); + + try (FileOutputStream fos = new FileOutputStream(SINGLETON_TEST_TXT); + ObjectOutputStream oos = new ObjectOutputStream(fos); + FileInputStream fis = new FileInputStream(SINGLETON_TEST_TXT); + ObjectInputStream ois = new ObjectInputStream(fis)) { + + // Serializing. + oos.writeObject(s1); + + // Deserializing. + Singleton s2 = (Singleton) ois.readObject(); + + // Checking if the state is preserved. + assertEquals(s1.getState(), s2.getState()); + + } catch (Exception e) { + System.out.println(e); + } + } + + // Checking that when a Singleton instance is serialized + // and then deserialized, then there are two instances of + // the Singleton class. + @Test + public void givenSingleton_whenSerializedAndDeserialized_thenTwoInstances() { + Singleton s1 = Singleton.getInstance(); + + try (FileOutputStream fos = new FileOutputStream(SINGLETON_TEST_TXT); + ObjectOutputStream oos = new ObjectOutputStream(fos); + FileInputStream fis = new FileInputStream(SINGLETON_TEST_TXT); + ObjectInputStream ois = new ObjectInputStream(fis)) { + + // Serializing. + oos.writeObject(s1); + + // Deserializing. + Singleton s2 = (Singleton) ois.readObject(); + + // Checking if s1 and s2 are not the same instance. + assertNotEquals(s1, s2); + + } catch (Exception e) { + System.out.println(e); + } + } + + @AfterAll + public static void cleanUp() { + final File removeFile = new File(SINGLETON_TEST_TXT); + if (removeFile.exists()) { + removeFile.deleteOnExit(); + } + } +} diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipe.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipe.java new file mode 100644 index 0000000000..6fdb4c71c3 --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipe.java @@ -0,0 +1,5 @@ +package com.baeldung.pipeline.immutable; + +public interface Pipe { + OUT process(IN input); +} diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipeline.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipeline.java new file mode 100644 index 0000000000..db46a26d7e --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/immutable/Pipeline.java @@ -0,0 +1,37 @@ +package com.baeldung.pipeline.immutable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +public class Pipeline { + + private Collection> pipes; + + private Pipeline(Pipe pipe) { + pipes = Collections.singletonList(pipe); + } + + private Pipeline(Collection> pipes) { + this.pipes = new ArrayList<>(pipes); + } + + public static Pipeline of(Pipe pipe) { + return new Pipeline<>(pipe); + } + + + public Pipeline withNextPipe(Pipe pipe) { + final ArrayList> newPipes = new ArrayList<>(pipes); + newPipes.add(pipe); + return new Pipeline<>(newPipes); + } + + public OUT process(IN input) { + Object output = input; + for (final Pipe pipe : pipes) { + output = pipe.process(output); + } + return (OUT) output; + } +} diff --git a/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/pipes/Pipe.java b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/pipes/Pipe.java new file mode 100644 index 0000000000..93f005fdd2 --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/main/java/com/baeldung/pipeline/pipes/Pipe.java @@ -0,0 +1,9 @@ +package com.baeldung.pipeline.pipes; + +public interface Pipe { + OUT process(IN input); + + default Pipe add(Pipe pipe) { + return input -> pipe.process(process(input)); + } +} diff --git a/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/BiFunctionPipelineUnitTest.java b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/BiFunctionPipelineUnitTest.java new file mode 100644 index 0000000000..5f094ad6e8 --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/BiFunctionPipelineUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.pipeline; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.function.BiFunction; +import java.util.function.Function; +import org.junit.jupiter.api.Test; + +class BiFunctionPipelineUnitTest { + + @Test + void whenCombiningFunctionAndBiFunctions_andInitializingPipeline_thenResultIsCorrect() { + BiFunction add = Integer::sum; + BiFunction mul = (a, b) -> a * b; + Function toString = Object::toString; + BiFunction pipeline = add.andThen(a -> mul.apply(a, 2)) + .andThen(toString); + String result = pipeline.apply(1, 2); + String expected = "6"; + assertEquals(expected, result); + } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/FunctionPipelineUnitTest.java b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/FunctionPipelineUnitTest.java new file mode 100644 index 0000000000..71bc14a5eb --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/FunctionPipelineUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.pipeline; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.function.Function; +import org.junit.jupiter.api.Test; + +class FunctionPipelineUnitTest { + + @Test + void whenCombiningThreeFunctions_andInitializingPipeline_thenResultIsCorrect() { + Function square = s -> s * s; + Function half = s -> s / 2; + Function toString = Object::toString; + Function pipeline = square.andThen(half) + .andThen(toString); + String result = pipeline.apply(5); + String expected = "12"; + assertEquals(expected, result); + } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipeUnitTest.java b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipeUnitTest.java new file mode 100644 index 0000000000..6a3a988f89 --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipeUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.pipeline; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.pipeline.pipes.Pipe; +import org.junit.jupiter.api.Test; + +class PipeUnitTest { + + @Test + void whenCombiningThreePipes_andInitializingPipeline_thenResultIsCorrect() { + Pipe square = s -> s * s; + Pipe half = s -> s / 2; + Pipe toString = Object::toString; + Pipe pipeline = square.add(half).add(toString); + String result = pipeline.process(5); + String expected = "12"; + assertThat(result).isEqualTo(expected); + } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipelineUnitTest.java b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipelineUnitTest.java new file mode 100644 index 0000000000..2cbafc6213 --- /dev/null +++ b/patterns-modules/design-patterns-structural/src/test/java/com/baeldung/pipeline/PipelineUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.pipeline; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.pipeline.immutable.Pipe; +import com.baeldung.pipeline.immutable.Pipeline; +import org.junit.jupiter.api.Test; + +class PipelineUnitTest { + + @Test + void whenCombiningThreePipes_andInitializingPipeline_thenResultIsCorrect() { + Pipe square = s -> s * s; + Pipe half = s -> s / 2; + Pipe toString = Object::toString; + Pipeline squarePipeline = Pipeline.of(square); + Pipeline squareAndHalfPipeline = squarePipeline.withNextPipe(half); + Pipeline squareHalfAndStringPipeline = squareAndHalfPipeline.withNextPipe(toString); + + String result = squareHalfAndStringPipeline.process(5); + String expected = "12"; + assertThat(result).isEqualTo(expected); + } +} \ No newline at end of file diff --git a/patterns-modules/enterprise-patterns/wire-tap/README.md b/patterns-modules/enterprise-patterns/README.md similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/README.md rename to patterns-modules/enterprise-patterns/README.md diff --git a/patterns-modules/enterprise-patterns/pom.xml b/patterns-modules/enterprise-patterns/pom.xml index aee56c04ff..0e9edbff67 100644 --- a/patterns-modules/enterprise-patterns/pom.xml +++ b/patterns-modules/enterprise-patterns/pom.xml @@ -12,10 +12,6 @@ 1.0.0-SNAPSHOT - - wire-tap - - @@ -69,7 +65,7 @@ 3.7.4 - 2.2.2.RELEASE + 2.7.8 2.17.1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/data/.camel/msg1.xml b/patterns-modules/enterprise-patterns/src/data/.camel/msg1.xml similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/data/.camel/msg1.xml rename to patterns-modules/enterprise-patterns/src/data/.camel/msg1.xml diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/data/msg.xml b/patterns-modules/enterprise-patterns/src/data/msg.xml similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/data/msg.xml rename to patterns-modules/enterprise-patterns/src/data/msg.xml diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/AmqApplication.java b/patterns-modules/enterprise-patterns/src/main/java/com/baeldung/AmqApplication.java similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/AmqApplication.java rename to patterns-modules/enterprise-patterns/src/main/java/com/baeldung/AmqApplication.java diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyBean.java b/patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyBean.java similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyBean.java rename to patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyBean.java diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyPayload.java b/patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyPayload.java similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyPayload.java rename to patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyPayload.java diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyPayloadClonePrepare.java b/patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyPayloadClonePrepare.java similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/java/com/baeldung/MyPayloadClonePrepare.java rename to patterns-modules/enterprise-patterns/src/main/java/com/baeldung/MyPayloadClonePrepare.java diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/resources/application.properties b/patterns-modules/enterprise-patterns/src/main/resources/application.properties similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/resources/application.properties rename to patterns-modules/enterprise-patterns/src/main/resources/application.properties diff --git a/patterns-modules/enterprise-patterns/wire-tap/src/main/resources/log4j.properties b/patterns-modules/enterprise-patterns/src/main/resources/log4j.properties similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/src/main/resources/log4j.properties rename to patterns-modules/enterprise-patterns/src/main/resources/log4j.properties diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-10-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-10-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-10-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-10-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-11-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-11-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-11-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-11-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-2-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-2-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-2-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-2-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-3-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-3-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-3-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-3-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-4-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-4-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-4-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-4-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-5-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-5-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-5-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-5-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-6-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-6-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-6-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-6-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-7-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-7-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-7-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-7-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-8-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-8-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-8-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-8-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-9-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-9-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-9-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-34209-1621429668568-4-9-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-10-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-10-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-10-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-10-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-11-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-11-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-11-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-11-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-2-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-2-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-2-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-2-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-3-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-3-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-3-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-3-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-4-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-4-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-4-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-4-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-5-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-5-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-5-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-5-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-6-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-6-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-6-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-6-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-7-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-7-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-7-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-7-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-8-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-8-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-8-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-8-1-1-1 diff --git a/patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-9-1-1-1 b/patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-9-1-1-1 similarity index 100% rename from patterns-modules/enterprise-patterns/wire-tap/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-9-1-1-1 rename to patterns-modules/enterprise-patterns/test/ID-PRINHYLTPDL1209-46717-1621429562728-4-9-1-1-1 diff --git a/patterns-modules/front-controller/pom.xml b/patterns-modules/front-controller/pom.xml index 84de94cee3..c30a7a666c 100644 --- a/patterns-modules/front-controller/pom.xml +++ b/patterns-modules/front-controller/pom.xml @@ -25,10 +25,12 @@ org.apache.maven.plugins maven-war-plugin + ${maven-war-plugin.version} org.eclipse.jetty jetty-maven-plugin + ${jetty-maven-plugin.version} /front-controller @@ -38,4 +40,9 @@ + + 3.3.2 + 11.0.13 + + \ No newline at end of file diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java deleted file mode 100644 index ee8a01d0e2..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.pattern.hexagonal.config; - -import com.baeldung.pattern.hexagonal.domain.services.EmployeeService; -import com.baeldung.pattern.hexagonal.domain.services.EmployeeServiceImpl; -import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class AppConfig { - @Bean - public EmployeeService getEmployeeService(EmployeeRepository employeeRepository) { - return new EmployeeServiceImpl(employeeRepository); - } -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java deleted file mode 100644 index fa6980824a..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.baeldung.pattern.hexagonal.config; - -import com.baeldung.pattern.hexagonal.persistence.MongoRepoEx; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; - -@Configuration -@EnableMongoRepositories(basePackageClasses = MongoRepoEx.class) -public class MongoConfig { -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java deleted file mode 100644 index 077fc6fdea..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.pattern.hexagonal.controller; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import com.baeldung.pattern.hexagonal.domain.services.EmployeeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/employees") -public class EmployeeController { - @Autowired - EmployeeService employeeService; - - @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public Employee addEmployee(@RequestBody Employee employee) { - return employeeService.addEmployee(employee); - } - - @GetMapping(path = "/{employeeId}") - public Employee getEmployee(@PathVariable("employeeId") String employeeId) { - return employeeService.getEmployee(employeeId); - } -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java deleted file mode 100644 index de1f15cf53..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.pattern.hexagonal.domain.model; - -import org.springframework.data.annotation.Id; - -import java.util.Objects; - -public class Employee { - @Id - private String empId; - private String empName; - private String empJobTitle; - - public String getEmpId() { - return empId; - } - - public void setEmpId(String empId) { - this.empId = empId; - } - - public String getEmpName() { - return empName; - } - - public void setEmpName(String empName) { - this.empName = empName; - } - - public String getEmpJobTitle() { - return empJobTitle; - } - - public void setEmpJobTitle(String empJobTitle) { - this.empJobTitle = empJobTitle; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Employee employee = (Employee) o; - return empId.equals(employee.empId); - } - - @Override - public int hashCode() { - return Objects.hash(empId); - } -} \ No newline at end of file diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java deleted file mode 100644 index 902abefabb..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.baeldung.pattern.hexagonal.domain.services; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; - -public interface EmployeeService { - - Employee addEmployee(Employee employee); - - Employee getEmployee(String employeeId); -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java deleted file mode 100644 index cd7c30ff30..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.pattern.hexagonal.domain.services; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Optional; - -public class EmployeeServiceImpl implements EmployeeService { - - private EmployeeRepository employeeRepository; - - @Autowired - public EmployeeServiceImpl(EmployeeRepository employeeRepository) { - this.employeeRepository = employeeRepository; - } - - @Override - public Employee addEmployee(Employee employee) { - return employeeRepository.add(employee); - } - - @Override - public Employee getEmployee(String employeeId) { - Optional employee = employeeRepository.findById(employeeId); - - if (employee.isPresent()) { - return employee.get(); - } else { - // throw - } - return null; - } -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java deleted file mode 100644 index 53b4b6d276..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.pattern.hexagonal.persistence; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface EmployeeRepository { - - Employee add(Employee employee); - - Optional findById(String id); - -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java deleted file mode 100644 index 08f0c96ab0..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.pattern.hexagonal.persistence; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public class MongoDBRepository implements EmployeeRepository { - - @Autowired - MongoRepoEx mongoRepository; - - @Override - public Employee add(Employee employee) { - return mongoRepository.insert(employee); - } - - @Override - public Optional findById(String id) { - return mongoRepository.findById(id); - } -} diff --git a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java b/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java deleted file mode 100644 index 766444c22f..0000000000 --- a/patterns-modules/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.baeldung.pattern.hexagonal.persistence; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface MongoRepoEx extends MongoRepository { -} diff --git a/patterns-modules/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplUnitTest.java b/patterns-modules/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplUnitTest.java deleted file mode 100644 index 542e45d6f4..0000000000 --- a/patterns-modules/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.baeldung.pattern.hexagonal.domain.services; - -import com.baeldung.pattern.hexagonal.domain.model.Employee; -import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class EmployeeServiceImplUnitTest { - - private EmployeeRepository employeeRepository; - private EmployeeService testService; - private Employee testModel; - - @BeforeEach - void setUp() { - employeeRepository = mock(EmployeeRepository.class); - - testService = new EmployeeServiceImpl(employeeRepository); - testModel = new Employee(); - testModel.setEmpId("2000"); - testModel.setEmpName("Test user 1"); - testModel.setEmpJobTitle("Software engineer"); - } - - @Test - void addEmployee() { - when(employeeRepository.add(any(Employee.class))).thenReturn(testModel); - - Employee testResponse = testService.addEmployee(testModel); - assertEquals(testModel, testResponse); - } - - @Test - void getEmployee() { - when(employeeRepository.findById("2000")).thenReturn(Optional.of(testModel)); - - Employee testResponse = testService.getEmployee("2000"); - assertEquals(testModel, testResponse); - } -} \ No newline at end of file diff --git a/patterns-modules/idd/README.md b/patterns-modules/idd/README.md new file mode 100644 index 0000000000..e320af31b4 --- /dev/null +++ b/patterns-modules/idd/README.md @@ -0,0 +1 @@ +### Relevant Articles: \ No newline at end of file diff --git a/patterns-modules/enterprise-patterns/wire-tap/pom.xml b/patterns-modules/idd/pom.xml similarity index 59% rename from patterns-modules/enterprise-patterns/wire-tap/pom.xml rename to patterns-modules/idd/pom.xml index e7959e17f0..02795089e0 100644 --- a/patterns-modules/enterprise-patterns/wire-tap/pom.xml +++ b/patterns-modules/idd/pom.xml @@ -3,23 +3,27 @@ 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 - wire-tap + idd 1.0 - jar - - - enterprise-patterns - com.baeldung - 1.0.0-SNAPSHOT - - + idd - org.springframework.boot - spring-boot-maven-plugin + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + jar + + + com.baeldung + patterns-modules + 1.0.0-SNAPSHOT + \ No newline at end of file diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/CreateHelpRequestDTO.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/CreateHelpRequestDTO.java new file mode 100644 index 0000000000..87084474db --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/CreateHelpRequestDTO.java @@ -0,0 +1,15 @@ +package com.baeldung.idd; + +public class CreateHelpRequestDTO { + + private final HelpRequestStatus status; + + public CreateHelpRequestDTO(HelpRequestStatus status) { + this.status = status; + } + + public HelpRequestStatus getStatus() { + return status; + } + +} diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestDTO.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestDTO.java new file mode 100644 index 0000000000..2ad0c5f100 --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestDTO.java @@ -0,0 +1,13 @@ +package com.baeldung.idd; + +public class HelpRequestDTO { + private HelpRequestStatus status; + + public HelpRequestStatus getStatus() { + return status; + } + + public HelpRequestDTO(HelpRequestStatus status) { + this.status = status; + } +} diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestService.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestService.java new file mode 100644 index 0000000000..02c0b2531c --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestService.java @@ -0,0 +1,11 @@ +package com.baeldung.idd; + +import java.util.List; + +public interface HelpRequestService { + HelpRequestDTO createHelpRequest(CreateHelpRequestDTO createHelpRequestDTO); + + List findAllByStatus(HelpRequestStatus status); + + HelpRequestDTO updateHelpRequest(UpdateHelpRequestDTO updateHelpRequestDTO); +} diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestServiceImpl.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestServiceImpl.java new file mode 100644 index 0000000000..8ffed62078 --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestServiceImpl.java @@ -0,0 +1,24 @@ +package com.baeldung.idd; + +import java.util.List; + +public class HelpRequestServiceImpl implements HelpRequestService { + + @Override + public HelpRequestDTO createHelpRequest(CreateHelpRequestDTO createHelpRequestDTO) { + // here goes the implementation + return new HelpRequestDTO(createHelpRequestDTO.getStatus()); + } + + @Override + public List findAllByStatus(HelpRequestStatus status) { + // here goes the implementation + return List.of(new HelpRequestDTO(status), new HelpRequestDTO(status)); + } + + @Override + public HelpRequestDTO updateHelpRequest(UpdateHelpRequestDTO updateHelpRequestDTO) { + // here goes the implementation + return new HelpRequestDTO(updateHelpRequestDTO.getStatus()); + } +} diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestStatus.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestStatus.java new file mode 100644 index 0000000000..adb2fb5cc3 --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/HelpRequestStatus.java @@ -0,0 +1,6 @@ +package com.baeldung.idd; + +public enum HelpRequestStatus { + OPEN, IN_PROGRESS, CLOSED +} + diff --git a/patterns-modules/idd/src/main/java/com/baeldung/idd/UpdateHelpRequestDTO.java b/patterns-modules/idd/src/main/java/com/baeldung/idd/UpdateHelpRequestDTO.java new file mode 100644 index 0000000000..04a46e3d27 --- /dev/null +++ b/patterns-modules/idd/src/main/java/com/baeldung/idd/UpdateHelpRequestDTO.java @@ -0,0 +1,14 @@ +package com.baeldung.idd; + +public class UpdateHelpRequestDTO { + + private final HelpRequestStatus status; + + public UpdateHelpRequestDTO(HelpRequestStatus status) { + this.status = status; + } + + public HelpRequestStatus getStatus() { + return status; + } +} diff --git a/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java new file mode 100644 index 0000000000..7bfacf8a48 --- /dev/null +++ b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.idd; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import java.util.List; + +public class HelpRequestServiceUnitTest { + + HelpRequestService testHelpRequestService = new HelpRequestService() { + @Override + public HelpRequestDTO createHelpRequest(CreateHelpRequestDTO createHelpRequestDTO) { + return new HelpRequestDTO(HelpRequestStatus.OPEN); + } + + @Override + public List findAllByStatus(HelpRequestStatus status) { + return List.of(new HelpRequestDTO(HelpRequestStatus.OPEN)); + } + + @Override + public HelpRequestDTO updateHelpRequest(UpdateHelpRequestDTO updateHelpRequestDTO) { + return new HelpRequestDTO(HelpRequestStatus.OPEN); + } + }; + + @Test + public void givenHelpRequest_whenCreateHelpRequest_thenHelpRequestIsCreated() { + // given + CreateHelpRequestDTO createHelpRequestDTO = new CreateHelpRequestDTO(HelpRequestStatus.OPEN); + + // when + HelpRequestDTO helpRequestDTO = testHelpRequestService.createHelpRequest(createHelpRequestDTO); + + // then + Assertions.assertThat(helpRequestDTO).isNotNull(); + Assertions.assertThat(helpRequestDTO.getStatus()).isEqualTo(HelpRequestStatus.OPEN); + } + + @Test + public void givenHelpRequestList_whenFindAllByStatus_shouldContainOnlyStatus() { + HelpRequestService helpRequestService = new HelpRequestServiceImpl(); + List allByStatusOpen = helpRequestService.findAllByStatus(HelpRequestStatus.OPEN); + Assertions.assertThat(allByStatusOpen).extracting(HelpRequestDTO::getStatus).containsOnly(HelpRequestStatus.OPEN); + } + +} diff --git a/patterns-modules/intercepting-filter/pom.xml b/patterns-modules/intercepting-filter/pom.xml index 8028454ee2..cbce56cd6c 100644 --- a/patterns-modules/intercepting-filter/pom.xml +++ b/patterns-modules/intercepting-filter/pom.xml @@ -30,6 +30,7 @@ org.apache.maven.plugins maven-war-plugin + ${maven-war-plugin.version} false @@ -46,4 +47,8 @@ + + 3.3.2 + + \ No newline at end of file diff --git a/patterns-modules/pom.xml b/patterns-modules/pom.xml index 4c020734bf..5a99b539be 100644 --- a/patterns-modules/pom.xml +++ b/patterns-modules/pom.xml @@ -19,17 +19,19 @@ design-patterns-behavioral-2 design-patterns-cloud design-patterns-creational + design-patterns-creational-2 design-patterns-functional + design-patterns-singleton design-patterns-structural dip cqrs-es front-controller - hexagonal-architecture intercepting-filter solid clean-architecture enterprise-patterns coupling + idd @@ -70,4 +72,4 @@ 9.4.0.v20161208 - \ No newline at end of file + diff --git a/patterns-modules/solid/src/main/java/com/baeldung/s/GoodBook.java b/patterns-modules/solid/src/main/java/com/baeldung/s/Book.java similarity index 94% rename from patterns-modules/solid/src/main/java/com/baeldung/s/GoodBook.java rename to patterns-modules/solid/src/main/java/com/baeldung/s/Book.java index 04606bcdcd..8e26c88655 100644 --- a/patterns-modules/solid/src/main/java/com/baeldung/s/GoodBook.java +++ b/patterns-modules/solid/src/main/java/com/baeldung/s/Book.java @@ -1,6 +1,6 @@ package com.baeldung.s; -public class GoodBook { +public class Book { private String name; private String author; diff --git a/pdf-2/README.md b/pdf-2/README.md index 531ebb04e5..12c0934543 100644 --- a/pdf-2/README.md +++ b/pdf-2/README.md @@ -1,2 +1,3 @@ ## Relevant articles - [Editing Existing PDF Files in Java](https://www.baeldung.com/java-edit-existing-pdf) +- [Get Information About a PDF in Java](https://www.baeldung.com/java-pdf-info) diff --git a/pdf-2/pom.xml b/pdf-2/pom.xml index 1c752a9e9c..653b55a206 100644 --- a/pdf-2/pom.xml +++ b/pdf-2/pom.xml @@ -38,7 +38,7 @@ - pdf + pdf-2 src/main/resources diff --git a/pdf/README.md b/pdf/README.md index dd6931ba78..2a9a23a804 100644 --- a/pdf/README.md +++ b/pdf/README.md @@ -8,3 +8,4 @@ This module contains articles about PDF files. - [Generating PDF Files Using Thymeleaf](https://www.baeldung.com/thymeleaf-generate-pdf) - [Java Convert PDF to Base64](https://www.baeldung.com/java-convert-pdf-to-base64) - [HTML to PDF Using OpenPDF](https://www.baeldung.com/java-html-to-pdf) +- [Reading PDF File Using Java](https://www.baeldung.com/java-pdf-file-read) diff --git a/pdf/sample.pdf b/pdf/sample.pdf new file mode 100644 index 0000000000..805a21e6e0 Binary files /dev/null and b/pdf/sample.pdf differ diff --git a/pdf/src/test/java/com/baeldung/pdfreadertest/ReadPdfFileUnitTest.java b/pdf/src/test/java/com/baeldung/pdfreadertest/ReadPdfFileUnitTest.java new file mode 100644 index 0000000000..83e3aa711a --- /dev/null +++ b/pdf/src/test/java/com/baeldung/pdfreadertest/ReadPdfFileUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.pdfreadertest; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.File; +import java.io.IOException; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.junit.jupiter.api.Test; + +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.parser.PdfTextExtractor; + +class ReadPdfFileUnitTest { + + @Test + public void givenSamplePdf_whenUsingApachePdfBox_thenCompareOutput() throws IOException { + String expectedText = "Hello World!\n"; + + File file = new File("sample.pdf"); + PDDocument document = PDDocument.load(file); + + PDFTextStripper stripper = new PDFTextStripper(); + + String text = stripper.getText(document); + + document.close(); + + assertEquals(expectedText, text); + + } + + @Test + public void givenSamplePdf_whenUsingiTextPdf_thenCompareOutput() throws IOException { + String expectedText = "Hello World!"; + + PdfReader reader = new PdfReader("sample.pdf"); + int pages = reader.getNumberOfPages(); + StringBuilder text = new StringBuilder(); + + for (int i = 1; i <= pages; i++) { + + text.append(PdfTextExtractor.getTextFromPage(reader, i)); + + } + reader.close(); + assertEquals(expectedText, text.toString()); + + } + +} diff --git a/persistence-modules/blaze-persistence/README.md b/persistence-modules/blaze-persistence/README.md new file mode 100644 index 0000000000..ca467fdfd9 --- /dev/null +++ b/persistence-modules/blaze-persistence/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Getting Started with Blaze Persistence](https://www.baeldung.com/blaze-persistence-tutorial) diff --git a/persistence-modules/blaze-persistence/pom.xml b/persistence-modules/blaze-persistence/pom.xml new file mode 100644 index 0000000000..dfe4a69eab --- /dev/null +++ b/persistence-modules/blaze-persistence/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + blaze-persistence + 1.0-SNAPSHOT + blaze-persistence + + + org.springframework.boot + spring-boot-starter-parent + 2.4.0 + + + + + + + com.blazebit + blaze-persistence-bom + ${blaze-persistence.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.blazebit + blaze-persistence-core-api + + + com.blazebit + blaze-persistence-core-impl + + + com.blazebit + blaze-persistence-integration-hibernate-5.4 + + + + com.blazebit + blaze-persistence-entity-view-api + + + com.blazebit + blaze-persistence-entity-view-impl + + + com.blazebit + blaze-persistence-entity-view-processor + + + + com.blazebit + blaze-persistence-integration-entity-view-spring + + + com.blazebit + blaze-persistence-integration-spring-data-2.4 + + + + org.springframework + spring-context + + + org.springframework + spring-orm + + + com.h2database + h2 + + + + org.springframework + spring-test + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + UTF-8 + 1.8 + 1.8 + 1.6.8 + + + \ No newline at end of file diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/BlazePersistenceApplication.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/BlazePersistenceApplication.java new file mode 100644 index 0000000000..e2976aaf37 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/BlazePersistenceApplication.java @@ -0,0 +1,57 @@ +package com.baeldung; + +import com.baeldung.model.Person; +import com.baeldung.model.Post; +import com.baeldung.repository.PersonRepository; +import com.baeldung.repository.PostRepository; +import com.baeldung.repository.PostViewRepository; +import com.baeldung.view.PostWithAuthorView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BlazePersistenceApplication implements CommandLineRunner { + + private static final Logger logger = LoggerFactory.getLogger(BlazePersistenceApplication.class); + + @Autowired + private PersonRepository personRepository; + + @Autowired + private PostRepository postRepository; + + @Autowired + private PostViewRepository postViewRepository; + + public static void main(String[] args) { + SpringApplication.run(BlazePersistenceApplication.class, args); + } + + @Override + public void run(String... args) { + + logger.info("All Posts:"); + Iterable posts = postRepository.findAll(); + posts.forEach(p -> logger.info(String.valueOf(p))); + + logger.info("Posts with title 'Spring' or author 'Peter':"); + Iterable postsFiltered = postRepository.findBy("Spring", "Peter"); + postsFiltered.forEach(p -> logger.info(String.valueOf(p))); + + logger.info("Find all post with author view:"); + Iterable postsView = postViewRepository.findAll(); + postsView.forEach(p -> logger.info(String.valueOf(p))); + + logger.info("Person with at least two posts:"); + Iterable personIterable = personRepository.find(); + personIterable.forEach(p -> logger.info(String.valueOf(p))); + + logger.info("All Persons:"); + Iterable personIterableAll = personRepository.findAll(); + personIterableAll.forEach(p -> logger.info(String.valueOf(p))); + } +} \ No newline at end of file diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/config/BlazePersistenceConfiguration.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/config/BlazePersistenceConfiguration.java new file mode 100644 index 0000000000..0ec2e881ed --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/config/BlazePersistenceConfiguration.java @@ -0,0 +1,35 @@ +package com.baeldung.config; + +import com.blazebit.persistence.Criteria; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.integration.view.spring.EnableEntityViews; +import com.blazebit.persistence.spi.CriteriaBuilderConfiguration; +import com.blazebit.persistence.spring.data.repository.config.EnableBlazeRepositories; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.spi.EntityViewConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.persistence.EntityManagerFactory; + +@Configuration +@EnableEntityViews(basePackages = {"com.baeldung.view"}) +@EnableBlazeRepositories(basePackages = "com.baeldung.repository") +public class BlazePersistenceConfiguration { + + @Autowired + private EntityManagerFactory entityManagerFactory; + + @Bean + public CriteriaBuilderFactory createCriteriaBuilderFactory() { + CriteriaBuilderConfiguration config = Criteria.getDefault(); + return config.createCriteriaBuilderFactory(entityManagerFactory); + } + + @Bean + public EntityViewManager createEntityViewManager(CriteriaBuilderFactory criteriaBuilderFactory, + EntityViewConfiguration entityViewConfiguration) { + return entityViewConfiguration.createEntityViewManager(criteriaBuilderFactory); + } +} \ No newline at end of file diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Person.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Person.java new file mode 100644 index 0000000000..a6daade80d --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Person.java @@ -0,0 +1,72 @@ +package com.baeldung.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import java.util.HashSet; +import java.util.Set; + +@Entity +public class Person { + + @Id + @GeneratedValue + private Long id; + + private String name; + + private int age; + + @OneToMany(mappedBy = "author") + private Set posts = new HashSet<>(); + + public Person() { + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + 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 Set getPosts() { + return posts; + } + + public void setPosts(Set posts) { + this.posts = posts; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Post.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Post.java new file mode 100644 index 0000000000..6fc10dc730 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/model/Post.java @@ -0,0 +1,68 @@ +package com.baeldung.model; + +import javax.persistence.*; + +@Entity +public class Post { + + @Id + @GeneratedValue + private Long id; + + private String title; + + private String content; + + @ManyToOne(fetch = FetchType.LAZY) + private Person author; + + public Post() { + } + + public Post(String title, String content, Person author) { + this.title = title; + this.content = content; + this.author = author; + } + + public Long getId() { + return id; + } + + public void setId(Long 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; + } + + public Person getAuthor() { + return author; + } + + public void setAuthor(Person author) { + this.author = author; + } + + @Override + public String toString() { + return "Post{" + + "id=" + id + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + '}'; + } +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PersonRepository.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PersonRepository.java new file mode 100644 index 0000000000..12b197e8be --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PersonRepository.java @@ -0,0 +1,47 @@ +package com.baeldung.repository; + +import com.baeldung.model.Person; +import com.baeldung.model.Post; +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.CriteriaBuilderFactory; +import org.springframework.stereotype.Repository; + +import javax.persistence.EntityManager; +import javax.transaction.Transactional; + +@Repository +@Transactional +public class PersonRepository { + + private final EntityManager entityManager; + + private final CriteriaBuilderFactory builderFactory; + + public PersonRepository(EntityManager entityManager, CriteriaBuilderFactory builderFactory) { + this.entityManager = entityManager; + this.builderFactory = builderFactory; + } + + public Iterable findPostsByPerson() { + CriteriaBuilder postCriteriaBuilder = builderFactory.create(entityManager, Post.class) + .from(Person.class, "person") + .select("person.posts"); + return postCriteriaBuilder.getResultList(); + } + + public Iterable findAll() { + return builderFactory.create(entityManager, Person.class).getResultList(); + } + + public Iterable find() { + CriteriaBuilder personCriteriaBuilder = builderFactory.create(entityManager, Person.class, "p") + .where("p.age") + .betweenExpression("18") + .andExpression("40") + .where("SIZE(p.posts)").geExpression("2") + .orderByAsc("p.name") + .orderByAsc("p.id"); + return personCriteriaBuilder.getResultList(); + } + +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostRepository.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostRepository.java new file mode 100644 index 0000000000..cf7edffe62 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostRepository.java @@ -0,0 +1,48 @@ +package com.baeldung.repository; + +import com.baeldung.model.Post; +import com.baeldung.view.PostWithAuthorView; +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.EntityViewSetting; +import org.springframework.stereotype.Repository; + +import javax.persistence.EntityManager; +import javax.transaction.Transactional; + +@Repository +@Transactional +public class PostRepository { + + private final EntityManager entityManager; + + private final CriteriaBuilderFactory builderFactory; + + private final EntityViewManager viewManager; + + public PostRepository(EntityManager entityManager, CriteriaBuilderFactory builderFactory, + EntityViewManager viewManager) { + this.entityManager = entityManager; + this.builderFactory = builderFactory; + this.viewManager = viewManager; + } + + public Iterable findAll() { + return builderFactory.create(entityManager, Post.class).getResultList(); + } + + public Iterable findBy(final String title, final String authorName) { + CriteriaBuilder postCriteriaBuilder = builderFactory.create(entityManager, Post.class, "p") + .whereOr() + .where("p.title").like().value(title + "%").noEscape() + .where("p.author.name").eq(authorName) + .endOr(); + + CriteriaBuilder postWithAuthorViewCriteriaBuilder = + viewManager.applySetting(EntityViewSetting + .create(PostWithAuthorView.class), postCriteriaBuilder); + + return postWithAuthorViewCriteriaBuilder.getResultList(); + } +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostViewRepository.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostViewRepository.java new file mode 100644 index 0000000000..ef241c73a2 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/repository/PostViewRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.repository; + +import com.baeldung.view.PostWithAuthorView; +import com.blazebit.persistence.spring.data.repository.EntityViewRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +@Repository +@Transactional(readOnly = true) +public interface PostViewRepository extends EntityViewRepository { +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PersonView.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PersonView.java new file mode 100644 index 0000000000..e9dd184629 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PersonView.java @@ -0,0 +1,16 @@ +package com.baeldung.view; + +import com.baeldung.model.Person; +import com.blazebit.persistence.view.EntityView; +import com.blazebit.persistence.view.IdMapping; + +@EntityView(Person.class) +public interface PersonView { + + @IdMapping + Long getId(); + + int getAge(); + + String getName(); +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostView.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostView.java new file mode 100644 index 0000000000..b335cda385 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostView.java @@ -0,0 +1,18 @@ +package com.baeldung.view; + +import com.baeldung.model.Post; +import com.blazebit.persistence.view.EntityView; +import com.blazebit.persistence.view.IdMapping; +import com.blazebit.persistence.view.Mapping; + +@EntityView(Post.class) +public interface PostView { + + @IdMapping + Long getId(); + + @Mapping("UPPER(title)") + String getTitle(); + + String getContent(); +} diff --git a/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostWithAuthorView.java b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostWithAuthorView.java new file mode 100644 index 0000000000..8a34a4e34a --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/java/com/baeldung/view/PostWithAuthorView.java @@ -0,0 +1,10 @@ +package com.baeldung.view; + +import com.baeldung.model.Post; +import com.blazebit.persistence.view.EntityView; + +@EntityView(Post.class) +public interface PostWithAuthorView extends PostView { + PersonView getAuthor(); + +} diff --git a/persistence-modules/blaze-persistence/src/main/resources/application.properties b/persistence-modules/blaze-persistence/src/main/resources/application.properties new file mode 100644 index 0000000000..de4a62720a --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.h2.console.enabled=true +spring.jpa.show-sql=true +logging.level.org.hibernate.SQL=DEBUG +spring.jpa.hibernate.ddl-auto=create +spring.datasource.url=jdbc:h2:mem:test +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=sa +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect \ No newline at end of file diff --git a/persistence-modules/blaze-persistence/src/main/resources/data.sql b/persistence-modules/blaze-persistence/src/main/resources/data.sql new file mode 100644 index 0000000000..0ed609a2a4 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/main/resources/data.sql @@ -0,0 +1,11 @@ +INSERT INTO Person(id, name, age) VALUES(1, 'Peter', 18); +INSERT INTO Person(id, name, age) VALUES(2, 'Emily', 36); +INSERT INTO Person(id, name, age) VALUES(3, 'John', 27); + +INSERT INTO Post(id, title, content, author_id) VALUES(1, 'Blaze Persistence', 'Blaze Content', 1); +INSERT INTO Post(id, title, content, author_id) VALUES(2, 'Jacoco', 'Jacoco Content', 1); +INSERT INTO Post(id, title, content, author_id) VALUES(3, 'Spring', 'Spring Content', 2); +INSERT INTO Post(id, title, content, author_id) VALUES(4, 'Spring Boot', 'Spring Boot Content', 3); +INSERT INTO Post(id, title, content, author_id) VALUES(5, 'Java 17', 'Java Content', 3); +INSERT INTO Post(id, title, content, author_id) VALUES(6, 'Functional Programming', 'Functional Programming Content', 3); +INSERT INTO Post(id, title, content, author_id) VALUES(7, 'Unit Testing', 'Unit Testing Content', 3); \ No newline at end of file diff --git a/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PersonUnitTest.java b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PersonUnitTest.java new file mode 100644 index 0000000000..16434d52d0 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PersonUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung; + +import com.baeldung.model.Person; +import com.baeldung.model.Post; +import com.baeldung.repository.PersonRepository; +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 java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ContextConfiguration(classes = TestContextConfig.class) +@ExtendWith(SpringExtension.class) +public class PersonUnitTest { + + @Autowired + private PersonRepository personRepository; + + @Test + public void whenFind_thenReturnCorrectListSize() { + final Iterable listIterable = personRepository.find(); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(2, list.size()); + assertEquals("John", list.get(0).getName()); + } + + @Test + public void whenFindAll_thenReturnCorrectListSize() { + final Iterable listIterable = personRepository.findAll(); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(3, list.size()); + } + + @Test + public void whenFindPostsByPerson_thenReturnCorrectListSize() { + final Iterable listIterable = personRepository.findPostsByPerson(); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(7, list.size()); + } + +} diff --git a/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PostUnitTest.java b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PostUnitTest.java new file mode 100644 index 0000000000..0af01de088 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/PostUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung; + +import com.baeldung.model.Post; +import com.baeldung.repository.PostRepository; +import com.baeldung.repository.PostViewRepository; +import com.baeldung.view.PostView; +import com.baeldung.view.PostWithAuthorView; +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 java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ContextConfiguration(classes = TestContextConfig.class) +@ExtendWith(SpringExtension.class) +public class PostUnitTest { + + @Autowired + private PostViewRepository postViewRepository; + + @Autowired + private PostRepository postRepository; + + @Test + public void whenFindAll_thenReturnCorrectListViewSize() { + final Iterable listIterable = postViewRepository.findAll(); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(7, list.size()); + } + + @Test + public void givenPostIdAndAuthorName_whenFind_thenReturnCorrectResult() { + final Iterable listIterable = + postRepository.findBy("Spring", "Peter"); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(4, list.size()); + } + + @Test + public void whenFindAll_thenReturnCorrectListSize() { + final Iterable listIterable = postRepository.findAll(); + final List list = new ArrayList<>(); + listIterable.forEach(list::add); + assertEquals(7, list.size()); + } + +} diff --git a/persistence-modules/blaze-persistence/src/test/java/com/baeldung/TestContextConfig.java b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/TestContextConfig.java new file mode 100644 index 0000000000..1df1fb21d9 --- /dev/null +++ b/persistence-modules/blaze-persistence/src/test/java/com/baeldung/TestContextConfig.java @@ -0,0 +1,15 @@ +package com.baeldung; + +import com.blazebit.persistence.integration.view.spring.EnableEntityViews; +import com.blazebit.persistence.spring.data.repository.config.EnableBlazeRepositories; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan("com.baeldung") +@EnableEntityViews(basePackages = {"com.baeldung.view"}) +@EnableBlazeRepositories(basePackages = "com.baeldung.repository") +public class TestContextConfig { + + +} diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index 472484d166..0bec7a808f 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -79,7 +79,7 @@ 3.11.11 20220320 07.00.00-MS-GA - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/resultset2json/ResultSet2JSONUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/resultset2json/ResultSet2JSONUnitTest.java index f3dd8350fa..4ca3ca23ef 100644 --- a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/resultset2json/ResultSet2JSONUnitTest.java +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/resultset2json/ResultSet2JSONUnitTest.java @@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class ResultSet2JSONUnitTest { JSONObject object = new JSONObject( - "{\"records\":[[\"doe1\",\"7173\",\"John\",\"Doe\"],[\"smith3\",\"3722\",\"Dana\",\"Smith\"],[\"john22\",\"5490\",\"John\",\"Wang\"]],\"fields\":[{\"schema\":\"PUBLIC\",\"name\":\"USERNAME\",\"type\":\"VARCHAR\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"ID\",\"type\":\"VARCHAR\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"First name\",\"type\":\"VARCHAR\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"Last name\",\"type\":\"VARCHAR\",\"table\":\"WORDS\"}]}"); + "{\"records\":[[\"doe1\",\"7173\",\"John\",\"Doe\"],[\"smith3\",\"3722\",\"Dana\",\"Smith\"],[\"john22\",\"5490\",\"John\",\"Wang\"]],\"fields\":[{\"schema\":\"PUBLIC\",\"name\":\"USERNAME\",\"type\":\"OTHER\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"ID\",\"type\":\"OTHER\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"First name\",\"type\":\"OTHER\",\"table\":\"WORDS\"},{\"schema\":\"PUBLIC\",\"name\":\"Last name\",\"type\":\"OTHER\",\"table\":\"WORDS\"}]}"); JSONArray array = new JSONArray( "[{\"USERNAME\":\"doe1\",\"First name\":\"John\",\"ID\":\"7173\",\"Last name\":\"Doe\"},{\"USERNAME\":\"smith3\",\"First name\":\"Dana\",\"ID\":\"3722\",\"Last name\":\"Smith\"},{\"USERNAME\":\"john22\",\"First name\":\"John\",\"ID\":\"5490\",\"Last name\":\"Wang\"}]"); @@ -43,7 +43,7 @@ public class ResultSet2JSONUnitTest { @Test void whenResultSetConvertedUsingJOOQDefaultApproach_shouldMatchJSON() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); - Connection dbConnection = DriverManager.getConnection("jdbc:h2:mem:rs2jdbc2", "user", "password"); + Connection dbConnection = DriverManager.getConnection("jdbc:h2:mem:rs2jdbc2;MODE=LEGACY", "user", "password"); // Create a table Statement stmt = dbConnection.createStatement(); stmt.execute("CREATE TABLE words AS SELECT * FROM CSVREAD('./example.csv')"); diff --git a/persistence-modules/deltaspike/pom.xml b/persistence-modules/deltaspike/pom.xml index 5c905b996c..974a61d618 100644 --- a/persistence-modules/deltaspike/pom.xml +++ b/persistence-modules/deltaspike/pom.xml @@ -293,7 +293,7 @@ 2.6 1.1.3 1.2.4.Final - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/deltaspike/src/test/resources/META-INF/persistence.xml b/persistence-modules/deltaspike/src/test/resources/META-INF/persistence.xml index ee69855138..ffcf20878c 100644 --- a/persistence-modules/deltaspike/src/test/resources/META-INF/persistence.xml +++ b/persistence-modules/deltaspike/src/test/resources/META-INF/persistence.xml @@ -28,7 +28,7 @@ - + diff --git a/persistence-modules/flyway/README.md b/persistence-modules/flyway/README.md index bd5f9bbe03..5fbbc7df9c 100644 --- a/persistence-modules/flyway/README.md +++ b/persistence-modules/flyway/README.md @@ -2,3 +2,4 @@ - [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway) - [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks) - [Rolling Back Migrations with Flyway](https://www.baeldung.com/flyway-roll-back) +- [Flyway Out of Order Migrations](https://www.baeldung.com/flyway-migrations) diff --git a/persistence-modules/flyway/db/out-of-order-migration/V1_0__create_city_table.sql b/persistence-modules/flyway/db/out-of-order-migration/V1_0__create_city_table.sql new file mode 100644 index 0000000000..1c45a12fac --- /dev/null +++ b/persistence-modules/flyway/db/out-of-order-migration/V1_0__create_city_table.sql @@ -0,0 +1,5 @@ +create table city ( + id numeric, + name varchar(50), + constraint pk_city primary key (id) +); \ No newline at end of file diff --git a/persistence-modules/flyway/db/out-of-order-migration/V1_1__add_zipcode_to_city.sql b/persistence-modules/flyway/db/out-of-order-migration/V1_1__add_zipcode_to_city.sql new file mode 100644 index 0000000000..a619097071 --- /dev/null +++ b/persistence-modules/flyway/db/out-of-order-migration/V1_1__add_zipcode_to_city.sql @@ -0,0 +1,3 @@ +alter table city add column ( + zip varchar(10) +); \ No newline at end of file diff --git a/persistence-modules/flyway/db/out-of-order-migration/V2_0__create_person_table.sql b/persistence-modules/flyway/db/out-of-order-migration/V2_0__create_person_table.sql new file mode 100644 index 0000000000..19aa5e2ac7 --- /dev/null +++ b/persistence-modules/flyway/db/out-of-order-migration/V2_0__create_person_table.sql @@ -0,0 +1,5 @@ +create table person ( + id numeric, + name varchar(50), + constraint pk_person primary key (id) +); \ No newline at end of file diff --git a/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java b/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java index ae5174ac9c..d3f64bfed3 100644 --- a/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java +++ b/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java @@ -34,6 +34,7 @@ public class HibernateUtil { ServiceRegistry serviceRegistry) { MetadataSources metadataSources = new MetadataSources(serviceRegistry); metadataSources.addAnnotatedClass(Product.class); + metadataSources.addAnnotatedClass(ProductEntity.class); Metadata metadata = metadataSources.getMetadataBuilder() .build(); return metadata.getSessionFactoryBuilder() diff --git a/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/ProductEntity.java b/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/ProductEntity.java new file mode 100644 index 0000000000..b9c5f5010d --- /dev/null +++ b/persistence-modules/hibernate-enterprise/src/main/java/com/baeldung/hibernate/exception/ProductEntity.java @@ -0,0 +1,40 @@ +package com.baeldung.hibernate.exception; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "PRODUCT") +public class ProductEntity { + + @Id + private Integer id; + private String name; + private String description; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/persistence-modules/hibernate-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java b/persistence-modules/hibernate-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java index 679f786796..891352843d 100644 --- a/persistence-modules/hibernate-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java +++ b/persistence-modules/hibernate-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java @@ -26,6 +26,7 @@ import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.DataException; import org.hibernate.exception.SQLGrammarException; import org.hibernate.hql.internal.ast.QuerySyntaxException; +import org.hibernate.id.IdentifierGenerationException; import org.hibernate.query.NativeQuery; import org.hibernate.tool.schema.spi.CommandAcceptanceException; import org.hibernate.tool.schema.spi.SchemaManagementException; @@ -222,6 +223,33 @@ public class HibernateExceptionUnitTest { } + @Test + public void givenEntityWithoutId_whenCallingSave_thenThrowIdentifierGenerationException() { + + thrown.expect(isA(IdentifierGenerationException.class)); + thrown.expectMessage("ids for this class must be manually assigned before calling save(): com.baeldung.hibernate.exception.Product"); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + ProductEntity product = new ProductEntity(); + product.setName("Product Name"); + + session.save(product); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + + } + @Test public void givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException() { thrown.expectCause(isA(DataException.class)); diff --git a/persistence-modules/hibernate-exceptions/pom.xml b/persistence-modules/hibernate-exceptions/pom.xml index efa18e1b72..4bef688715 100644 --- a/persistence-modules/hibernate-exceptions/pom.xml +++ b/persistence-modules/hibernate-exceptions/pom.xml @@ -39,7 +39,7 @@ 2.4.0 2.3.0 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/hibernate-exceptions/src/main/resources/META-INF/persistence.xml b/persistence-modules/hibernate-exceptions/src/main/resources/META-INF/persistence.xml index 4e83a57f48..a154b41eb5 100644 --- a/persistence-modules/hibernate-exceptions/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/hibernate-exceptions/src/main/resources/META-INF/persistence.xml @@ -15,7 +15,7 @@ - + diff --git a/persistence-modules/hibernate-mapping-2/pom.xml b/persistence-modules/hibernate-mapping-2/pom.xml index 5ecb9e8b73..2a787a0e46 100644 --- a/persistence-modules/hibernate-mapping-2/pom.xml +++ b/persistence-modules/hibernate-mapping-2/pom.xml @@ -81,7 +81,7 @@ 9.0.0.M26 2.3.0.1 2.3.1 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping-2/src/main/resources/persistence-h2.properties b/persistence-modules/hibernate-mapping-2/src/main/resources/persistence-h2.properties index 9c8cf6e02b..33badc9b62 100644 --- a/persistence-modules/hibernate-mapping-2/src/main/resources/persistence-h2.properties +++ b/persistence-modules/hibernate-mapping-2/src/main/resources/persistence-h2.properties @@ -1,6 +1,6 @@ # jdbc.X jdbc.driverClassName=org.h2.Driver -jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;MODE=LEGACY jdbc.eventGeneratedId=sa jdbc.user=sa jdbc.pass= diff --git a/persistence-modules/hibernate-mapping-2/src/test/resources/manytomany.cfg.xml b/persistence-modules/hibernate-mapping-2/src/test/resources/manytomany.cfg.xml index 3ddff9a993..db7bc6ab8e 100644 --- a/persistence-modules/hibernate-mapping-2/src/test/resources/manytomany.cfg.xml +++ b/persistence-modules/hibernate-mapping-2/src/test/resources/manytomany.cfg.xml @@ -6,7 +6,7 @@ org.h2.Driver - jdbc:h2:mem:spring_hibernate_many_to_many + jdbc:h2:mem:spring_hibernate_many_to_many;MODE=LEGACY sa org.hibernate.dialect.H2Dialect thread diff --git a/persistence-modules/hibernate-queries/README.md b/persistence-modules/hibernate-queries/README.md index f5cba1aa6f..9e6c52d6dc 100644 --- a/persistence-modules/hibernate-queries/README.md +++ b/persistence-modules/hibernate-queries/README.md @@ -12,3 +12,4 @@ This module contains articles about use of Queries in Hibernate. - [Hibernate’s addScalar() Method](https://www.baeldung.com/hibernate-addscalar) - [Distinct Queries in HQL](https://www.baeldung.com/java-hql-distinct) - [JPA and Hibernate – Criteria vs. JPQL vs. HQL Query](https://www.baeldung.com/jpql-hql-criteria-query) +- [Database Keywords as Columns in Hibernate Entities](https://www.baeldung.com/java-hibernate-db-keywords-as-columns) diff --git a/persistence-modules/hibernate-queries/pom.xml b/persistence-modules/hibernate-queries/pom.xml index a2949e1513..68a46b82b1 100644 --- a/persistence-modules/hibernate-queries/pom.xml +++ b/persistence-modules/hibernate-queries/pom.xml @@ -79,6 +79,12 @@ jmh-generator-annprocess ${jmh-generator.version} + + org.testcontainers + mysql + ${testcontainers.mysql.version} + test + @@ -87,7 +93,8 @@ 9.0.0.M26 6.0.6 2.2.3 - 1.4.200 + 2.1.214 + 1.17.6 \ No newline at end of file diff --git a/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/BrokenPhoneOrder.java b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/BrokenPhoneOrder.java new file mode 100644 index 0000000000..e045005f28 --- /dev/null +++ b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/BrokenPhoneOrder.java @@ -0,0 +1,39 @@ +package com.baeldung.hibernate.keywords; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "broken_phone_order") +public class BrokenPhoneOrder implements Serializable { + @Id + @Column(name = "order") + String order; + @Column(name = "where") + String where; + + public BrokenPhoneOrder(String order, String where) { + this.order = order; + this.where = where; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } + + public String getWhere() { + return where; + } + + public void setWhere(String where) { + this.where = where; + } +} diff --git a/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/PhoneOrder.java b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/PhoneOrder.java new file mode 100644 index 0000000000..daee57d553 --- /dev/null +++ b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/keywords/PhoneOrder.java @@ -0,0 +1,39 @@ +package com.baeldung.hibernate.keywords; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "phone_order") +public class PhoneOrder implements Serializable { + @Id + @Column(name = "`order`") + String order; + @Column(name = "`where`") + String where; + + public PhoneOrder(String order, String where) { + this.order = order; + this.where = where; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } + + public String getWhere() { + return where; + } + + public void setWhere(String where) { + this.where = where; + } +} diff --git a/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExample.java b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExample.java index 69aaaae19d..4cbb6f40de 100644 --- a/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExample.java +++ b/persistence-modules/hibernate-queries/src/main/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExample.java @@ -39,8 +39,8 @@ public class HibernateScalarExample { .list(); } - public Integer fetchAvgAgeWithScalar() { - return (Integer) session.createNativeQuery("SELECT AVG(age) as avgAge FROM Student student") + public Double fetchAvgAgeWithScalar() { + return (Double) session.createNativeQuery("SELECT AVG(age) as avgAge FROM Student student") .addScalar("avgAge") .uniqueResult(); } diff --git a/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/keywords/HibernateKeywordsApplicationIntegrationTest.java b/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/keywords/HibernateKeywordsApplicationIntegrationTest.java new file mode 100644 index 0000000000..4282da3de4 --- /dev/null +++ b/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/keywords/HibernateKeywordsApplicationIntegrationTest.java @@ -0,0 +1,58 @@ +package com.baeldung.hibernate.keywords; + +import static java.util.UUID.randomUUID; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import javax.persistence.PersistenceException; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class HibernateKeywordsApplicationIntegrationTest { + + private static SessionFactory sessionFactory; + private Session session; + + @BeforeAll + static void createSession() { + sessionFactory = new Configuration().addAnnotatedClass(BrokenPhoneOrder.class) + .addAnnotatedClass(PhoneOrder.class) + .configure("keywords/hibernate.keywords.cfg.xml") + .buildSessionFactory(); + } + + @BeforeEach + void before() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @AfterEach + void after() { + session.close(); + } + + @Test + void givenBrokenPhoneOrderWithReservedKeywords_whenNewObjectIsPersisted_thenItFails() { + BrokenPhoneOrder order = new BrokenPhoneOrder(randomUUID().toString(), "My House"); + + assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> { + session.persist(order); + session.flush(); + }); + } + + @Test + void givenPhoneOrderWithEscapedKeywords_whenNewObjectIsPersisted_thenItSucceeds() { + PhoneOrder order = new PhoneOrder(randomUUID().toString(), "here"); + + session.persist(order); + session.flush(); + } + +} diff --git a/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExampleUnitTest.java b/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExampleUnitTest.java index ca01c5cb84..1752c11712 100644 --- a/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExampleUnitTest.java +++ b/persistence-modules/hibernate-queries/src/test/java/com/baeldung/hibernate/scalarmethod/HibernateScalarExampleUnitTest.java @@ -73,7 +73,7 @@ public class HibernateScalarExampleUnitTest { @Test public void whenScalarUsedForAvgAge_ThenSingleValueReturned() { - Integer avgAge = scalarExample.fetchAvgAgeWithScalar(); + Double avgAge = scalarExample.fetchAvgAgeWithScalar(); assertEquals(true, (avgAge >= 5 && avgAge <= 24)); } diff --git a/persistence-modules/hibernate-queries/src/test/resources/criteria.cfg.xml b/persistence-modules/hibernate-queries/src/test/resources/criteria.cfg.xml index 30d8168c5c..d46213ebc6 100644 --- a/persistence-modules/hibernate-queries/src/test/resources/criteria.cfg.xml +++ b/persistence-modules/hibernate-queries/src/test/resources/criteria.cfg.xml @@ -6,7 +6,7 @@ org.h2.Driver - jdbc:h2:mem:testdb + jdbc:h2:mem:testdb;MODE=LEGACY sa org.hibernate.dialect.H2Dialect diff --git a/persistence-modules/hibernate-queries/src/test/resources/hibernate-namedquery.properties b/persistence-modules/hibernate-queries/src/test/resources/hibernate-namedquery.properties index 120212070a..4fc32325da 100644 --- a/persistence-modules/hibernate-queries/src/test/resources/hibernate-namedquery.properties +++ b/persistence-modules/hibernate-queries/src/test/resources/hibernate-namedquery.properties @@ -1,5 +1,5 @@ hibernate.connection.driver_class=org.h2.Driver -hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'src/main/resources/init_database.sql' +hibernate.connection.url=jdbc:h2:mem:mydb1;MODE=LEGACY;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'src/main/resources/init_database.sql' hibernate.connection.username=sa hibernate.connection.autocommit=true jdbc.password= diff --git a/persistence-modules/hibernate-queries/src/test/resources/hibernate.properties b/persistence-modules/hibernate-queries/src/test/resources/hibernate.properties index c202f59f82..2d1b8dcb5d 100644 --- a/persistence-modules/hibernate-queries/src/test/resources/hibernate.properties +++ b/persistence-modules/hibernate-queries/src/test/resources/hibernate.properties @@ -1,5 +1,5 @@ hibernate.connection.driver_class=org.h2.Driver -hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.url=jdbc:h2:mem:mydb1;MODE=LEGACY;DB_CLOSE_DELAY=-1 hibernate.connection.username=sa hibernate.connection.autocommit=true jdbc.password= diff --git a/persistence-modules/hibernate-queries/src/test/resources/keywords/hibernate.keywords.cfg.xml b/persistence-modules/hibernate-queries/src/test/resources/keywords/hibernate.keywords.cfg.xml new file mode 100644 index 0000000000..9a1b6bb775 --- /dev/null +++ b/persistence-modules/hibernate-queries/src/test/resources/keywords/hibernate.keywords.cfg.xml @@ -0,0 +1,14 @@ + + + + + + org.hibernate.dialect.MySQLDialect + jdbc:tc:mysql:5.7.41:///restaurant?TC_INITSCRIPT=keywords/init.sql + org.testcontainers.jdbc.ContainerDatabaseDriver + validate + true + + + \ No newline at end of file diff --git a/persistence-modules/hibernate-queries/src/test/resources/keywords/init.sql b/persistence-modules/hibernate-queries/src/test/resources/keywords/init.sql new file mode 100644 index 0000000000..4d42a45f5b --- /dev/null +++ b/persistence-modules/hibernate-queries/src/test/resources/keywords/init.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS phone_order ( + `order` varchar(255) PRIMARY KEY, + `where` varchar(255) +); + +CREATE TABLE IF NOT EXISTS broken_phone_order ( + `order` varchar(255) PRIMARY KEY, + `where` varchar(255) +); \ No newline at end of file diff --git a/persistence-modules/hibernate5/pom.xml b/persistence-modules/hibernate5/pom.xml index 8f5ab01f77..1a2c65c6ba 100644 --- a/persistence-modules/hibernate5/pom.xml +++ b/persistence-modules/hibernate5/pom.xml @@ -57,10 +57,10 @@ - 5.4.12.Final + 5.4.24.Final 6.0.6 2.2.3 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryIdClass.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryIdClass.java index 18926640af..707713fe57 100644 --- a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryIdClass.java +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryIdClass.java @@ -3,6 +3,7 @@ package com.baeldung.hibernate.pojo; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; +import javax.persistence.ManyToOne; @Entity @IdClass(OrderEntryPK.class) @@ -11,6 +12,8 @@ public class OrderEntryIdClass { private long orderId; @Id private long productId; + @ManyToOne + private User user; public long getOrderId() { return orderId; @@ -28,4 +31,12 @@ public class OrderEntryIdClass { this.productId = productId; } + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + } diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryPK.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryPK.java index 637d590629..41ceb6ab25 100644 --- a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryPK.java +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryPK.java @@ -4,6 +4,7 @@ import java.io.Serializable; import java.util.Objects; import javax.persistence.Embeddable; +import javax.persistence.ManyToOne; @Embeddable public class OrderEntryPK implements Serializable { @@ -11,6 +12,9 @@ public class OrderEntryPK implements Serializable { private long orderId; private long productId; + @ManyToOne + private User user; + public long getOrderId() { return orderId; } @@ -27,6 +31,14 @@ public class OrderEntryPK implements Serializable { this.productId = productId; } + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/IdentifiersIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/IdentifiersIntegrationTest.java index 6b54dc80a8..29d1273b37 100644 --- a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/IdentifiersIntegrationTest.java +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/IdentifiersIntegrationTest.java @@ -63,9 +63,12 @@ public class IdentifiersIntegrationTest { @Test public void whenSaveCompositeIdEntity_thenOk() { + User user = new User(); + OrderEntryPK entryPK = new OrderEntryPK(); entryPK.setOrderId(1L); entryPK.setProductId(30L); + entryPK.setUser(user); OrderEntry entry = new OrderEntry(); entry.setEntryId(entryPK); @@ -77,9 +80,12 @@ public class IdentifiersIntegrationTest { @Test public void whenSaveIdClassEntity_thenOk() { + User user = new User(); + OrderEntryIdClass entry = new OrderEntryIdClass(); entry.setOrderId(1L); entry.setProductId(30L); + entry.setUser(user); session.save(entry); assertThat(entry.getOrderId()).isEqualTo(1L); diff --git a/persistence-modules/hibernate5/src/test/resources/hibernate-lifecycle.properties b/persistence-modules/hibernate5/src/test/resources/hibernate-lifecycle.properties index 1a5e6482bf..a1014d77ef 100644 --- a/persistence-modules/hibernate5/src/test/resources/hibernate-lifecycle.properties +++ b/persistence-modules/hibernate5/src/test/resources/hibernate-lifecycle.properties @@ -1,5 +1,5 @@ hibernate.connection.driver_class=org.h2.Driver -hibernate.connection.url=jdbc:h2:mem:lifecycledb;DB_CLOSE_DELAY=-1; +hibernate.connection.url=jdbc:h2:mem:lifecycledb;MODE=LEGACY;DB_CLOSE_DELAY=-1; hibernate.connection.username=sa hibernate.connection.password= hibernate.connection.autocommit=true diff --git a/persistence-modules/hibernate5/src/test/resources/hibernate-namingstrategy.properties b/persistence-modules/hibernate5/src/test/resources/hibernate-namingstrategy.properties index d0e068d13f..07922ae050 100644 --- a/persistence-modules/hibernate5/src/test/resources/hibernate-namingstrategy.properties +++ b/persistence-modules/hibernate5/src/test/resources/hibernate-namingstrategy.properties @@ -1,5 +1,5 @@ hibernate.connection.driver_class=org.h2.Driver -hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.url=jdbc:h2:mem:mydb1;MODE=LEGACY;DB_CLOSE_DELAY=-1 hibernate.connection.username=sa hibernate.dialect=org.hibernate.dialect.H2Dialect diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml index b9516281de..20143af9f0 100644 --- a/persistence-modules/java-jpa-3/pom.xml +++ b/persistence-modules/java-jpa-3/pom.xml @@ -91,7 +91,7 @@ 3.5.1 3.3.3 3.0.0 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java index d121c81c6b..79a5982140 100644 --- a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/ignorable/fields/HibernateConfig.java @@ -18,7 +18,7 @@ public class HibernateConfig { Properties settings = new Properties(); settings.put(Environment.DRIVER, "org.h2.Driver"); - settings.put(Environment.URL, "jdbc:h2:mem:test"); + settings.put(Environment.URL, "jdbc:h2:mem:test;MODE=LEGACY"); settings.put(Environment.USER, "sa"); settings.put(Environment.PASS, ""); settings.put(Environment.DIALECT, "org.hibernate.dialect.H2Dialect"); diff --git a/persistence-modules/java-jpa-3/src/test/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/test/resources/META-INF/persistence.xml index 9a33f912bf..bc52256d68 100644 --- a/persistence-modules/java-jpa-3/src/test/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-3/src/test/resources/META-INF/persistence.xml @@ -67,7 +67,7 @@ true - + @@ -104,7 +104,7 @@ true - + @@ -138,7 +138,7 @@ true - + diff --git a/persistence-modules/java-jpa/pom.xml b/persistence-modules/java-jpa/pom.xml index acdd648e45..0c8cec2116 100644 --- a/persistence-modules/java-jpa/pom.xml +++ b/persistence-modules/java-jpa/pom.xml @@ -107,7 +107,7 @@ 2.2 3.3.3 3.0.0 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml index b780a6f569..50188391af 100644 --- a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml @@ -15,7 +15,7 @@ + value="jdbc:h2:mem:test;MODE=LEGACY;INIT=RUNSCRIPT FROM 'classpath:database.sql'" /> + value="jdbc:h2:mem:test;MODE=LEGACY" /> + value="jdbc:h2:mem:entitygraphdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=USER" /> collection; + private static String collectionName; + private static String databaseName; + + public static void setUp() { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + + databaseName = "baeldung"; + collectionName = "pet"; + + database = mongoClient.getDatabase(databaseName); + collection = database.getCollection(collectionName); + } + } + + public static void addFieldToExistingBsonFilter() { + + Bson existingFilter = and(eq("type", "Dog"), eq("gender", "Male")); + + Bson newFilter = and(existingFilter, gt("age", 5)); + FindIterable documents = collection.find(newFilter); + + MongoCursor cursor = documents.iterator(); + while (cursor.hasNext()) { + System.out.println(cursor.next()); + } + } + + + public static void addFieldToExistingBsonFilterUsingBsonDocument() { + + Bson existingFilter = eq("type", "Dog"); + BsonDocument existingBsonDocument = existingFilter.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry()); + + Bson newFilter = gt("age", 5); + BsonDocument newBsonDocument = newFilter.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry()); + + existingBsonDocument.append("age", newBsonDocument.get("age")); + + FindIterable documents = collection.find(existingBsonDocument); + + MongoCursor cursor = documents.iterator(); + while (cursor.hasNext()) { + System.out.println(cursor.next()); + } + } + + public static void main(String args[]) { + + setUp(); + + addFieldToExistingBsonFilter(); + + addFieldToExistingBsonFilterUsingBsonDocument(); + } +} diff --git a/persistence-modules/java-mongodb-3/src/test/java/com/baeldung/mongo/insert/InsertFieldIntoFilterLiveTest.java b/persistence-modules/java-mongodb-3/src/test/java/com/baeldung/mongo/insert/InsertFieldIntoFilterLiveTest.java new file mode 100644 index 0000000000..be4ed260d9 --- /dev/null +++ b/persistence-modules/java-mongodb-3/src/test/java/com/baeldung/mongo/insert/InsertFieldIntoFilterLiveTest.java @@ -0,0 +1,73 @@ +package com.baeldung.mongo.insert; + +import com.baeldung.mongo.find.FindOperationLiveTest; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import org.bson.BsonDocument; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import static com.mongodb.client.model.Filters.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class InsertFieldIntoFilterLiveTest { + + private static MongoClient mongoClient; + private static MongoDatabase database; + private static MongoCollection collection; + private static final String DATASET_JSON = "/pet.json"; + + @BeforeClass + public static void setUp() throws IOException { + if (mongoClient == null) { + mongoClient = new MongoClient("localhost", 27017); + + database = mongoClient.getDatabase("baeldung"); + collection = database.getCollection("pet"); + + collection.drop(); + + InputStream is = FindOperationLiveTest.class.getResourceAsStream(DATASET_JSON); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + reader.lines() + .forEach(line -> collection.insertOne(Document.parse(line))); + reader.close(); + } + } + + @Test + public void givenPetCollection_whenFetchingAfterAddingFieldToFilter_thenFindMatchingDocuments() { + Bson existingFilter = and(eq("type", "Dog"), eq("gender", "Male")); + + Bson newFilter = and(existingFilter, gt("age", 5)); + MongoCursor cursor = collection.find(newFilter).iterator(); + + assertNotNull(cursor); + assertTrue(cursor.hasNext()); + } + + @Test + public void givenPetCollection_whenFetchingAfterAddingFieldToFilterUsingBsonDocument_thenFindMatchingDocuments() { + Bson existingFilter = eq("type", "Dog"); + BsonDocument existingBsonDocument = existingFilter.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry()); + + Bson newFilter = gt("age", 5); + BsonDocument newBsonDocument = newFilter.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry()); + + existingBsonDocument.append("age", newBsonDocument.get("age")); + MongoCursor cursor = collection.find(existingBsonDocument).iterator(); + + assertNotNull(cursor); + assertTrue(cursor.hasNext()); + } +} diff --git a/persistence-modules/java-mongodb-3/src/test/resources/pet.json b/persistence-modules/java-mongodb-3/src/test/resources/pet.json new file mode 100644 index 0000000000..b31cf16718 --- /dev/null +++ b/persistence-modules/java-mongodb-3/src/test/resources/pet.json @@ -0,0 +1,3 @@ +{"petId":"P1","name":"Tom","age":3,"type":"Cat","gender":"Female"} +{"petId":"P2","name":"Max","age":4,"type":"Dog","gender":"Male"} +{"petId":"P3","name":"Milo","age":8,"type":"Dog","gender":"Male"} \ No newline at end of file diff --git a/persistence-modules/java-mongodb/pom.xml b/persistence-modules/java-mongodb/pom.xml index 2e366d8368..844b9e5bcd 100644 --- a/persistence-modules/java-mongodb/pom.xml +++ b/persistence-modules/java-mongodb/pom.xml @@ -14,20 +14,14 @@ - - de.flapdoodle.embedmongo - de.flapdoodle.embedmongo - ${flapdoodle.version} - test - org.mongodb - mongo-java-driver + mongodb-driver-sync ${mongo.version} dev.morphia.morphia - core + morphia-core ${morphia.version} @@ -42,12 +36,18 @@ ${testcontainers.version} test + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${flapdoodle.version} + test + - 3.12.1 - 1.11 - 1.5.3 + 4.8.2 + 4.4.1 + 2.0.0 \ No newline at end of file diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoExample.java index 9af1e1f6a4..ef4003fa82 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoExample.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoExample.java @@ -1,53 +1,64 @@ package com.baeldung; -import com.mongodb.BasicDBObject; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.MongoClient; +import java.util.ArrayList; + +import org.bson.Document; + +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; public class MongoExample { public static void main(String[] args) { + try (MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017")) { - MongoClient mongoClient = new MongoClient("localhost", 27017); + MongoDatabase database = mongoClient.getDatabase("myMongoDb"); - DB database = mongoClient.getDB("myMongoDb"); + // print existing databases + mongoClient.listDatabaseNames().forEach(System.out::println); - // print existing databases - mongoClient.getDatabaseNames().forEach(System.out::println); + boolean collectionExists = mongoClient.getDatabase("myMongoDb").listCollectionNames() + .into(new ArrayList<>()).contains("customers"); + if (!collectionExists) { + database.createCollection("customers"); + } - database.createCollection("customers", null); + // print all collections in customers database + database.listCollectionNames().forEach(System.out::println); - // print all collections in customers database - database.getCollectionNames().forEach(System.out::println); + // create data + MongoCollection collection = database.getCollection("customers"); + Document document = new Document(); + document.put("name", "Shubham"); + document.put("company", "Baeldung"); + collection.insertOne(document); - // create data - DBCollection collection = database.getCollection("customers"); - BasicDBObject document = new BasicDBObject(); - document.put("name", "Shubham"); - document.put("company", "Baeldung"); - collection.insert(document); + // update data + Document query = new Document(); + query.put("name", "Shubham"); + Document newDocument = new Document(); + newDocument.put("name", "John"); + Document updateObject = new Document(); + updateObject.put("$set", newDocument); + collection.updateOne(query, updateObject); - // update data - BasicDBObject query = new BasicDBObject(); - query.put("name", "Shubham"); - BasicDBObject newDocument = new BasicDBObject(); - newDocument.put("name", "John"); - BasicDBObject updateObject = new BasicDBObject(); - updateObject.put("$set", newDocument); - collection.update(query, updateObject); + // read data + Document searchQuery = new Document(); + searchQuery.put("name", "John"); + FindIterable cursor = collection.find(searchQuery); + try (final MongoCursor cursorIterator = cursor.cursor()) { + while (cursorIterator.hasNext()) { + System.out.println(cursorIterator.next()); + } + } - // read data - BasicDBObject searchQuery = new BasicDBObject(); - searchQuery.put("name", "John"); - DBCursor cursor = collection.find(searchQuery); - while (cursor.hasNext()) { - System.out.println(cursor.next()); + // delete data + Document deleteQuery = new Document(); + deleteQuery.put("name", "John"); + collection.deleteOne(deleteQuery); } - - // delete data - BasicDBObject deleteQuery = new BasicDBObject(); - deleteQuery.put("name", "John"); - collection.remove(deleteQuery); } } diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/bsontojson/Book.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/bsontojson/Book.java index 44e4ecb539..c57f759a95 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/bsontojson/Book.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/bsontojson/Book.java @@ -1,11 +1,9 @@ package com.baeldung.bsontojson; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.HashSet; import java.util.Set; -import dev.morphia.annotations.Embedded; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Field; import dev.morphia.annotations.Id; @@ -25,7 +23,7 @@ public class Book { @Property private String title; private String author; - @Embedded + private Publisher publisher; @Property("price") private double cost; diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java index 074913af4e..c94a7c042a 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/CollectionExistence.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import org.bson.Document; -import com.mongodb.DB; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -18,7 +18,7 @@ public class CollectionExistence { public static void setUp() { if (mongoClient == null) { - mongoClient = new MongoClient("localhost", 27017); + mongoClient = MongoClients.create("mongodb://localhost:27017"); } databaseName = "baeldung"; testCollectionName = "student"; @@ -26,9 +26,9 @@ public class CollectionExistence { public static void collectionExistsSolution() { - DB db = mongoClient.getDB(databaseName); + MongoDatabase db = mongoClient.getDatabase(databaseName); - System.out.println("collectionName " + testCollectionName + db.collectionExists(testCollectionName)); + System.out.println("collectionName " + testCollectionName + db.listCollectionNames().into(new ArrayList<>()).contains(testCollectionName)); } @@ -62,7 +62,7 @@ public class CollectionExistence { MongoCollection collection = database.getCollection(testCollectionName); - System.out.println(collection.count()); + System.out.println(collection.countDocuments()); } diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java index 74279bbfcd..5ccabc9326 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java @@ -5,7 +5,8 @@ import java.util.Date; import org.bson.Document; import org.bson.types.ObjectId; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -13,7 +14,7 @@ public class RetrieveIdExample { public static void main(String[] args) { - try ( MongoClient mongoClient = new MongoClient("localhost", 27017) ) { + try ( MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017") ) { MongoDatabase database = mongoClient.getDatabase("myMongoDb"); MongoCollection collection = database.getCollection("example"); diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java index ebc56cbfd0..9ad62bc1c7 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/MultipleFieldsExample.java @@ -3,7 +3,8 @@ package com.baeldung.mongo.update; import org.bson.Document; import com.mongodb.BasicDBObject; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.result.UpdateResult; @@ -16,7 +17,7 @@ public class MultipleFieldsExample { // Connect to cluster (default is localhost:27017) // - MongoClient mongoClient = new MongoClient("localhost", 27017); + MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017"); MongoDatabase database = mongoClient.getDatabase("baeldung"); MongoCollection collection = database.getCollection("employee"); diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java index a1b051e74c..594d535245 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateFields.java @@ -2,7 +2,8 @@ package com.baeldung.mongo.update; import org.bson.Document; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; @@ -83,10 +84,9 @@ public class UpdateFields { public static void setup() { if (mongoClient == null) { - mongoClient = new MongoClient("localhost", 27017); + mongoClient = MongoClients.create("mongodb://localhost:27017"); database = mongoClient.getDatabase("baeldung"); collection = database.getCollection("student"); - } } diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java index 96dd086ed7..08fdce68d6 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/update/UpdateMultipleFields.java @@ -2,7 +2,8 @@ package com.baeldung.mongo.update; import org.bson.Document; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; @@ -16,19 +17,19 @@ public class UpdateMultipleFields { // // Connect to cluster // + try (MongoClient mongoClient = MongoClients.create("mongodb://localhost:27007");) { + MongoDatabase database = mongoClient.getDatabase("baeldung"); + MongoCollection collection = database.getCollection("employee"); - MongoClient mongoClient = new MongoClient("localhost", 27007); - MongoDatabase database = mongoClient.getDatabase("baeldung"); - MongoCollection collection = database.getCollection("employee"); + // + // Update query + // - // - // Update query - // + UpdateResult updateResult = collection.updateMany(Filters.eq("employee_id", 794875), Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); - UpdateResult updateResult = collection.updateMany(Filters.eq("employee_id", 794875), Updates.combine(Updates.set("department_id", 4), Updates.set("job", "Sales Manager"))); - - System.out.println("updateResult:- " + updateResult); - System.out.println("updateResult:- " + updateResult.getModifiedCount()); + System.out.println("updateResult:- " + updateResult); + System.out.println("updateResult:- " + updateResult.getModifiedCount()); + } } diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/morphia/domain/Book.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/morphia/domain/Book.java index 4ed2ab8580..b79550dcd1 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/morphia/domain/Book.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/morphia/domain/Book.java @@ -1,6 +1,5 @@ package com.baeldung.morphia.domain; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.HashSet; import java.util.Set; @@ -25,7 +24,7 @@ public class Book { @Property private String title; private String author; - @Embedded + private Publisher publisher; @Property("price") private double cost; diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/tagging/TagRepository.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/tagging/TagRepository.java index d27d48c743..44b5d461bc 100644 --- a/persistence-modules/java-mongodb/src/main/java/com/baeldung/tagging/TagRepository.java +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/tagging/TagRepository.java @@ -10,8 +10,9 @@ import org.bson.Document; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; -import com.mongodb.MongoClient; import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; @@ -45,7 +46,7 @@ public class TagRepository implements Closeable { * Instantiates a new TagRepository by opening the DB connection. */ public TagRepository() { - mongoClient = new MongoClient("localhost", 27018); + mongoClient = MongoClients.create("mongodb://localhost:27018"); MongoDatabase database = mongoClient.getDatabase("blog"); collection = database.getCollection("posts"); } diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/AppLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/AppLiveTest.java index 7692a37d03..2abecdbd48 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/AppLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/AppLiveTest.java @@ -2,71 +2,50 @@ package com.baeldung; import static org.junit.Assert.assertEquals; -import org.junit.After; -import org.junit.Before; +import org.bson.Document; import org.junit.Test; -import com.mongodb.BasicDBObject; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.Mongo; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; -import de.flapdoodle.embedmongo.MongoDBRuntime; -import de.flapdoodle.embedmongo.MongodExecutable; -import de.flapdoodle.embedmongo.MongodProcess; -import de.flapdoodle.embedmongo.config.MongodConfig; -import de.flapdoodle.embedmongo.distribution.Version; -import de.flapdoodle.embedmongo.runtime.Network; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.mongo.transitions.Mongod; +import de.flapdoodle.embed.mongo.transitions.RunningMongodProcess; +import de.flapdoodle.reverse.TransitionWalker; public class AppLiveTest { private static final String DB_NAME = "myMongoDb"; - private MongodExecutable mongodExe; - private MongodProcess mongod; - private Mongo mongo; - private DB db; - private DBCollection collection; - - @Before - public void setup() throws Exception { - // Creating Mongodbruntime instance - MongoDBRuntime runtime = MongoDBRuntime.getDefaultInstance(); - - // Creating MongodbExecutable - mongodExe = runtime.prepare(new MongodConfig(Version.V2_0_1, 12345, Network.localhostIsIPv6())); - - // Starting Mongodb - mongod = mongodExe.start(); - mongo = new Mongo("localhost", 12345); - - // Creating DB - db = mongo.getDB(DB_NAME); - - // Creating collection Object and adding values - collection = db.getCollection("customers"); - } - - @After - public void teardown() throws Exception { - mongod.stop(); - mongodExe.cleanup(); - } @Test public void testAddressPersistance() { - BasicDBObject contact = new BasicDBObject(); - contact.put("name", "John"); - contact.put("company", "Baeldung"); + try (TransitionWalker.ReachedState running = Mongod.instance().start(Version.V6_0_3)) { + try (MongoClient mongo = MongoClients.create("mongodb://" + running.current().getServerAddress().getHost() + ":" + running.current().getServerAddress().getPort())) { + // Creating DB + MongoDatabase db = mongo.getDatabase(DB_NAME); - // Inserting document - collection.insert(contact); - DBCursor cursorDoc = collection.find(); - BasicDBObject contact1 = new BasicDBObject(); - while (cursorDoc.hasNext()) { - contact1 = (BasicDBObject) cursorDoc.next(); - System.out.println(contact1); + // Creating collection Object and adding values + MongoCollection collection = db.getCollection("customers"); + + Document contact = new Document(); + contact.put("name", "John"); + contact.put("company", "Baeldung"); + + // Inserting document + collection.insertOne(contact); + FindIterable cursorDoc = collection.find(); + Document contact1 = new Document(); + final MongoCursor cursor = cursorDoc.cursor(); + while (cursor.hasNext()) { + contact1 = cursor.next(); + System.out.println(contact1); + } + assertEquals(contact1.get("name"), "John"); + } } - assertEquals(contact1.get("name"), "John"); } } \ No newline at end of file diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/BsonToJsonLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/BsonToJsonLiveTest.java index 0548119d7a..e2b53436b3 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/BsonToJsonLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/BsonToJsonLiveTest.java @@ -1,5 +1,6 @@ package com.baeldung.bsontojson; +import static dev.morphia.query.experimental.filters.Filters.eq; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -14,10 +15,12 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoDatabase; import dev.morphia.Datastore; +import dev.morphia.DeleteOptions; import dev.morphia.Morphia; public class BsonToJsonLiveTest { @@ -27,9 +30,8 @@ public class BsonToJsonLiveTest { @BeforeClass public static void setUp() { - Morphia morphia = new Morphia(); - morphia.mapPackage("com.baeldung.bsontojson"); - datastore = morphia.createDatastore(new MongoClient(), DB_NAME); + datastore = Morphia.createDatastore(MongoClients.create(), DB_NAME); + datastore.getMapper().mapPackage("com.baeldung.bsontojson"); datastore.ensureIndexes(); datastore.save(new Book() @@ -44,25 +46,33 @@ public class BsonToJsonLiveTest { @AfterClass public static void tearDown() { - datastore.delete(datastore.createQuery(Book.class)); + datastore.find(Book.class) + .filter(eq("isbn", "isbn")) + .filter(eq("title", "title")) + .filter(eq("author", "author")) + .filter(eq("cost", "3.95")) + .delete(new DeleteOptions().multi(true)); } @Test public void givenBsonDocument_whenUsingStandardJsonTransformation_thenJsonDateIsObjectEpochTime() { String json; - try (MongoClient mongoClient = new MongoClient()) { + try (MongoClient mongoClient = MongoClients.create()) { MongoDatabase mongoDatabase = mongoClient.getDatabase(DB_NAME); Document bson = mongoDatabase.getCollection("Books").find().first(); - json = bson.toJson(); + json = bson.toJson(JsonWriterSettings + .builder() + .dateTimeConverter(new JSONDateFormatEpochTimeConverter()) + .build()); } String expectedJson = "{\"_id\": \"isbn\", " + - "\"className\": \"com.baeldung.bsontojson.Book\", " + + "\"_t\": \"Book\", " + "\"title\": \"title\", " + "\"author\": \"author\", " + "\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " + - "\"name\": \"publisher\"}, " + + "\"_t\": \"Publisher\", \"name\": \"publisher\"}, " + "\"price\": 3.95, " + "\"publishDate\": {\"$date\": 1577898812000}}"; @@ -71,12 +81,11 @@ public class BsonToJsonLiveTest { assertEquals(expectedJson, json); } - @Test public void givenBsonDocument_whenUsingRelaxedJsonTransformation_thenJsonDateIsObjectIsoDate() { String json; - try (MongoClient mongoClient = new MongoClient()) { + try (MongoClient mongoClient = MongoClients.create()) { MongoDatabase mongoDatabase = mongoClient.getDatabase(DB_NAME); Document bson = mongoDatabase.getCollection("Books").find().first(); json = bson.toJson(JsonWriterSettings @@ -86,11 +95,11 @@ public class BsonToJsonLiveTest { } String expectedJson = "{\"_id\": \"isbn\", " + - "\"className\": \"com.baeldung.bsontojson.Book\", " + + "\"_t\": \"Book\", " + "\"title\": \"title\", " + "\"author\": \"author\", " + "\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " + - "\"name\": \"publisher\"}, " + + "\"_t\": \"Publisher\", \"name\": \"publisher\"}, " + "\"price\": 3.95, " + "\"publishDate\": {\"$date\": \"2020-01-01T17:13:32Z\"}}"; @@ -103,7 +112,7 @@ public class BsonToJsonLiveTest { public void givenBsonDocument_whenUsingCustomJsonTransformation_thenJsonDateIsStringField() { String json; - try (MongoClient mongoClient = new MongoClient()) { + try (MongoClient mongoClient = MongoClients.create()) { MongoDatabase mongoDatabase = mongoClient.getDatabase(DB_NAME); Document bson = mongoDatabase.getCollection("Books").find().first(); json = bson.toJson(JsonWriterSettings @@ -113,11 +122,11 @@ public class BsonToJsonLiveTest { } String expectedJson = "{\"_id\": \"isbn\", " + - "\"className\": \"com.baeldung.bsontojson.Book\", " + + "\"_t\": \"Book\", " + "\"title\": \"title\", " + "\"author\": \"author\", " + "\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " + - "\"name\": \"publisher\"}, " + + "\"_t\": \"Publisher\", \"name\": \"publisher\"}, " + "\"price\": 3.95, " + "\"publishDate\": \"2020-01-01T17:13:32Z\"}"; diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/JSONDateFormatEpochTimeConverter.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/JSONDateFormatEpochTimeConverter.java new file mode 100644 index 0000000000..7f3a4f936f --- /dev/null +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/bsontojson/JSONDateFormatEpochTimeConverter.java @@ -0,0 +1,18 @@ +package com.baeldung.bsontojson; + +import org.bson.json.Converter; +import org.bson.json.StrictJsonWriter; + +/** + * Convertor to epoch time + */ +public class JSONDateFormatEpochTimeConverter implements Converter { + + @Override + public void convert(Long value, StrictJsonWriter writer) { + writer.writeStartObject(); + writer.writeName("$date"); + writer.writeNumber(String.valueOf(value)); + writer.writeEndObject(); + } +} diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java index ad839d1219..5be97bcb25 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/mongo/CollectionExistenceLiveTest.java @@ -8,8 +8,8 @@ import org.bson.Document; import org.junit.Before; import org.junit.Test; -import com.mongodb.DB; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -22,7 +22,7 @@ public class CollectionExistenceLiveTest { @Before public void setup() { if (mongoClient == null) { - mongoClient = new MongoClient("localhost", 27017); + mongoClient = MongoClients.create("mongodb://localhost:27017"); databaseName = "baeldung"; testCollectionName = "student"; @@ -58,28 +58,16 @@ public class CollectionExistenceLiveTest { } - @Test - public void givenCollectionExists_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { - - DB db = mongoClient.getDB(databaseName); - Boolean collectionStatus = db.collectionExists(testCollectionName); - - Boolean expectedStatus = true; - assertEquals(expectedStatus, collectionStatus); - - } - @Test public void givenListCollectionNames_whenCollectionAlreadyExists_thenCheckingForCollectionExistence() { MongoDatabase database = mongoClient.getDatabase(databaseName); boolean collectionExists = database.listCollectionNames() - .into(new ArrayList()) + .into(new ArrayList<>()) .contains(testCollectionName); Boolean expectedStatus = true; assertEquals(expectedStatus, collectionExists); - } @Test @@ -88,7 +76,7 @@ public class CollectionExistenceLiveTest { MongoDatabase database = mongoClient.getDatabase(databaseName); MongoCollection collection = database.getCollection(testCollectionName); - Boolean collectionExists = collection.count() > 0 ? true : false; + Boolean collectionExists = collection.countDocuments() > 0 ? true : false; Boolean expectedStatus = false; assertEquals(expectedStatus, collectionExists); diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/morphia/MorphiaIntegrationTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/morphia/MorphiaIntegrationTest.java index f508c5f525..d702c691d6 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/morphia/MorphiaIntegrationTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/morphia/MorphiaIntegrationTest.java @@ -2,39 +2,44 @@ package com.baeldung.morphia; import static dev.morphia.aggregation.Group.grouping; import static dev.morphia.aggregation.Group.push; +import static dev.morphia.query.experimental.filters.Filters.eq; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.bson.types.ObjectId; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import com.baeldung.morphia.domain.Author; import com.baeldung.morphia.domain.Book; import com.baeldung.morphia.domain.Publisher; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.model.ReturnDocument; import dev.morphia.Datastore; +import dev.morphia.DeleteOptions; +import dev.morphia.ModifyOptions; import dev.morphia.Morphia; +import dev.morphia.query.FindOptions; import dev.morphia.query.Query; -import dev.morphia.query.UpdateOperations; +import dev.morphia.query.experimental.updates.UpdateOperators; -@Ignore public class MorphiaIntegrationTest { private static Datastore datastore; private static ObjectId id = new ObjectId(); - @BeforeClass + @BeforeClass public static void setUp() { - Morphia morphia = new Morphia(); - morphia.mapPackage("com.baeldung.morphia"); - datastore = morphia.createDatastore(new MongoClient(), "library"); + datastore = Morphia.createDatastore(MongoClients.create(), "library"); + datastore.getMapper().mapPackage("com.baeldung.morphia"); datastore.ensureIndexes(); } @@ -47,11 +52,11 @@ public class MorphiaIntegrationTest { datastore.save(companionBook); datastore.save(book); - List books = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java") - .find() - .toList(); + Query booksQuery = datastore.find(Book.class) + .filter(eq("title", "Learning Java")); + List books = StreamSupport + .stream(booksQuery.spliterator(), true) + .collect(Collectors.toList()); assertEquals(1, books.size()); assertEquals(book, books.get(0)); } @@ -61,19 +66,13 @@ public class MorphiaIntegrationTest { Publisher publisher = new Publisher(id, "Awsome Publisher"); Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher); datastore.save(book); - Query query = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java"); - UpdateOperations updates = datastore.createUpdateOperations(Book.class) - .inc("price", 1); - datastore.update(query, updates); - List books = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java") - .find() - .toList(); - assertEquals(4.95, books.get(0) - .getCost()); + + final Book execute = datastore.find(Book.class) + .filter(eq("title", "Learning Java")) + .modify(UpdateOperators.set("price", 4.95)) + .execute(new ModifyOptions().returnDocument(ReturnDocument.AFTER)); + + assertEquals(4.95, execute.getCost()); } @Test @@ -81,16 +80,12 @@ public class MorphiaIntegrationTest { Publisher publisher = new Publisher(id, "Awsome Publisher"); Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher); datastore.save(book); - Query query = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java"); - datastore.delete(query); - List books = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java") - .find() - .toList(); - assertEquals(0, books.size()); + datastore.find(Book.class) + .filter(eq("title", "Learning Java")) + .delete(new DeleteOptions().multi(true)); + Query books = datastore.find(Book.class) + .filter(eq("title", "Learning Java")); + assertFalse(books.iterator().hasNext()); } @Test @@ -107,7 +102,6 @@ public class MorphiaIntegrationTest { .out(Author.class); assertTrue(authors.hasNext()); - } @Test @@ -115,17 +109,12 @@ public class MorphiaIntegrationTest { Publisher publisher = new Publisher(id, "Awsome Publisher"); Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher); datastore.save(book); - List books = datastore.createQuery(Book.class) - .field("title") - .contains("Learning Java") - .project("title", true) - .find() - .toList(); - assertEquals(books.size(), 1); - assertEquals("Learning Java", books.get(0) - .getTitle()); - assertNull(books.get(0) - .getAuthor()); + List books = datastore.find(Book.class) + .filter(eq("title", "Learning Java")) + .iterator(new FindOptions().projection().include("title")).toList(); + assertEquals( 1, books.size()); + assertEquals("Learning Java", books.get(0).getTitle()); + assertNull(books.get(0).getAuthor()); } } diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/tagging/TaggingLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/tagging/TaggingLiveTest.java index edd8e22775..2a7afbd753 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/tagging/TaggingLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/tagging/TaggingLiveTest.java @@ -100,9 +100,7 @@ public class TaggingLiveTest { results.forEach(System.out::println); Assert.assertEquals(1, results.size()); - results.forEach(post -> { - Assert.assertFalse(post.getTags().contains("MongoDB")); - }); + results.forEach(post -> Assert.assertFalse(post.getTags().contains("MongoDB"))); } /** diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java index 47114e1f1a..ef725a9435 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateFieldLiveTest.java @@ -8,7 +8,8 @@ import org.bson.Document; import org.junit.BeforeClass; import org.junit.Test; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; @@ -27,7 +28,7 @@ public class UpdateFieldLiveTest { @BeforeClass public static void setup() { if (mongoClient == null) { - mongoClient = new MongoClient("localhost", 27017); + mongoClient = MongoClients.create("mongodb://localhost:27017"); db = mongoClient.getDatabase("baeldung"); collection = db.getCollection("student"); diff --git a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java index d06de23423..19edda5870 100644 --- a/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java +++ b/persistence-modules/java-mongodb/src/test/java/com/baeldung/update/UpdateMultipleFieldsLiveTest.java @@ -8,7 +8,8 @@ import org.junit.Before; import org.junit.Test; import com.mongodb.BasicDBObject; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; @@ -23,7 +24,7 @@ public class UpdateMultipleFieldsLiveTest { @Before public void setup() { if (mongoClient == null) { - mongoClient = new MongoClient("localhost", 27017); + mongoClient = MongoClients.create("mongodb://localhost:27017"); db = mongoClient.getDatabase("baeldung"); collection = db.getCollection("employee"); diff --git a/persistence-modules/jpa-hibernate-cascade-type/src/test/java/com/baeldung/cascading/CasCadeTypeUnitTest.java b/persistence-modules/jpa-hibernate-cascade-type/src/test/java/com/baeldung/cascading/CasCadeTypeUnitTest.java index a196bdac12..88cc920a92 100644 --- a/persistence-modules/jpa-hibernate-cascade-type/src/test/java/com/baeldung/cascading/CasCadeTypeUnitTest.java +++ b/persistence-modules/jpa-hibernate-cascade-type/src/test/java/com/baeldung/cascading/CasCadeTypeUnitTest.java @@ -34,7 +34,7 @@ public class CasCadeTypeUnitTest { } @Test - public void testPersist() { + public void whenParentSavedThenChildSaved() { Person person = new Person(); Address address = new Address(); address.setPerson(person); @@ -45,7 +45,7 @@ public class CasCadeTypeUnitTest { } @Test - public void testMerge() { + public void whenParentSavedThenMerged() { int addressId; Person person = buildPerson("devender"); Address address = buildAddress(person); @@ -64,7 +64,7 @@ public class CasCadeTypeUnitTest { } @Test - public void testRemove() { + public void whenParentRemovedThenChildRemoved() { int personId; Person person = buildPerson("devender"); Address address = buildAddress(person); @@ -80,12 +80,13 @@ public class CasCadeTypeUnitTest { } @Test - public void testDetach() { + public void whenParentDetachedThenChildDetached() { Person person = buildPerson("devender"); Address address = buildAddress(person); person.setAddresses(Arrays.asList(address)); session.persist(person); session.flush(); + Assertions.assertThat(session.contains(person)).isTrue(); Assertions.assertThat(session.contains(address)).isTrue(); @@ -95,12 +96,13 @@ public class CasCadeTypeUnitTest { } @Test - public void testLock() { + public void whenDetachedAndLockedThenBothReattached() { Person person = buildPerson("devender"); Address address = buildAddress(person); person.setAddresses(Arrays.asList(address)); session.persist(person); session.flush(); + Assertions.assertThat(session.contains(person)).isTrue(); Assertions.assertThat(session.contains(address)).isTrue(); @@ -116,7 +118,7 @@ public class CasCadeTypeUnitTest { } @Test - public void testRefresh() { + public void whenParentRefreshedThenChildRefreshed() { Person person = buildPerson("devender"); Address address = buildAddress(person); person.setAddresses(Arrays.asList(address)); @@ -125,12 +127,13 @@ public class CasCadeTypeUnitTest { person.setName("Devender Kumar"); address.setHouseNumber(24); session.refresh(person); + Assertions.assertThat(person.getName()).isEqualTo("devender"); Assertions.assertThat(address.getHouseNumber()).isEqualTo(23); } @Test - public void testReplicate() { + public void whenParentReplicatedThenChildReplicated() { Person person = buildPerson("devender"); person.setId(2); Address address = buildAddress(person); diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index bff23cffc1..9606da4594 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -18,6 +18,7 @@ apache-bookkeeper apache-cayenne apache-derby + blaze-persistence core-java-persistence core-java-persistence-2 deltaspike @@ -42,7 +43,8 @@ java-jpa java-jpa-2 java-jpa-3 - java-mongodb + + java-mongodb-2 java-mongodb-3 java-mongodb-queries @@ -59,6 +61,7 @@ solr spring-boot-persistence-2 + spring-boot-persistence-3 spring-boot-mysql spring-boot-persistence spring-boot-persistence-h2 @@ -74,7 +77,8 @@ spring-data-dynamodb spring-data-eclipselink spring-data-elasticsearch - + + spring-data-geode spring-data-jpa-annotations spring-data-jpa-crud @@ -116,4 +120,4 @@ 1.16.3 - + \ No newline at end of file diff --git a/persistence-modules/read-only-transactions/pom.xml b/persistence-modules/read-only-transactions/pom.xml index 39621bfe26..9a347fde88 100644 --- a/persistence-modules/read-only-transactions/pom.xml +++ b/persistence-modules/read-only-transactions/pom.xml @@ -73,7 +73,7 @@ 2.6.1 5.3.13 5.8.2 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/read-only-transactions/src/main/java/com/baeldung/readonlytransactions/h2/Config.java b/persistence-modules/read-only-transactions/src/main/java/com/baeldung/readonlytransactions/h2/Config.java index 241dad417b..2e661a9651 100644 --- a/persistence-modules/read-only-transactions/src/main/java/com/baeldung/readonlytransactions/h2/Config.java +++ b/persistence-modules/read-only-transactions/src/main/java/com/baeldung/readonlytransactions/h2/Config.java @@ -20,7 +20,7 @@ public class Config { @Bean("h2DataSource") public DataSource dataSource() { HikariConfig config = new HikariConfig(); - config.setJdbcUrl("jdbc:h2:mem:mydb"); + config.setJdbcUrl("jdbc:h2:mem:mydb;MODE=LEGACY"); config.setUsername("sa"); config.setPassword(""); config.setDriverClassName("org.h2.Driver"); diff --git a/persistence-modules/rethinkdb/README.md b/persistence-modules/rethinkdb/README.md new file mode 100644 index 0000000000..e8cf1415e7 --- /dev/null +++ b/persistence-modules/rethinkdb/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Getting Started With RethinkDB](https://www.baeldung.com/rethinkdb) diff --git a/patterns-modules/hexagonal-architecture/pom.xml b/persistence-modules/rethinkdb/pom.xml similarity index 66% rename from patterns-modules/hexagonal-architecture/pom.xml rename to persistence-modules/rethinkdb/pom.xml index b18bd49aec..17c7036ed3 100644 --- a/patterns-modules/hexagonal-architecture/pom.xml +++ b/persistence-modules/rethinkdb/pom.xml @@ -3,11 +3,9 @@ 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 - hexagonal-architecture - 1.0 - hexagonal-architecture - Project for hexagonal architecture in java + rethinkdb + rethinkdb + Code snippets for RethinkDB articles com.baeldung @@ -21,20 +19,21 @@ org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-data-mongodb - org.springframework.boot spring-boot-starter-test test - - - org.junit.vintage - junit-vintage-engine - - + + + com.rethinkdb + rethinkdb-driver + 2.4.4 + + + + org.projectlombok + lombok + provided @@ -47,4 +46,8 @@ - \ No newline at end of file + + 17 + + + diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java new file mode 100644 index 0000000000..244959d854 --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java @@ -0,0 +1,62 @@ +package com.baeldung.rethinkdb; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static com.rethinkdb.RethinkDB.r; + +/** + * Some tests demonstrating inserting data. + */ +public class InsertIntegrationTest extends TestBase { + /** + * Create a table for the tests. + */ + @BeforeEach + public void createTable() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + } + + /** + * Insert a single simple record into the database. + */ + @Test + public void insertSimpleRecord() { + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("name", "Baeldung") + ) + .run(conn); + } + + @Test + public void insertMap() { + r.db(DB_NAME).table(tableName) + .insert( + Map.of("name", "Baeldung") + ) + .run(conn); + } + + @Test + public void insertComplex() { + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("name", "Baeldung") + .with("articles", r.array( + r.hashMap() + .with("name", "String Interpolation in Java") + .with("url", "https://www.baeldung.com/java-string-interpolation"), + r.hashMap() + .with("name", "Access HTTPS REST Service Using Spring RestTemplate") + .with("url", "https://www.baeldung.com/spring-resttemplate-secure-https-service") + ) + ) + ) + .run(conn); + } +} diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java new file mode 100644 index 0000000000..263dda9bc6 --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java @@ -0,0 +1,81 @@ +package com.baeldung.rethinkdb; + +import com.rethinkdb.net.Result; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.rethinkdb.RethinkDB.r; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Some tests demonstrating querying data. + */ +public class QueryIntegrationTest extends TestBase { + /** + * Create a table for the tests. + */ + @BeforeEach + public void createTable() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("id", "article1") + .with("name", "String Interpolation in Java") + .with("url", "https://www.baeldung.com/java-string-interpolation") + ).run(conn); + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("id", "article2") + .with("name", "Access HTTPS REST Service Using Spring RestTemplate") + .with("url", "https://www.baeldung.com/spring-resttemplate-secure-https-service") + ).run(conn); + } + + @Test + public void listAll() { + Result results = r.db(DB_NAME).table(tableName).run(conn, Map.class); + + // We can't ensure the order the results come back in. + Set expected = new HashSet<>(Set.of( + "String Interpolation in Java", + "Access HTTPS REST Service Using Spring RestTemplate" + )); + + for (Map result : results) { + assertTrue(expected.remove(result.get("name"))); + } + + assertTrue(expected.isEmpty()); + } + + @Test + public void listSome() { + Result results = r.db(DB_NAME) + .table(tableName) + .filter(r -> r.g("name").eq("String Interpolation in Java")) + .run(conn, Map.class); + + // We can't ensure the order the results come back in. + Set expected = Set.of("https://www.baeldung.com/java-string-interpolation"); + + assertEquals(expected, results.stream() + .map(r -> r.get("url")) + .collect(Collectors.toSet())); + } + + @Test + public void getByKey() { + Result results = r.db(DB_NAME).table(tableName).get("article1").run(conn, Map.class); + + assertEquals("String Interpolation in Java", results.first().get("name")); + } +} diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java new file mode 100644 index 0000000000..4ca147cf68 --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java @@ -0,0 +1,117 @@ +package com.baeldung.rethinkdb; + +import com.rethinkdb.net.Result; +import org.junit.jupiter.api.Test; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static com.rethinkdb.RethinkDB.r; + +/** + * Some tests demonstrating streaming live changes to data. + */ +public class StreamingIntegrationTest extends TestBase { + @Test + public void getLiveInserts() throws InterruptedException { + ExecutorService executorService = Executors.newCachedThreadPool(); + + r.db(DB_NAME).tableCreate(tableName).run(conn); + + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", 0)).run(conn); + + executorService.submit(() -> { + Result cursor = r.db(DB_NAME).table(tableName).changes().run(conn, Map.class); + + cursor.stream().forEach(record -> System.out.println("Record: " + record)); + }); + + for (int i = 0; i < 10; ++i) { + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", i)).run(conn); + TimeUnit.MILLISECONDS.sleep(100); + } + + executorService.shutdownNow(); + } + + @Test + public void getSomeLiveInserts() throws InterruptedException { + ExecutorService executorService = Executors.newCachedThreadPool(); + + r.db(DB_NAME).tableCreate(tableName).run(conn); + + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", 0)).run(conn); + + executorService.submit(() -> { + Result cursor = r.db(DB_NAME).table(tableName) + .filter(r -> r.g("index").eq(5)) + .changes() + .run(conn, Map.class); + + cursor.stream().forEach(record -> System.out.println("Record: " + record)); + }); + + for (int i = 0; i < 10; ++i) { + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", i)).run(conn); + TimeUnit.MILLISECONDS.sleep(100); + } + + executorService.shutdownNow(); + } + + @Test + public void getLiveUpdates() throws InterruptedException { + ExecutorService executorService = Executors.newCachedThreadPool(); + + r.db(DB_NAME).tableCreate(tableName).run(conn); + + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", 0)).run(conn); + + executorService.submit(() -> { + Result cursor = r.db(DB_NAME).table(tableName).changes().run(conn, Map.class); + + cursor.stream().forEach(record -> System.out.println("Record: " + record)); + }); + + for (int i = 0; i < 10; ++i) { + r.db(DB_NAME).table(tableName).update(r.hashMap().with("index", i)).run(conn); + TimeUnit.MILLISECONDS.sleep(100); + } + + executorService.shutdownNow(); + } + + @Test + public void getLiveDeletes() throws InterruptedException { + ExecutorService executorService = Executors.newCachedThreadPool(); + + r.db(DB_NAME).tableCreate(tableName).run(conn); + + for (int i = 0; i < 10; ++i) { + r.db(DB_NAME).table(tableName).insert(r.hashMap().with("index", i)).run(conn); + } + + executorService.submit(() -> { + Result cursor = r.db(DB_NAME).table(tableName).changes().run(conn, Map.class); + + cursor.stream().forEach(record -> System.out.println("Record: " + record)); + }); + + r.db(DB_NAME).table(tableName) + .filter(r -> r.g("index").eq(1)) + .delete() + .run(conn); + r.db(DB_NAME).table(tableName) + .filter(r -> r.g("index").eq(3)) + .delete() + .run(conn); + r.db(DB_NAME).table(tableName) + .filter(r -> r.g("index").eq(5)) + .delete() + .run(conn); + + executorService.shutdownNow(); + } +} diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java new file mode 100644 index 0000000000..d60e500373 --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.rethinkdb; + +import com.rethinkdb.gen.exc.ReqlOpFailedError; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static com.rethinkdb.RethinkDB.r; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Some tests demonstrating working with tables. + */ +public class TablesIntegrationTest extends TestBase { + + @Test + public void createTable() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + } + + @Test + public void createTableTwice() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + + Assertions.assertThrows(ReqlOpFailedError.class, () -> { + r.db(DB_NAME).tableCreate(tableName).run(conn); + }); + } + + @Test + public void listTables() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + + List tables = r.db(DB_NAME).tableList().run(conn, List.class).first(); + + assertTrue(tables.contains(tableName)); + } +} diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TestBase.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TestBase.java new file mode 100644 index 0000000000..396f6655ea --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TestBase.java @@ -0,0 +1,44 @@ +package com.baeldung.rethinkdb; + +import com.rethinkdb.net.Connection; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import java.util.UUID; + +import static com.rethinkdb.RethinkDB.r; + +/** + * Base class for RethinkDB tests. + */ +public class TestBase { + /** The database name to work with */ + protected static final String DB_NAME = "test"; + + /** A randomly generated table name so they never collide */ + protected final String tableName = UUID.randomUUID().toString().replaceAll("-",""); + + /** A database connection */ + protected Connection conn; + + /** + * Connect to the database for each test + */ + @BeforeEach + public void connect() { + conn = r.connection() + .hostname("localhost") + .port(28015) + .connect(); + } + + /** + * Disconnect from the database after each test + */ + @AfterEach + public void disconnect() { + if (this.conn != null) { + conn.close(); + } + } +} diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java new file mode 100644 index 0000000000..39fad3a878 --- /dev/null +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java @@ -0,0 +1,55 @@ +package com.baeldung.rethinkdb; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static com.rethinkdb.RethinkDB.r; + +/** + * Some tests demonstrating updating data. + */ +public class UpdateIntegrationTest extends TestBase { + /** + * Create a table for the tests. + */ + @BeforeEach + public void createTable() { + r.db(DB_NAME).tableCreate(tableName).run(conn); + + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("id", "article1") + .with("name", "String Interpolation in Java") + .with("url", "https://www.baeldung.com/java-string-interpolation") + ).run(conn); + r.db(DB_NAME).table(tableName) + .insert( + r.hashMap() + .with("id", "article2") + .with("name", "Access HTTPS REST Service Using Spring RestTemplate") + .with("url", "https://www.baeldung.com/spring-resttemplate-secure-https-service") + ).run(conn); + } + + @Test + public void updateAll() { + r.db(DB_NAME).table(tableName).update(r.hashMap().with("site", "Baeldung")).run(conn); + } + + @Test + public void updateSome() { + r.db(DB_NAME).table(tableName) + .filter(r -> r.g("name").eq("String Interpolation in Java")) + .update(r.hashMap().with("category", "java")) + .run(conn); + } + + @Test + public void delete() { + r.db(DB_NAME).table(tableName) + .filter(r -> r.g("name").eq("String Interpolation in Java")) + .delete() + .run(conn); + } +} diff --git a/persistence-modules/scylladb/README.md b/persistence-modules/scylladb/README.md new file mode 100644 index 0000000000..b845051972 --- /dev/null +++ b/persistence-modules/scylladb/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to ScyllaDB with Java](https://www.baeldung.com/java-scylladb) diff --git a/persistence-modules/scylladb/pom.xml b/persistence-modules/scylladb/pom.xml new file mode 100644 index 0000000000..e457c75d91 --- /dev/null +++ b/persistence-modules/scylladb/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + com.baeldung.examples.scylladb + scylladb + 0.0.1-SNAPSHOT + scylladb + Sample ScyllaDB Project + + 1.17.6 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + org.springframework.boot + spring-boot-starter + + + com.scylladb + java-driver-core + 4.14.1.0 + + + com.scylladb + java-driver-query-builder + 4.14.1.0 + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.testcontainers + testcontainers + test + + + org.testcontainers + junit-jupiter + test + + + + + + org.testcontainers + testcontainers-bom + ${testcontainers.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/ScylladbApplication.java b/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/ScylladbApplication.java new file mode 100644 index 0000000000..3e6cea7ed2 --- /dev/null +++ b/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/ScylladbApplication.java @@ -0,0 +1,89 @@ +package com.baeldung.scylladb; + +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.insertInto; +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal; +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; +import static com.datastax.oss.driver.api.querybuilder.SchemaBuilder.createKeyspace; +import static com.datastax.oss.driver.api.querybuilder.SchemaBuilder.createTable; + +import java.util.ArrayList; +import java.util.List; + +import com.baeldung.scylladb.model.User; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.ResultSet; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.querybuilder.insert.InsertInto; +import com.datastax.oss.driver.api.querybuilder.schema.CreateKeyspaceStart; +import com.datastax.oss.driver.api.querybuilder.schema.CreateTableStart; +import com.datastax.oss.driver.api.querybuilder.select.Select; + +public class ScylladbApplication { + + private String keySpaceName; + private String tableName; + + public ScylladbApplication(String keySpaceName, String tableName) { + this.keySpaceName = keySpaceName; + this.tableName = tableName; + CreateKeyspaceStart createKeyspace = createKeyspace(keySpaceName); + SimpleStatement keypaceStatement = createKeyspace.ifNotExists() + .withSimpleStrategy(3) + .build(); + + CreateTableStart createTable = createTable(keySpaceName, tableName); + SimpleStatement tableStatement = createTable.ifNotExists() + .withPartitionKey("id", DataTypes.BIGINT) + .withColumn("name", DataTypes.TEXT) + .build(); + + try (CqlSession session = CqlSession.builder().build()) { + ResultSet rs = session.execute(keypaceStatement); + if (null == rs.getExecutionInfo().getErrors() || rs.getExecutionInfo().getErrors().isEmpty()) { + rs = session.execute(tableStatement); + } + } + } + + public List getAllUserNames() { + List userNames = new ArrayList<>(); + try (CqlSession session = CqlSession.builder().build()) { + String query = String.format("select * from %s.%s",keySpaceName,tableName); + ResultSet rs = session.execute(query); + for (Row r : rs.all()) + userNames.add(r.getString("name")); + } + return userNames; + } + + public List getUsersByUserName(String userName) { + List userList = new ArrayList<>(); + try (CqlSession session = CqlSession.builder().build()) { + Select query = selectFrom(keySpaceName, tableName).all() + .whereColumn("name") + .isEqualTo(literal(userName)) + .allowFiltering(); + SimpleStatement statement = query.build(); + ResultSet rs = session.execute(statement); + for (Row r : rs) + userList.add(new User(r.getLong("id"), r.getString("name"))); + } + return userList; + } + + public boolean addNewUser(User user) { + boolean response = false; + try (CqlSession session = CqlSession.builder().build()) { + InsertInto insert = insertInto(keySpaceName, tableName); + SimpleStatement statement = insert.value("id", literal(user.getId())) + .value("name", literal(user.getName())) + .build(); + ResultSet rs = session.execute(statement); + response = null == rs.getExecutionInfo().getErrors() || rs.getExecutionInfo().getErrors().isEmpty(); + } + return response; + } + +} diff --git a/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/model/User.java b/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/model/User.java new file mode 100644 index 0000000000..28d60112b9 --- /dev/null +++ b/persistence-modules/scylladb/src/main/java/com/baeldung/scylladb/model/User.java @@ -0,0 +1,17 @@ +package com.baeldung.scylladb.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class User { + + private long id; + + private String name; +} diff --git a/persistence-modules/scylladb/src/main/resources/application.yml b/persistence-modules/scylladb/src/main/resources/application.yml new file mode 100644 index 0000000000..3a4abad3dd --- /dev/null +++ b/persistence-modules/scylladb/src/main/resources/application.yml @@ -0,0 +1,3 @@ +datastax-java-driver: + basic: + contact-points: 127.0.0.1:9042 \ No newline at end of file diff --git a/persistence-modules/scylladb/src/test/java/com/baeldung/scylladb/ScyllaDBApplicationLiveTest.java b/persistence-modules/scylladb/src/test/java/com/baeldung/scylladb/ScyllaDBApplicationLiveTest.java new file mode 100644 index 0000000000..4e3cb00a41 --- /dev/null +++ b/persistence-modules/scylladb/src/test/java/com/baeldung/scylladb/ScyllaDBApplicationLiveTest.java @@ -0,0 +1,68 @@ +package com.baeldung.scylladb; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.function.Consumer; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.scylladb.model.User; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; + +@Testcontainers +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ScyllaDBApplicationLiveTest { + + private static final String IMAGE_NAME = "scylladb/scylla"; + private static final int hostPort = 9042; + private static final int containerExposedPort = 9042; + private static Consumer cmd = e -> e.withPortBindings(new PortBinding(Ports.Binding.bindPort(hostPort), + new ExposedPort(containerExposedPort))); + + @Container + private static final GenericContainer scyllaDbContainer = new GenericContainer(DockerImageName.parse(IMAGE_NAME)) + .withExposedPorts(containerExposedPort) + .withCreateContainerCmdModifier(cmd); + + private ScylladbApplication scylladbApplication; + + @BeforeAll + void setUp() { + scylladbApplication = new ScylladbApplication("baeldung", "User"); + } + + @Test + public void givenKeySpaceAndTable_whenInsertData_thenShouldBeAbleToFindData() { + User user = new User(10, "John"); + scylladbApplication.addNewUser(user); + + List userList = scylladbApplication.getUsersByUserName("John"); + assertEquals(1, userList.size()); + assertEquals("John", userList.get(0).getName()); + assertEquals(10, userList.get(0).getId()); + + } + + @Test + public void givenKeySpaceAndTable_whenInsertData_thenRowCountIncreases() { + int initialCount = scylladbApplication.getAllUserNames().size(); + User user = new User(11, "Doe"); + scylladbApplication.addNewUser(user); + + int expectedCount = initialCount+1; + int updatedCount = scylladbApplication.getAllUserNames().size(); + assertEquals(expectedCount, updatedCount); + + } + +} diff --git a/persistence-modules/scylladb/src/test/resources/application.yml b/persistence-modules/scylladb/src/test/resources/application.yml new file mode 100644 index 0000000000..3a4abad3dd --- /dev/null +++ b/persistence-modules/scylladb/src/test/resources/application.yml @@ -0,0 +1,3 @@ +datastax-java-driver: + basic: + contact-points: 127.0.0.1:9042 \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml index efb988d0a0..b9a47aa703 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml +++ b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml @@ -24,6 +24,11 @@ org.springframework.boot spring-boot-starter-data-mongodb + + org.mongodb + mongodb-crypt + ${mongodb-crypt.version} + de.flapdoodle.embed de.flapdoodle.embed.mongo @@ -31,4 +36,8 @@ + + 1.6.1 + + diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/MongoDbCsfleApplication.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/MongoDbCsfleApplication.java new file mode 100644 index 0000000000..fac296a208 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/MongoDbCsfleApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.csfle; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MongoDbCsfleApplication { + + public static void main(String... args) { + SpringApplication.run(MongoDbCsfleApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java new file mode 100644 index 0000000000..0ff97eb6c1 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java @@ -0,0 +1,47 @@ +package com.baeldung.boot.csfle.config; + +import org.bson.BsonBinary; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EncryptionConfig { + + @Value("${com.baeldung.csfle.master-key-path}") + private String masterKeyPath; + + @Value("${com.baeldung.csfle.key-vault.namespace}") + private String keyVaultNamespace; + + @Value("${com.baeldung.csfle.key-vault.alias}") + private String keyVaultAlias; + + @Value("${com.baeldung.csfle.auto-decryption:false}") + private Boolean autoDecryption; + + private BsonBinary dataKeyId; + + public void setDataKeyId(BsonBinary dataKeyId) { + this.dataKeyId = dataKeyId; + } + + public BsonBinary getDataKeyId() { + return dataKeyId; + } + + public String getKeyVaultNamespace() { + return keyVaultNamespace; + } + + public String getKeyVaultAlias() { + return keyVaultAlias; + } + + public String getMasterKeyPath() { + return masterKeyPath; + } + + public Boolean getAutoDecryption() { + return autoDecryption; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/LocalKmsUtils.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/LocalKmsUtils.java new file mode 100644 index 0000000000..e5daf781f0 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/LocalKmsUtils.java @@ -0,0 +1,55 @@ +package com.baeldung.boot.csfle.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +public class LocalKmsUtils { + + private static final int KEY_SIZE = 96; + + private LocalKmsUtils() { + } + + public static byte[] createMasterKey(String path) throws FileNotFoundException, IOException { + byte[] masterKey = new byte[KEY_SIZE]; + new SecureRandom().nextBytes(masterKey); + + try (FileOutputStream stream = new FileOutputStream(path)) { + stream.write(masterKey); + } + + return masterKey; + } + + public static byte[] readMasterKey(String path) throws FileNotFoundException, IOException { + byte[] masterKey = new byte[KEY_SIZE]; + + try (FileInputStream stream = new FileInputStream(path)) { + stream.read(masterKey, 0, KEY_SIZE); + } + + return masterKey; + } + + public static Map> providersMap(String masterKeyPath) throws FileNotFoundException, IOException { + if (masterKeyPath == null) + throw new IllegalArgumentException("master key path cannot be null"); + + File masterKeyFile = new File(masterKeyPath); + byte[] masterKey = masterKeyFile.isFile() + ? readMasterKey(masterKeyPath) + : createMasterKey(masterKeyPath); + + Map masterKeyMap = new HashMap<>(); + masterKeyMap.put("key", masterKey); + Map> providersMap = new HashMap<>(); + providersMap.put("local", masterKeyMap); + return providersMap; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java new file mode 100644 index 0000000000..0dff1ec86d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java @@ -0,0 +1,116 @@ +package com.baeldung.boot.csfle.config; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import org.bson.BsonBinary; +import org.bson.BsonDocument; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; + +import com.mongodb.AutoEncryptionSettings; +import com.mongodb.ClientEncryptionSettings; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoClientSettings.Builder; +import com.mongodb.MongoNamespace; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.Indexes; +import com.mongodb.client.model.vault.DataKeyOptions; +import com.mongodb.client.vault.ClientEncryption; +import com.mongodb.client.vault.ClientEncryptions; + +@Configuration +public class MongoClientConfig extends AbstractMongoClientConfiguration { + + @Value("${spring.data.mongodb.uri}") + private String uri; + + @Value("${spring.data.mongodb.database}") + private String db; + + @Autowired + private EncryptionConfig encryptionConfig; + + @Override + protected String getDatabaseName() { + return db; + } + + @Bean + @Override + public MongoClient mongoClient() { + MongoClient client; + try { + client = MongoClients.create(clientSettings()); + + ClientEncryption encryption = clientEncryption(); + encryptionConfig.setDataKeyId(createOrRetrieveDataKey(client, encryption)); + + return client; + } catch (IOException e) { + throw new IllegalStateException("unable to create client", e); + } + } + + @Bean + public ClientEncryption clientEncryption() throws FileNotFoundException, IOException { + Map> kmsProviders = LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath()); + + ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder() + .keyVaultMongoClientSettings(clientSettings()) + .keyVaultNamespace(encryptionConfig.getKeyVaultNamespace()) + .kmsProviders(kmsProviders) + .build(); + + return ClientEncryptions.create(encryptionSettings); + } + + private BsonBinary createOrRetrieveDataKey(MongoClient client, ClientEncryption encryption) { + MongoNamespace namespace = new MongoNamespace(encryptionConfig.getKeyVaultNamespace()); + MongoCollection keyVault = client.getDatabase(namespace.getDatabaseName()) + .getCollection(namespace.getCollectionName()); + + Bson query = Filters.in("keyAltNames", encryptionConfig.getKeyVaultAlias()); + BsonDocument key = keyVault.withDocumentClass(BsonDocument.class) + .find(query) + .first(); + + if (key == null) { + keyVault.createIndex(Indexes.ascending("keyAltNames"), new IndexOptions().unique(true) + .partialFilterExpression(Filters.exists("keyAltNames"))); + + DataKeyOptions options = new DataKeyOptions(); + options.keyAltNames(Arrays.asList(encryptionConfig.getKeyVaultAlias())); + return encryption.createDataKey("local", options); + } else { + return (BsonBinary) key.get("_id"); + } + } + + private MongoClientSettings clientSettings() throws FileNotFoundException, IOException { + Builder settings = MongoClientSettings.builder() + .applyConnectionString(new ConnectionString(uri)); + + if (encryptionConfig.getAutoDecryption()) { + settings.autoEncryptionSettings(AutoEncryptionSettings.builder() + .keyVaultNamespace(encryptionConfig.getKeyVaultNamespace()) + .kmsProviders(LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath())) + .bypassAutoEncryption(true) + .build()); + } + + return settings.build(); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/Citizen.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/Citizen.java new file mode 100644 index 0000000000..11e776123a --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/Citizen.java @@ -0,0 +1,49 @@ +package com.baeldung.boot.csfle.data; + +import org.springframework.data.mongodb.core.mapping.Document; + +@Document("citizens") +public class Citizen { + + private String name; + private String email; + private Integer birthYear; + + public Citizen() { + } + + public Citizen(EncryptedCitizen encryptedCitizen) { + if (encryptedCitizen != null) { + this.name = encryptedCitizen.getName(); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getBirthYear() { + return birthYear; + } + + public void setBirthYear(Integer birthYear) { + this.birthYear = birthYear; + } + + @Override + public String toString() { + return "Citizen [name=" + name + ", email=" + email + ", birthYear=" + birthYear + "]"; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/EncryptedCitizen.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/EncryptedCitizen.java new file mode 100644 index 0000000000..c7ca5566a9 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/data/EncryptedCitizen.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.csfle.data; + +import org.bson.types.Binary; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document("citizens") +public class EncryptedCitizen { + + private String name; + private Binary email; + private Binary birthYear; + + public EncryptedCitizen() { + } + + public EncryptedCitizen(Citizen citizen) { + this.name = citizen.getName(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Binary getEmail() { + return email; + } + + public void setEmail(Binary email) { + this.email = email; + } + + public Binary getBirthYear() { + return birthYear; + } + + public void setBirthYear(Binary birthYear) { + this.birthYear = birthYear; + } + + @Override + public String toString() { + return "Citizen [name=" + name + ", email=" + email + ", birthYear=" + birthYear + "]"; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java new file mode 100644 index 0000000000..6b3c463d0d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java @@ -0,0 +1,116 @@ +package com.baeldung.boot.csfle.service; + +import java.util.List; +import java.util.stream.Collectors; + +import org.bson.BsonBinary; +import org.bson.BsonInt32; +import org.bson.BsonString; +import org.bson.BsonValue; +import org.bson.types.Binary; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.csfle.config.EncryptionConfig; +import com.baeldung.boot.csfle.data.Citizen; +import com.baeldung.boot.csfle.data.EncryptedCitizen; +import com.mongodb.client.model.vault.EncryptOptions; +import com.mongodb.client.vault.ClientEncryption; + +@Service +public class CitizenService { + + public static final String DETERMINISTIC_ALGORITHM = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"; + public static final String RANDOM_ALGORITHM = "AEAD_AES_256_CBC_HMAC_SHA_512-Random"; + + @Autowired + private MongoTemplate mongo; + + @Autowired + private EncryptionConfig encryptionConfig; + + @Autowired + private ClientEncryption clientEncryption; + + public EncryptedCitizen save(Citizen citizen) { + EncryptedCitizen encryptedCitizen = new EncryptedCitizen(citizen); + encryptedCitizen.setEmail(encrypt(citizen.getEmail(), DETERMINISTIC_ALGORITHM)); + encryptedCitizen.setBirthYear(encrypt(citizen.getBirthYear(), RANDOM_ALGORITHM)); + + return mongo.save(encryptedCitizen); + } + + public List findAll() { + if (!encryptionConfig.getAutoDecryption()) { + List allEncrypted = mongo.findAll(EncryptedCitizen.class); + + return allEncrypted.stream() + .map(this::decrypt) + .collect(Collectors.toList()); + } else { + return mongo.findAll(Citizen.class); + } + } + + public Citizen findByEmail(String email) { + Query byEmail = new Query(Criteria.where("email") + .is(encrypt(email, DETERMINISTIC_ALGORITHM))); + if (!encryptionConfig.getAutoDecryption()) { + EncryptedCitizen encryptedCitizen = mongo.findOne(byEmail, EncryptedCitizen.class); + return decrypt(encryptedCitizen); + } else { + return mongo.findOne(byEmail, Citizen.class); + } + } + + public Binary encrypt(Object value, String algorithm) { + if (value == null) + return null; + + BsonValue bsonValue; + if (value instanceof Integer) { + bsonValue = new BsonInt32((Integer) value); + } else if (value instanceof String) { + bsonValue = new BsonString((String) value); + } else { + throw new IllegalArgumentException("unsupported type: " + value.getClass()); + } + + EncryptOptions options = new EncryptOptions(algorithm); + options.keyId(encryptionConfig.getDataKeyId()); + + BsonBinary encryptedValue = clientEncryption.encrypt(bsonValue, options); + return new Binary(encryptedValue.getType(), encryptedValue.getData()); + } + + public BsonValue decryptProperty(Binary value) { + if (value == null) + return null; + + return clientEncryption.decrypt(new BsonBinary(value.getType(), value.getData())); + } + + private Citizen decrypt(EncryptedCitizen encrypted) { + if (encrypted == null) + return null; + + Citizen citizen = new Citizen(encrypted); + + BsonValue decryptedBirthYear = decryptProperty(encrypted.getBirthYear()); + if (decryptedBirthYear != null) { + citizen.setBirthYear(decryptedBirthYear.asInt32() + .intValue()); + } + + BsonValue decryptedEmail = decryptProperty(encrypted.getEmail()); + if (decryptedEmail != null) { + citizen.setEmail(decryptedEmail.asString() + .getValue()); + } + + return citizen; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java new file mode 100644 index 0000000000..d17435fb5e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java @@ -0,0 +1,38 @@ +package com.baeldung.boot.csfle.web; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +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; + +import com.baeldung.boot.csfle.data.Citizen; +import com.baeldung.boot.csfle.data.EncryptedCitizen; +import com.baeldung.boot.csfle.service.CitizenService; + +@RestController +@RequestMapping("/citizen") +public class CitizenController { + + @Autowired + private CitizenService service; + + @GetMapping + public List get() { + return service.findAll(); + } + + @GetMapping("by") + public Citizen getBy(@RequestParam String email) { + return service.findByEmail(email); + } + + @PostMapping + public EncryptedCitizen post(@RequestBody Citizen citizen) { + return service.save(citizen); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java new file mode 100644 index 0000000000..471cb2883a --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java @@ -0,0 +1,75 @@ +package com.baeldung.boot.csfle; + +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 org.bson.types.Binary; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.csfle.data.Citizen; +import com.baeldung.boot.csfle.data.EncryptedCitizen; +import com.baeldung.boot.csfle.service.CitizenService; + +@DirtiesContext +@RunWith(SpringRunner.class) +@TestPropertySource("/embedded.properties") +@SpringBootTest(classes = MongoDbCsfleApplication.class) +public class CitizenServiceLiveTest { + + @Autowired + private MongoTemplate mongo; + + @Autowired + private CitizenService service; + + @Test + public void givenCitizen_whenEncryptingEmail_thenEncryptedCitizenEmailMatches() { + final Citizen citizen = new Citizen(); + citizen.setName("Foo"); + citizen.setEmail("foo@citizen.com"); + + Binary encryptedEmail = service.encrypt(citizen.getEmail(), CitizenService.DETERMINISTIC_ALGORITHM); + + EncryptedCitizen saved = service.save(citizen); + assertEquals(encryptedEmail, saved.getEmail()); + } + + @Test + public void givenRandomEncryptedField_whenFilteringByField_thenDocumentNotFound() { + Citizen john = new Citizen(); + john.setName("Jane Doe"); + john.setEmail("jane.doe@citizen.com"); + john.setBirthYear(1852); + + service.save(john); + + Query byBirthYear = new Query(Criteria.where("birthYear") + .is(service.encrypt(john.getBirthYear(), CitizenService.RANDOM_ALGORITHM))); + Citizen result = mongo.findOne(byBirthYear, Citizen.class); + + assertNull(result); + } + + @Test + public void givenDeterministicallyEncryptedField_whenFilteringByField_thenDocumentFound() { + Citizen jane = new Citizen(); + jane.setName("Jane Doe"); + jane.setEmail("jane.doe@citizen.com"); + jane.setBirthYear(1952); + + service.save(jane); + Citizen result = service.findByEmail(jane.getEmail()); + + assertNotNull(result); + } +} 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 a5b5fb9804..5325354e55 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 +1,10 @@ -spring.mongodb.embedded.version=4.4.9 \ No newline at end of file +spring.mongodb.embedded.version=4.4.9 + +spring.data.mongodb.uri=changeit +spring.data.mongodb.database=changeit + +com.baeldung.csfle.kms-provider=local +com.baeldung.csfle.key-vault.namespace=encryption._keyVault +com.baeldung.csfle.key-vault.alias=master.key +com.baeldung.csfle.master-key-path=/tmp/master.key +com.baeldung.csfle.auto-decryption=false diff --git a/persistence-modules/spring-data-cassandra-2/README.md b/persistence-modules/spring-data-cassandra-2/README.md index f5cf20b8a9..3f49d6ae93 100644 --- a/persistence-modules/spring-data-cassandra-2/README.md +++ b/persistence-modules/spring-data-cassandra-2/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [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) diff --git a/persistence-modules/spring-data-cassandra-2/pom.xml b/persistence-modules/spring-data-cassandra-2/pom.xml index 1e6412dc17..740c04d2a0 100644 --- a/persistence-modules/spring-data-cassandra-2/pom.xml +++ b/persistence-modules/spring-data-cassandra-2/pom.xml @@ -60,8 +60,32 @@ ${system.stubs.version} test + + com.datastax.oss + java-driver-mapper-runtime + 4.15.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + + com.datastax.oss + java-driver-mapper-processor + 4.15.0 + + + + + + + 11 3.1.11 diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/CassandraMapperApplication.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/CassandraMapperApplication.java new file mode 100644 index 0000000000..da66ee1401 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/CassandraMapperApplication.java @@ -0,0 +1,12 @@ +package org.baeldung.objectmapper; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CassandraMapperApplication { + + public static void main(String[] args) { + SpringApplication.run(CassandraMapperApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/DaoMapper.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/DaoMapper.java new file mode 100644 index 0000000000..f7e937702d --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/DaoMapper.java @@ -0,0 +1,18 @@ +package org.baeldung.objectmapper; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; +import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; +import com.datastax.oss.driver.api.mapper.annotations.Mapper; +import org.baeldung.objectmapper.dao.CounterDao; +import org.baeldung.objectmapper.dao.UserDao; + +@Mapper +public interface DaoMapper { + + @DaoFactory + UserDao getUserDao(@DaoKeyspace CqlIdentifier keyspace); + + @DaoFactory + CounterDao getUserCounterDao(@DaoKeyspace CqlIdentifier keyspace); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/CounterDao.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/CounterDao.java new file mode 100644 index 0000000000..71978ce116 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/CounterDao.java @@ -0,0 +1,16 @@ +package org.baeldung.objectmapper.dao; + +import com.datastax.oss.driver.api.mapper.annotations.Dao; +import com.datastax.oss.driver.api.mapper.annotations.Increment; +import com.datastax.oss.driver.api.mapper.annotations.Select; +import org.baeldung.objectmapper.entity.Counter; + +@Dao +public interface CounterDao { + + @Increment(entityClass = Counter.class) + void incrementCounter(String id, long count); + + @Select + Counter getCounterById(String id); +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserDao.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserDao.java new file mode 100644 index 0000000000..9e06066c1e --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserDao.java @@ -0,0 +1,38 @@ +package org.baeldung.objectmapper.dao; + +import com.datastax.oss.driver.api.core.PagingIterable; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.mapper.annotations.*; +import org.baeldung.objectmapper.entity.User; + +@Dao +public interface UserDao { + + @Insert + void insertUser(User user); + + @Select + User getUserById(int id); + + @Select + PagingIterable getAllUsers(); + + @Update + void updateUser(User user); + + @Delete + void deleteUser(User user); + + @GetEntity + User getUser(Row row); + + @SetEntity + BoundStatement setUser(BoundStatement udtValue, User user); + + @Query(value = "select * from user_profile where user_age > :userAge ALLOW FILTERING") + PagingIterable getUsersOlderThanAge(int userAge); + + @QueryProvider(providerClass = UserQueryProvider.class, entityHelpers = User.class, providerMethod = "getUsersOlderThanAge") + PagingIterable getUsersOlderThan(String age); +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserQueryProvider.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserQueryProvider.java new file mode 100644 index 0000000000..10c56a9310 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/dao/UserQueryProvider.java @@ -0,0 +1,34 @@ +package org.baeldung.objectmapper.dao; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.PagingIterable; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.mapper.MapperContext; +import com.datastax.oss.driver.api.mapper.entity.EntityHelper; +import com.datastax.oss.driver.api.querybuilder.QueryBuilder; +import org.baeldung.objectmapper.entity.User; + +public class UserQueryProvider { + + private final CqlSession session; + private final EntityHelper userHelper; + + public UserQueryProvider(MapperContext context, EntityHelper userHelper) { + this.session = context.getSession(); + this.userHelper = userHelper; + } + + public PagingIterable getUsersOlderThanAge(String age) { + SimpleStatement statement = QueryBuilder.selectFrom("user_profile") + .all() + .whereColumn("user_age") + .isGreaterThan(QueryBuilder + .bindMarker(age)) + .build(); + PreparedStatement preparedSelectUser = session.prepare(statement); + return session + .execute(preparedSelectUser.getQuery()) + .map(result -> userHelper.get(result, true)); + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Admin.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Admin.java new file mode 100644 index 0000000000..afd6b74490 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Admin.java @@ -0,0 +1,31 @@ +package org.baeldung.objectmapper.entity; + +import com.datastax.oss.driver.api.mapper.annotations.CqlName; +import com.datastax.oss.driver.api.mapper.annotations.Entity; +import com.datastax.oss.driver.api.mapper.annotations.HierarchyScanStrategy; + +@Entity +@CqlName("admin_profile") +@HierarchyScanStrategy(highestAncestor = User.class, includeHighestAncestor = true) +public class Admin extends User { + private String role; + private String department; + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + +} + diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Counter.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Counter.java new file mode 100644 index 0000000000..88b49b561e --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/Counter.java @@ -0,0 +1,29 @@ +package org.baeldung.objectmapper.entity; + +import com.datastax.oss.driver.api.mapper.annotations.Entity; +import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; + +@Entity +public class Counter { + + @PartitionKey + private String id; + private long count; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public long getCount() { + return count; + } + + public void setCount(long count) { + this.count = count; + } + +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/User.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/User.java new file mode 100644 index 0000000000..31612ffe73 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/objectmapper/entity/User.java @@ -0,0 +1,58 @@ +package org.baeldung.objectmapper.entity; + +import com.datastax.oss.driver.api.mapper.annotations.*; + +@Entity +@CqlName("user_profile") +public class User { + @PartitionKey + private int id; + @CqlName("username") + private String userName; + @ClusteringColumn + private int userAge; + + @Computed("writetime(userName)") + private long writetime; + + public User() { + } + + public User(int id, String userName, int userAge) { + this.id = id; + this.userName = userName; + this.userAge = userAge; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public int getUserAge() { + return userAge; + } + + public void setUserAge(int userAge) { + this.userAge = userAge; + } + + public long getWritetime() { + return writetime; + } + + public void setWritetime(long writetime) { + this.writetime = writetime; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..b61663d622 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java @@ -0,0 +1,96 @@ +package org.baeldung.objectmapper; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import org.baeldung.objectmapper.dao.CounterDao; +import org.baeldung.objectmapper.dao.UserDao; +import org.baeldung.objectmapper.entity.Counter; +import org.baeldung.objectmapper.entity.User; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +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; + +@Testcontainers +@SpringBootTest +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); + + 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.port", String.valueOf(cassandra.getMappedPort(9042))); + } + + static UserDao userDao; + static CounterDao counterDao; + + @BeforeAll + static void setup() { + setupCassandraConnectionProperties(); + CqlSession session = CqlSession.builder().build(); + + 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));"; + + session.execute(createKeyspace); + session.execute(useKeyspace); + session.execute(createUserTable); + session.execute(createAdminTable); + session.execute(createCounter); + + DaoMapper mapper = new DaoMapperBuilder(session).build(); + userDao = mapper.getUserDao(CqlIdentifier.fromCql("baeldung")); + counterDao = mapper.getUserCounterDao(CqlIdentifier.fromCql("baeldung")); + } + + @Test + void givenUser_whenInsert_thenRetrievedDuringGet() { + User user = new User(1, "JohnDoe", 31); + userDao.insertUser(user); + User retrievedUser = userDao.getUserById(1); + Assertions.assertEquals(retrievedUser.getUserName(), user.getUserName()); + } + + @Test + void givenCounter_whenIncrement_thenIncremented() { + Counter users = counterDao.getCounterById("users"); + long initialCount = users != null ? users.getCount(): 0; + + counterDao.incrementCounter("users", 1); + + users = counterDao.getCounterById("users"); + long finalCount = users != null ? users.getCount(): 0; + + Assertions.assertEquals(finalCount - initialCount, 1); + } + + @Test + void givenUser_whenGetUsersOlderThan_thenRetrieved() { + User user = new User(2, "JaneDoe", 20); + userDao.insertUser(user); + List retrievedUsers = userDao.getUsersOlderThanAge(30).all(); + Assertions.assertEquals(retrievedUsers.size(), 1); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-eclipselink/pom.xml b/persistence-modules/spring-data-eclipselink/pom.xml index 561d144fe3..c3c530d2d7 100644 --- a/persistence-modules/spring-data-eclipselink/pom.xml +++ b/persistence-modules/spring-data-eclipselink/pom.xml @@ -66,7 +66,7 @@ 1.5.9.RELEASE 2.7.0 - 1.4.197 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties b/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties index 5874482e7a..c3ad7011aa 100644 --- a/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties +++ b/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties @@ -1,2 +1,2 @@ -spring.datasource.url=jdbc:h2:mem:test;MVCC=FALSE;LOCK_TIMEOUT=100; +spring.datasource.url=jdbc:h2:mem:test;LOCK_TIMEOUT=100; spring.jpa.show-sql=true \ No newline at end of file diff --git a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/config/Config.java b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/config/Config.java index 51bbe73e9e..7f6653d7a8 100644 --- a/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/config/Config.java +++ b/persistence-modules/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/config/Config.java @@ -6,17 +6,17 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.RestClients; -import org.springframework.data.elasticsearch.core.ElasticsearchOperations; -import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration; import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; @Configuration @EnableElasticsearchRepositories(basePackages = "com.baeldung.spring.data.es.repository") @ComponentScan(basePackages = { "com.baeldung.spring.data.es.service" }) -public class Config { +public class Config extends AbstractElasticsearchConfiguration { @Bean - RestHighLevelClient client() { + @Override + public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .build(); @@ -24,9 +24,4 @@ public class Config { return RestClients.create(clientConfiguration) .rest(); } - - @Bean - public ElasticsearchOperations elasticsearchTemplate() { - return new ElasticsearchRestTemplate(client()); - } } diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java index 412cd04e09..cc38acc41c 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java @@ -22,7 +22,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; -import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; @@ -41,7 +41,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; public class ElasticSearchManualTest { @Autowired - private ElasticsearchRestTemplate elasticsearchTemplate; + private ElasticsearchOperations elasticsearchOperations; @Autowired private ArticleRepository articleRepository; @@ -117,7 +117,7 @@ public class ElasticSearchManualTest { final Query searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*")) .build(); - final SearchHits

articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); } @@ -126,7 +126,7 @@ public class ElasticSearchManualTest { public void givenSavedDoc_whenTitleUpdated_thenCouldFindByUpdatedTitle() { final Query searchQuery = new NativeSearchQueryBuilder().withQuery(fuzzyQuery("title", "serch")) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); @@ -147,7 +147,7 @@ public class ElasticSearchManualTest { final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); final long count = articleRepository.count(); @@ -162,7 +162,7 @@ public class ElasticSearchManualTest { public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() { final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND)) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); } } diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java index aaf0c80097..03c8da80c9 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java @@ -39,7 +39,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; @@ -58,7 +58,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; public class ElasticSearchQueryManualTest { @Autowired - private ElasticsearchRestTemplate elasticsearchTemplate; + private ElasticsearchOperations elasticsearchOperations; @Autowired private ArticleRepository articleRepository; @@ -101,7 +101,7 @@ public class ElasticSearchQueryManualTest { public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(Operator.AND)) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); } @@ -110,7 +110,7 @@ public class ElasticSearchQueryManualTest { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Engines Solutions")) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); assertEquals("Search engines", articles.getSearchHit(0) @@ -123,7 +123,7 @@ public class ElasticSearchQueryManualTest { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "elasticsearch data")) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(3, articles.getTotalHits()); } @@ -133,14 +133,14 @@ public class ElasticSearchQueryManualTest { NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")) .build(); - SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About")) .build(); - articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(0, articles.getTotalHits()); } @@ -150,7 +150,7 @@ public class ElasticSearchQueryManualTest { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(2, articles.getTotalHits()); } @@ -205,7 +205,7 @@ public class ElasticSearchQueryManualTest { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); } @@ -217,7 +217,7 @@ public class ElasticSearchQueryManualTest { .prefixLength(3)) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); } @@ -229,7 +229,7 @@ public class ElasticSearchQueryManualTest { .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(2, articles.getTotalHits()); } @@ -241,7 +241,7 @@ public class ElasticSearchQueryManualTest { final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder) .build(); - final SearchHits
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog")); + final SearchHits
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(2, articles.getTotalHits()); } diff --git a/persistence-modules/spring-data-jpa-query-3/README.md b/persistence-modules/spring-data-jpa-query-3/README.md index 268bce96ca..c0cc4f6511 100644 --- a/persistence-modules/spring-data-jpa-query-3/README.md +++ b/persistence-modules/spring-data-jpa-query-3/README.md @@ -6,6 +6,8 @@ This module contains articles about querying data using Spring Data JPA. - [Query Entities by Dates and Times with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-query-by-date) - [JPA and Hibernate – Criteria vs. JPQL vs. HQL Query](https://www.baeldung.com/jpql-hql-criteria-query) - [Joining Tables With Spring Data JPA Specifications](https://www.baeldung.com/spring-jpa-joining-tables) +- [NonUniqueResultException in Spring Data JPA](https://www.baeldung.com/spring-jpa-non-unique-result-exception) +- [Spring Data Repositories – Collections vs. Stream](https://www.baeldung.com/spring-data-collections-vs-stream) - More articles: [[<-- prev]](../spring-data-jpa-query-2) ### Eclipse Config diff --git a/persistence-modules/spring-data-jpa-query-3/pom.xml b/persistence-modules/spring-data-jpa-query-3/pom.xml index 135d31aaba..18df57fe14 100644 --- a/persistence-modules/spring-data-jpa-query-3/pom.xml +++ b/persistence-modules/spring-data-jpa-query-3/pom.xml @@ -5,6 +5,9 @@ 4.0.0 spring-data-jpa-query-3 spring-data-jpa-query-3 + + 0.15 + com.baeldung @@ -22,6 +25,11 @@ com.h2database h2 + + com.github.javafaker + javafaker + ${javafaker.version} + org.springframework.boot spring-boot-starter-test diff --git a/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/ListVsStreamQueryApplication.java b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/ListVsStreamQueryApplication.java new file mode 100644 index 0000000000..58123afa6c --- /dev/null +++ b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/ListVsStreamQueryApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.data.jpa.collectionsvsstream; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ListVsStreamQueryApplication { + + public static void main(String[] args) { + SpringApplication.run(ListVsStreamQueryApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/User.java b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/User.java new file mode 100644 index 0000000000..d2174c343f --- /dev/null +++ b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/User.java @@ -0,0 +1,61 @@ +package com.baeldung.spring.data.jpa.collectionsvsstream; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "_user") +public class User { + private String firstName; + private String lastName; + private int age; + @Id + private int id; + + public User() { + } + + public User(String firstName, String lastName, int age) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + + public User(String firstName, String lastName, int age, int id) { + this(firstName, lastName, age); + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + 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 int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepository.java b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepository.java new file mode 100644 index 0000000000..ed37cb7036 --- /dev/null +++ b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.data.jpa.collectionsvsstream; + +import java.util.List; +import java.util.stream.Stream; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + Stream findAllByAgeGreaterThan(int age); + + List findByAgeGreaterThan(int age); +} diff --git a/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/query/datetime/ArticleRepository.java b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/query/datetime/ArticleRepository.java index 9ec14884f4..726764b411 100644 --- a/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/query/datetime/ArticleRepository.java +++ b/persistence-modules/spring-data-jpa-query-3/src/main/java/com/baeldung/spring/data/jpa/query/datetime/ArticleRepository.java @@ -14,6 +14,9 @@ public interface ArticleRepository extends JpaRepository { List
findAllByPublicationTimeBetween(Date publicationTimeStart, Date publicationTimeEnd); + Article findByPublicationTimeBetween(Date publicationTimeStart, + Date publicationTimeEnd); + @Query("select a from Article a where a.creationDateTime <= :creationDateTime") List
findAllWithCreationDateTimeBefore( @Param("creationDateTime") Date creationDateTime); diff --git a/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepositoryUnitTest.java b/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepositoryUnitTest.java new file mode 100644 index 0000000000..3a0342bf41 --- /dev/null +++ b/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/collectionsvsstream/UserRepositoryUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.spring.data.jpa.collectionsvsstream; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +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.autoconfigure.orm.jpa.DataJpaTest; + +import com.github.javafaker.Faker; + +@DataJpaTest +class UserRepositoryUnitTest { + + @Autowired + private UserRepository userRepository; + + @BeforeEach + public void setup() { + Faker faker = new Faker(); + List people = IntStream.range(1, 100) + .parallel() + .mapToObj(i -> new User(faker.name() + .firstName(), faker.name() + .lastName(), faker.number() + .numberBetween(1, 100), i)) + .collect(Collectors.toList()); + userRepository.saveAll(people); + } + + @AfterEach + public void tearDown() { + userRepository.deleteAll(); + } + + @Test + public void whenAgeIs20_thenItShouldReturnAllUsersWhoseAgeIsGreaterThan20InAList() { + List users = userRepository.findByAgeGreaterThan(20); + assertThat(users).isNotEmpty(); + assertThat(users.stream() + .map(User::getAge) + .allMatch(age -> age > 20)).isTrue(); + } + + @Test + public void whenAgeIs20_thenItShouldReturnAllUsersWhoseAgeIsGreaterThan20InAStream() { + Stream users = userRepository.findAllByAgeGreaterThan(20); + assertThat(users).isNotNull(); + assertThat(users.map(User::getAge) + .allMatch(age -> age > 20)).isTrue(); + } +} diff --git a/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/query/nonuniqueresultexception/NonUniqueResultExceptionIntegrationTest.java b/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/query/nonuniqueresultexception/NonUniqueResultExceptionIntegrationTest.java new file mode 100644 index 0000000000..b032819ad6 --- /dev/null +++ b/persistence-modules/spring-data-jpa-query-3/src/test/java/com/baeldung/spring/data/jpa/query/nonuniqueresultexception/NonUniqueResultExceptionIntegrationTest.java @@ -0,0 +1,35 @@ +package com.baeldung.spring.data.jpa.query.nonuniqueresultexception; + +import com.baeldung.spring.data.jpa.query.datetime.ArticleRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.persistence.NonUniqueResultException; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +@RunWith(SpringRunner.class) +@DataJpaTest(properties = "spring.sql.init.data-locations=classpath:import_entities.sql", showSql = false) +public class NonUniqueResultExceptionIntegrationTest { + + @Autowired + private ArticleRepository repository; + + @Test + public void givenImportedArticles_whenFindByPublicationTimeBetween_thenIncorrectResultSizeDataAccessExceptionThrown() { + assertThatThrownBy(() -> repository.findByPublicationTimeBetween(new SimpleDateFormat("HH:mm").parse("15:15"), new SimpleDateFormat("HH:mm").parse("16:30"))) + .isInstanceOf(IncorrectResultSizeDataAccessException.class) + .hasCauseInstanceOf(NonUniqueResultException.class); + } + + @Test + public void givenImportedArticles_whenFindAllByPublicationTimeBetween_thenSuccess() throws ParseException { + repository.findAllByPublicationTimeBetween(new SimpleDateFormat("HH:mm").parse("15:15"), new SimpleDateFormat("HH:mm").parse("16:30")); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/README.md b/persistence-modules/spring-data-jpa-repo-2/README.md index 6403510e6f..23134ec02d 100644 --- a/persistence-modules/spring-data-jpa-repo-2/README.md +++ b/persistence-modules/spring-data-jpa-repo-2/README.md @@ -6,4 +6,7 @@ - [Performance Difference Between save() and saveAll() in Spring Data](https://www.baeldung.com/spring-data-save-saveall) - [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries) - [How to Access EntityManager with Spring Data](https://www.baeldung.com/spring-data-entitymanager) +- [Difference Between JPA and Spring Data JPA](https://www.baeldung.com/spring-data-jpa-vs-jpa) +- [Differences Between Spring Data JPA findFirst() and findTop()](https://www.baeldung.com/spring-data-jpa-findfirst-vs-findtop) +- [Difference Between findBy and findAllBy in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-find-by-vs-find-all-by) - More articles: [[<-- prev]](../spring-data-jpa-repo) diff --git a/persistence-modules/spring-data-jpa-repo-2/pom.xml b/persistence-modules/spring-data-jpa-repo-2/pom.xml index 748623c91a..dd0406eca8 100644 --- a/persistence-modules/spring-data-jpa-repo-2/pom.xml +++ b/persistence-modules/spring-data-jpa-repo-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 spring-data-jpa-repo-2 spring-data-jpa-repo-2 @@ -34,7 +34,14 @@ com.h2database h2 - + + com.querydsl + querydsl-apt + + + com.querydsl + querydsl-jpa + com.google.guava guava @@ -42,4 +49,53 @@ + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + generate-sources + + process + + + ${project.build.directory}/generated-sources + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + org.bsc.maven + maven-processor-plugin + 3.3.3 + + + process + + process + + generate-sources + + ${project.build.directory}/generated-sources + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + + + + + + org.hibernate + hibernate-jpamodelgen + 5.6.11.Final + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByApplication.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByApplication.java new file mode 100644 index 0000000000..c9757e2f04 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.data.persistence.findbyvsfindallby; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FindByVsFindAllByApplication { + public static void main(String[] args) { + SpringApplication.run(FindByVsFindAllByApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/model/Player.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/model/Player.java new file mode 100644 index 0000000000..0d8f833b4c --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/model/Player.java @@ -0,0 +1,43 @@ +package com.baeldung.spring.data.persistence.findbyvsfindallby.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import java.util.Objects; + +@Entity +public class Player { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + private Integer score; + + public Player(Integer score) { + this.score = score; + } + + public Player() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Integer getScore() { + return score; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Player player = (Player) o; + return id == player.id && Objects.equals(score, player.score); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/repository/PlayerRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/repository/PlayerRepository.java new file mode 100644 index 0000000000..6b0d1c6e5d --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/findbyvsfindallby/repository/PlayerRepository.java @@ -0,0 +1,17 @@ +package com.baeldung.spring.data.persistence.findbyvsfindallby.repository; + +import com.baeldung.spring.data.persistence.findbyvsfindallby.model.Player; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface PlayerRepository extends JpaRepository { + List findByScoreGreaterThan(Integer target); + + List findAllByScoreGreaterThan(Integer target); + + Optional findFirstByScoreGreaterThan(Integer target); +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/Student.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/Student.java new file mode 100644 index 0000000000..1d6eaa3b33 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/Student.java @@ -0,0 +1,75 @@ +package com.baeldung.spring.data.persistence.search; + +import java.util.Objects; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Student { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + private String name; + private int score; + + public Student() { + } + + public Student(String name, int score) { + + this.name = name; + this.score = score; + } + + 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 int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + @Override + public String toString() { + return "Student [id=" + id + ", name=" + name + ", score=" + score + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(id, name, score); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Student other = (Student) obj; + return id == other.id && Objects.equals(name, other.name) && score == other.score; + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentApplication.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentApplication.java new file mode 100644 index 0000000000..6aa895d067 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.data.persistence.search; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StudentApplication { + + private static final Logger log = LoggerFactory.getLogger(StudentApplication.class); + + public static void main(String[] args) { + SpringApplication.run(StudentApplication.class, args); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentRepository.java new file mode 100644 index 0000000000..29aade5886 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/search/StudentRepository.java @@ -0,0 +1,31 @@ +package com.baeldung.spring.data.persistence.search; + +import java.util.List; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface StudentRepository extends JpaRepository { + + Student findFirstByOrderByScoreDesc(); + + Student findFirstBy(Sort sort); + + Student findFirstByNameLike(String name, Sort sort); + + List findFirst3ByOrderByScoreDesc(); + + List findFirst2ByScoreBetween(int startScore, int endScore, Sort sort); + + Student findTopByOrderByScoreDesc(); + + Student findTopBy(Sort sort); + + Student findTopByNameLike(String name, Sort sort); + + List findTop3ByOrderByScoreDesc(); + + List findTop2ByScoreBetween(int startScore, int endScore, Sort sort); +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/model/Employee.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/model/Employee.java new file mode 100644 index 0000000000..9690bcf68a --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/model/Employee.java @@ -0,0 +1,76 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference.model; + +import java.io.Serializable; +import java.util.Objects; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +@Entity +@Table(name = "employee") +@NamedQuery(name = "Employee.findById", query = "SELECT e FROM Employee e WHERE e.id = :id") +public class Employee implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @Column(nullable = false) + private String firstName; + @Column(nullable = false) + private String lastName; + + @Column(nullable = false) + private String email; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Employee employee = (Employee) o; + return Objects.equals(id, employee.id) && Objects.equals(firstName, employee.firstName) && Objects.equals(lastName, employee.lastName) && Objects.equals(email, employee.email); + } + + @Override + public int hashCode() { + return Objects.hash(id, firstName, lastName, email); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/config/SpringDataJpaConfig.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/config/SpringDataJpaConfig.java new file mode 100644 index 0000000000..923e923c88 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/config/SpringDataJpaConfig.java @@ -0,0 +1,68 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.config; + +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.JpaVendorAdapter; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; +import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; + +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(basePackageClasses = EmployeeRepository.class) +public class SpringDataJpaConfig { + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan(Employee.class.getPackage() + .getName()); + + JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + + Properties properties = new Properties(); + properties.setProperty("hibernate.hbm2ddl.auto", "create-drop"); + properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + + em.setJpaProperties(properties); + + return em; + } + + @Bean + public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) { + JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject()); + return transactionManager; + } + + @Bean + public DataSource dataSource() { + return DataSourceBuilder.create() + .url("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1") + .driverClassName("org.h2.Driver") + .username("sa") + .password("sa") + .build(); + } + + @Bean + public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) { + return new JPAQueryFactory((entityManager)); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepository.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepository.java new file mode 100644 index 0000000000..012a46d885 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository; + +import java.util.List; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; + +@Repository +public interface EmployeeRepository extends JpaRepository { + + List findByFirstName(String firstName); + + @Query(value = "SELECT e FROM Employee e") + List findAllEmployee(Sort sort); +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepositoryPagingAndSort.java b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepositoryPagingAndSort.java new file mode 100644 index 0000000000..731735ea62 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/springdatajpadifference/springdata/repository/EmployeeRepositoryPagingAndSort.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; + +@Repository +public interface EmployeeRepositoryPagingAndSort extends PagingAndSortingRepository { + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties index 30cc5abbcc..db4837d8d2 100644 --- a/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties @@ -3,3 +3,9 @@ spring.datasource.username=sa spring.datasource.password=sa spring.jpa.properties.hibernate.globally_quoted_identifiers=true +logging.level.com.baeldung.spring.data.persistence.search=debug + +spring.jpa.show-sql=true +logging.level.org.hibernate.SQL=DEBUG +logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE +spring.jpa.properties.hibernate.format_sql=true diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByIntegrationTest.java new file mode 100644 index 0000000000..add340b4dd --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/findbyvsfindallby/FindByVsFindAllByIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.spring.data.persistence.findbyvsfindallby; + +import com.baeldung.spring.data.persistence.findbyvsfindallby.model.Player; +import com.baeldung.spring.data.persistence.findbyvsfindallby.repository.PlayerRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = FindByVsFindAllByApplication.class, properties = "spring.jpa.show-sql=true") +public class FindByVsFindAllByIntegrationTest { + @Autowired + private PlayerRepository playerRepository; + + @Before + public void setup() { + Player player1 = new Player(600); + Player player2 = new Player(500); + Player player3 = new Player(300); + playerRepository.saveAll(Arrays.asList(player1, player2, player3)); + } + + @Test + public void givenSavedPlayer_whenUseFindByOrFindAllBy_thenReturnSameResult() { + List findByPlayers = playerRepository.findByScoreGreaterThan(400); + List findAllByPlayers = playerRepository.findAllByScoreGreaterThan(400); + assertEquals(findByPlayers, findAllByPlayers); + } + + @Test + public void givenSavedPlayer_whenUseFindFirst_thenReturnSingleResult() { + Optional player = playerRepository.findFirstByScoreGreaterThan(400); + assertTrue(player.isPresent()); + assertEquals(600, player.get().getScore()); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/search/StudentApplicationUnitTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/search/StudentApplicationUnitTest.java new file mode 100644 index 0000000000..ea16b3597d --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/search/StudentApplicationUnitTest.java @@ -0,0 +1,100 @@ +package com.baeldung.spring.data.persistence.search; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +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.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Sort; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class StudentApplicationUnitTest { + + @Autowired + private StudentRepository studentRepo; + private List students; + + @Before + public void fillData() { + students = new ArrayList<>(); + int count = 10; + Random r = new Random(); + List scores = r.ints(0, 101) + .distinct() + .limit(count) + .boxed() + .collect(Collectors.toList()); + + for (int i = 0; i < count; i++) { + Integer score = scores.get(i); + Student s = new Student("Student-" + i, score); + students.add(s); + } + + studentRepo.saveAll(students); + Comparator c = Comparator.comparing(a -> a.getScore()); + c = c.reversed(); + students.sort(c); + } + + @After + public void clearData() { + studentRepo.deleteAll(); + } + + @Test + public void givenStudentScores_whenMoreThanOne_thenFindFirst() { + + Student student = studentRepo.findFirstByOrderByScoreDesc(); + Student s = students.get(0); + assertEquals(student, s); + } + + @Test + public void givenStudentScores_whenMoreThan3_thenFindFirstThree() { + + List firstThree = studentRepo.findFirst3ByOrderByScoreDesc(); + List sList = students.subList(0, 3); + assertArrayEquals(firstThree.toArray(), sList.toArray()); + } + + @Test + public void givenStudentScores_whenNameMatches_thenFindFirstStudent() { + + String matchString = "3"; + Student student = studentRepo.findFirstByNameLike("%" + matchString + "%", Sort.by("score") + .descending()); + Student s = students.stream() + .filter(a -> a.getName() + .contains(matchString)) + .findFirst() + .orElse(null); + assertEquals(student, s); + } + + @Test + public void givenStudentScores_whenBetweenRange_thenFindFirstTwoStudents() { + + List topTwoBetweenRange = studentRepo.findFirst2ByScoreBetween(50, 60, Sort.by("score") + .descending()); + List _students = students.stream() + .filter(a -> a.getScore() >= 50 && a.getScore() <= 60) + .limit(2) + .collect(Collectors.toList()); + assertArrayEquals(_students.toArray(), topTwoBetweenRange.toArray()); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/JpaDaoIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/JpaDaoIntegrationTest.java new file mode 100644 index 0000000000..b25038f175 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/JpaDaoIntegrationTest.java @@ -0,0 +1,201 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference; + +import static com.baeldung.spring.data.persistence.springdatajpadifference.TestUtils.employee; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Arrays; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.CriteriaUpdate; +import javax.persistence.criteria.Root; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee_; + +public class JpaDaoIntegrationTest { + + private final EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu-test"); + private final EntityManager entityManager = emf.createEntityManager(); + + @Before + public void setup() { + deleteAllEmployees(); + } + + @Test + public void givenPersistedEmployee_whenFindById_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + save(employee); + + assertEquals(employee, entityManager.find(Employee.class, employee.getId())); + } + + @Test + public void givenPersistedEmployee_whenFindByIdCriteriaQuery_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + save(employee); + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Employee.class); + Root root = criteriaQuery.from(Employee.class); + criteriaQuery.select(root); + + criteriaQuery.where(criteriaBuilder.equal(root.get(Employee_.ID), employee.getId())); + + assertEquals(employee, entityManager.createQuery(criteriaQuery) + .getSingleResult()); + } + + @Test + public void givenPersistedEmployee_whenFindByIdJpql_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + save(employee); + + Query jpqlQuery = entityManager.createQuery("SELECT e from Employee e WHERE e.id=:id"); + jpqlQuery.setParameter("id", employee.getId()); + + assertEquals(employee, jpqlQuery.getSingleResult()); + } + + @Test + public void givenPersistedEmployee_whenFindByIdNamedQuery_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + save(employee); + + Query query = entityManager.createNamedQuery("Employee.findById"); + + query.setParameter(Employee_.ID, employee.getId()); + + assertEquals(employee, query.getSingleResult()); + } + + @Test + public void givenPersistedEmployee_whenFindWithPaginationAndSort_thenEmployeesAreFound() { + Employee john = employee("John", "Doe"); + Employee bob = employee("Bob", "Smith"); + Employee frank = employee("Frank", "Brown"); + Employee james = employee("James", "Smith"); + save(john); + save(bob); + save(frank); + save(james); + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Employee.class); + Root root = criteriaQuery.from(Employee.class); + criteriaQuery.select(root); + criteriaQuery.orderBy(criteriaBuilder.asc(root.get(Employee_.FIRST_NAME))); + + TypedQuery query = entityManager.createQuery(criteriaQuery); + + query.setFirstResult(0); + query.setMaxResults(3); + + List employeeList = query.getResultList(); + + assertEquals(Arrays.asList(bob, frank, james), employeeList); + } + + @Test + public void givenPersistedEmployee_whenUpdateEmployeeEmail_thenEmployeeHasUpdatedEmail() { + Employee employee = employee("John", "Doe"); + save(employee); + + Employee employeeToUpdate = entityManager.find(Employee.class, employee.getId()); + + String updatedEmail = "email@gmail.com"; + + employeeToUpdate.setEmail(updatedEmail); + + update(employeeToUpdate); + + assertEquals(updatedEmail, entityManager.find(Employee.class, employee.getId()) + .getEmail()); + } + + @Test + public void givenPersistedEmployee_whenUpdateEmployeeEmailWithCriteria_thenEmployeeHasUpdatedEmail() { + Employee employee = employee("John", "Doe"); + save(employee); + + String updatedEmail = "email@gmail.com"; + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaUpdate criteriaUpdate = criteriaBuilder.createCriteriaUpdate(Employee.class); + Root root = criteriaUpdate.from(Employee.class); + + criteriaUpdate.set(Employee_.EMAIL, updatedEmail); + criteriaUpdate.where(criteriaBuilder.equal(root.get(Employee_.ID), employee.getId())); + + assertEquals(1, update(criteriaUpdate)); + + assertEquals(updatedEmail, entityManager.find(Employee.class, employee.getId()) + .getEmail()); + } + + @Test + public void givenPersistedEmployee_whenRemoveEmployee_thenNoEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + save(employee); + + delete(employee.getId()); + + assertNull(entityManager.find(Employee.class, employee.getId())); + } + + private void deleteAllEmployees() { + entityManager.getTransaction() + .begin(); + entityManager.createNativeQuery("DELETE from Employee") + .executeUpdate(); + entityManager.getTransaction() + .commit(); + } + + public void save(Employee entity) { + entityManager.getTransaction() + .begin(); + entityManager.persist(entity); + entityManager.getTransaction() + .commit(); + } + + public void update(Employee entity) { + entityManager.getTransaction() + .begin(); + entityManager.merge(entity); + entityManager.getTransaction() + .commit(); + } + + public void delete(Long employee) { + entityManager.getTransaction() + .begin(); + entityManager.remove(entityManager.find(Employee.class, employee)); + entityManager.getTransaction() + .commit(); + } + + public int update(CriteriaUpdate criteriaUpdate) { + entityManager.getTransaction() + .begin(); + int result = entityManager.createQuery(criteriaUpdate) + .executeUpdate(); + entityManager.getTransaction() + .commit(); + entityManager.clear(); + + return result; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/SpringDataJpaIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/SpringDataJpaIntegrationTest.java new file mode 100644 index 0000000000..e6febdc9f1 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/SpringDataJpaIntegrationTest.java @@ -0,0 +1,153 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference; + +import static com.baeldung.spring.data.persistence.springdatajpadifference.TestUtils.employee; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; +import com.baeldung.spring.data.persistence.springdatajpadifference.model.QEmployee; +import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.config.SpringDataJpaConfig; +import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepository; +import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepositoryPagingAndSort; +import com.querydsl.jpa.impl.JPAQueryFactory; + +@ContextConfiguration(classes = SpringDataJpaConfig.class) +@RunWith(SpringJUnit4ClassRunner.class) +@Transactional +@Rollback +public class SpringDataJpaIntegrationTest { + + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private EmployeeRepositoryPagingAndSort employeeRepositoryPagingAndSort; + + @Autowired + private JPAQueryFactory jpaQueryFactory; + + @Test + public void givenPersistedEmployee_whenFindById_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + + employeeRepository.save(employee); + + assertEquals(Optional.of(employee), employeeRepository.findById(employee.getId())); + } + + @Test + public void givenPersistedEmployee_whenFindByFirstName_thenEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + + employeeRepository.save(employee); + + assertEquals(employee, employeeRepository.findByFirstName(employee.getFirstName()) + .get(0)); + } + + @Test + public void givenPersistedEmployee_whenUpdateEmployeeEmail_thenEmployeeHasUpdatedEmail() { + Employee employee = employee("John", "Doe"); + + employeeRepository.save(employee); + + Employee employeeToUpdate = employeeRepository.findById(employee.getId()) + .orElse(null); + + assertNotNull(employeeToUpdate); + assertEquals(employee, employeeToUpdate); + + String updatedEmail = "email@gmail.com"; + + employeeToUpdate.setEmail(updatedEmail); + + employeeRepository.save(employeeToUpdate); + + assertEquals(Optional.of(employeeToUpdate), employeeRepository.findById(employee.getId())); + } + + @Test + public void givenPersistedEmployee_whenRemoveEmployee_thenNoEmployeeIsFound() { + Employee employee = employee("John", "Doe"); + + employeeRepository.save(employee); + + Employee persistedEmployee = employeeRepository.findById(employee.getId()) + .orElse(null); + + assertNotNull(persistedEmployee); + + employeeRepository.delete(persistedEmployee); + + assertFalse(employeeRepository.findById(employee.getId()) + .isPresent()); + } + + @Test + public void givenPersistedEmployees_whenFindSortedByFirstName_thenEmployeeAreFoundInOrder() { + Employee john = employee("John", "Doe"); + Employee bob = employee("Bob", "Smith"); + Employee frank = employee("Frank", "Brown"); + + employeeRepository.saveAll(Arrays.asList(john, bob, frank)); + + List employees = employeeRepository.findAllEmployee(Sort.by("firstName")); + + assertEquals(3, employees.size()); + assertEquals(bob, employees.get(0)); + assertEquals(frank, employees.get(1)); + assertEquals(john, employees.get(2)); + } + + @Test + public void givenPersistedEmployee_whenFindByQueryDsl_thenEmployeeIsFound() { + Employee john = employee("John", "Doe"); + Employee frank = employee("Frank", "Doe"); + + employeeRepository.saveAll(Arrays.asList(john, frank)); + + QEmployee employeePath = QEmployee.employee; + + List employees = jpaQueryFactory.selectFrom(employeePath) + .where(employeePath.firstName.eq("John"), employeePath.lastName.eq("Doe")) + .fetch(); + + assertEquals(1, employees.size()); + assertEquals(john, employees.get(0)); + } + + @Test + public void givenPersistedEmployee_whenFindBySortAndPagingRepository_thenEmployeeAreFound() { + Employee john = employee("John", "Doe"); + Employee bob = employee("Bob", "Smith"); + Employee frank = employee("Frank", "Brown"); + Employee jimmy = employee("Jimmy", "Armstrong"); + + employeeRepositoryPagingAndSort.saveAll(Arrays.asList(john, bob, frank, jimmy)); + + Pageable pageable = PageRequest.of(0, 2, Sort.by("firstName")); + + Page employees = employeeRepositoryPagingAndSort.findAll(pageable); + + assertEquals(Arrays.asList(bob, frank), employees.get() + .collect(Collectors.toList())); + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/TestUtils.java b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/TestUtils.java new file mode 100644 index 0000000000..989a7db247 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/springdatajpadifference/TestUtils.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.data.persistence.springdatajpadifference; + +import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee; + +public class TestUtils { + + public static Employee employee(String firstName, String lastname) { + Employee employee = new Employee(); + employee.setFirstName(firstName); + employee.setLastName(lastname); + employee.setEmail(firstName + lastname + "@baeldung.com"); + + return employee; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/resources/META-INF/persistence.xml b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..94df50cf0a --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-2/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,21 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee + + + + + + + + + + + + diff --git a/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/derivedquery/repository/UserRepository.java b/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/derivedquery/repository/UserRepository.java index e613ee1531..76cdf41d81 100644 --- a/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/derivedquery/repository/UserRepository.java +++ b/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/derivedquery/repository/UserRepository.java @@ -56,5 +56,9 @@ public interface UserRepository extends JpaRepository { List findByNameOrderByName(String name); List findByNameOrderByNameDesc(String name); + + List findByNameIsNotNull(); + + List findByNameOrderByNameAsc(String name); } diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index 330f0d975a..ab133192a0 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -42,11 +42,6 @@ spring-boot-starter-test test - - org.junit.platform - junit-platform-runner - test - cglib cglib-nodep diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextLiveTest.java similarity index 83% rename from persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextTest.java rename to persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextLiveTest.java index 5167e63721..c370fdfecf 100644 --- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextTest.java +++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/SpringContextLiveTest.java @@ -1,8 +1,8 @@ package com.baeldung; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; @@ -13,17 +13,17 @@ import redis.embedded.RedisServerBuilder; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisApplication.class) @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) -public class SpringContextTest { +public class SpringContextLiveTest { private static redis.embedded.RedisServer redisServer; - @BeforeClass + @BeforeAll public static void startRedisServer() { redisServer = new RedisServerBuilder().port(6379).setting("maxmemory 256M").build(); redisServer.start(); } - @AfterClass + @AfterAll public static void stopRedisServer() { redisServer.stop(); } diff --git a/persistence-modules/spring-jdbc/README.md b/persistence-modules/spring-jdbc/README.md index 22f7fb3d63..21d25915de 100644 --- a/persistence-modules/spring-jdbc/README.md +++ b/persistence-modules/spring-jdbc/README.md @@ -6,3 +6,4 @@ - [Using a List of Values in a JdbcTemplate IN Clause](https://www.baeldung.com/spring-jdbctemplate-in-list) - [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) diff --git a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAO.java b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAO.java index 15da78ce35..77b69daa01 100644 --- a/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAO.java +++ b/persistence-modules/spring-jdbc/src/main/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAO.java @@ -1,10 +1,12 @@ package com.baeldung.spring.jdbc.template.testing; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Repository; - import javax.sql.DataSource; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; + @Repository public class EmployeeDAO { private JdbcTemplate jdbcTemplate; @@ -20,4 +22,21 @@ public class EmployeeDAO { public int getCountOfEmployees() { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class); } + + public Employee getEmployeeById(int id) { + RowMapper employeeRowMapper = (rs, rowNum) -> new Employee(rs.getInt("ID"), rs.getString("FIRST_NAME"), rs.getString("LAST_NAME")); + + return jdbcTemplate.queryForObject("SELECT * FROM EMPLOYEE WHERE id=?", employeeRowMapper, id); + } + + public Employee getEmployeeByIdV2(int id) { + RowMapper employeeRowMapper = (rs, rowNum) -> new Employee(rs.getInt("ID"), rs.getString("FIRST_NAME"), rs.getString("LAST_NAME")); + + try { + return jdbcTemplate.queryForObject("SELECT * FROM EMPLOYEE WHERE id=?", employeeRowMapper, id); + } catch (EmptyResultDataAccessException e) { + return null; + } + } + } \ No newline at end of file diff --git a/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAOUnitTest.java b/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAOUnitTest.java index 3609300c2d..982a423996 100644 --- a/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAOUnitTest.java +++ b/persistence-modules/spring-jdbc/src/test/java/com/baeldung/spring/jdbc/template/testing/EmployeeDAOUnitTest.java @@ -1,20 +1,26 @@ package com.baeldung.spring.jdbc.template.testing; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; + +import javax.sql.DataSource; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.test.util.ReflectionTestUtils; -import javax.sql.DataSource; - -import static org.junit.jupiter.api.Assertions.assertEquals; - @RunWith(MockitoJUnitRunner.class) public class EmployeeDAOUnitTest { @Mock @@ -25,10 +31,10 @@ public class EmployeeDAOUnitTest { @Before public void setup() { dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2) - .generateUniqueName(true) - .addScript("classpath:com/baeldung/spring/jdbc/template/testing/schema.sql") - .addScript("classpath:com/baeldung/spring/jdbc/template/testing/test-data.sql") - .build(); + .generateUniqueName(true) + .addScript("classpath:com/baeldung/spring/jdbc/template/testing/schema.sql") + .addScript("classpath:com/baeldung/spring/jdbc/template/testing/test-data.sql") + .build(); } @Test @@ -36,12 +42,12 @@ public class EmployeeDAOUnitTest { EmployeeDAO employeeDAO = new EmployeeDAO(); ReflectionTestUtils.setField(employeeDAO, "jdbcTemplate", jdbcTemplate); Mockito.when(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class)) - .thenReturn(4); + .thenReturn(4); assertEquals(4, employeeDAO.getCountOfEmployees()); Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.eq(Integer.class))) - .thenReturn(3); + .thenReturn(3); assertEquals(3, employeeDAO.getCountOfEmployees()); } @@ -53,4 +59,25 @@ public class EmployeeDAOUnitTest { assertEquals(4, employeeDAO.getCountOfEmployees()); } + + @Test(expected = EmptyResultDataAccessException.class) + public void whenIdNotExist_thenThrowEmptyResultDataAccessException() { + EmployeeDAO employeeDAO = new EmployeeDAO(); + ReflectionTestUtils.setField(employeeDAO, "jdbcTemplate", jdbcTemplate); + Mockito.when(jdbcTemplate.queryForObject(anyString(), ArgumentMatchers.> any(), anyInt())) + .thenThrow(EmptyResultDataAccessException.class); + + employeeDAO.getEmployeeById(1); + } + + @Test + public void whenIdNotExist_thenReturnNull() { + EmployeeDAO employeeDAO = new EmployeeDAO(); + ReflectionTestUtils.setField(employeeDAO, "jdbcTemplate", jdbcTemplate); + Mockito.when(jdbcTemplate.queryForObject(anyString(), ArgumentMatchers.> any(), anyInt())) + .thenReturn(null); + + assertNull(employeeDAO.getEmployeeByIdV2(1)); + } + } diff --git a/persistence-modules/spring-jpa-2/pom.xml b/persistence-modules/spring-jpa-2/pom.xml index d0152288d4..19bc9cba14 100644 --- a/persistence-modules/spring-jpa-2/pom.xml +++ b/persistence-modules/spring-jpa-2/pom.xml @@ -105,7 +105,7 @@ 2.2.6.RELEASE 9.0.0.M26 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/spring-jpa-2/src/test/resources/manytomany/db.sql b/persistence-modules/spring-jpa-2/src/test/resources/manytomany/db.sql index 02905e41ee..fb544b93c6 100644 --- a/persistence-modules/spring-jpa-2/src/test/resources/manytomany/db.sql +++ b/persistence-modules/spring-jpa-2/src/test/resources/manytomany/db.sql @@ -1,18 +1,18 @@ CREATE TABLE course ( - id bigint(20) NOT NULL, + id bigint auto_increment NOT NULL, PRIMARY KEY (id) ); CREATE TABLE student ( - id bigint(20) NOT NULL, + id bigint auto_increment NOT NULL, PRIMARY KEY (id) ); CREATE TABLE course_like ( - student_id bigint(20) NOT NULL, - course_id bigint(20) NOT NULL, + student_id bigint auto_increment NOT NULL, + course_id bigint auto_increment NOT NULL, PRIMARY KEY (student_id, course_id), CONSTRAINT fk_course_like__student FOREIGN KEY (student_id) REFERENCES student (id), CONSTRAINT fk_course_like__course FOREIGN KEY (course_id) REFERENCES course (id) @@ -21,9 +21,9 @@ CREATE TABLE course_like ( CREATE TABLE course_rating ( - course_id bigint(20) NOT NULL, - student_id bigint(20) NOT NULL, - rating int(11) NOT NULL, + course_id bigint auto_increment NOT NULL, + student_id bigint auto_increment NOT NULL, + rating int auto_increment NOT NULL, PRIMARY KEY (course_id, student_id), CONSTRAINT fk_course_rating__student FOREIGN KEY (student_id) REFERENCES student (id), CONSTRAINT fk_course_rating__course FOREIGN KEY (course_id) REFERENCES course (id) @@ -32,11 +32,11 @@ CREATE TABLE course_rating ( CREATE TABLE course_registration ( - id bigint(20) NOT NULL, - grade int(11), + id bigint auto_increment NOT NULL, + grade int auto_increment, registered_at datetime NOT NULL, - course_id bigint(20) NOT NULL, - student_id bigint(20) NOT NULL, + course_id bigint auto_increment NOT NULL, + student_id bigint auto_increment NOT NULL, PRIMARY KEY (id), CONSTRAINT fk_course_registration__student FOREIGN KEY (student_id) REFERENCES student (id), CONSTRAINT fk_course_registration__course FOREIGN KEY (course_id) REFERENCES course (id) diff --git a/persistence-modules/spring-jpa/pom.xml b/persistence-modules/spring-jpa/pom.xml index a08e3f92c8..77074e835a 100644 --- a/persistence-modules/spring-jpa/pom.xml +++ b/persistence-modules/spring-jpa/pom.xml @@ -125,7 +125,7 @@ 6.0.15.Final 1.4.01 2.2.5 - 1.4.200 + 2.1.214 \ No newline at end of file diff --git a/persistence-modules/spring-jpa/src/test/resources/persistence-student.properties b/persistence-modules/spring-jpa/src/test/resources/persistence-student.properties index 9ca389d6ab..24e625d418 100644 --- a/persistence-modules/spring-jpa/src/test/resources/persistence-student.properties +++ b/persistence-modules/spring-jpa/src/test/resources/persistence-student.properties @@ -1,5 +1,5 @@ jdbc.driverClassName=org.h2.Driver -jdbc.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 +jdbc.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1;NON_KEYWORDS=KEY,VALUE hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.show_sql=false diff --git a/pom.xml b/pom.xml index ba1f778614..dcfa26abd5 100644 --- a/pom.xml +++ b/pom.xml @@ -330,166 +330,64 @@ parent-spring-5 parent-java - akka-modules - - algorithms-modules - annotations - antlr - - apache-cxf-modules - apache-kafka - apache-kafka-2 - apache-libraries - apache-olingo - apache-poi - apache-poi-2 - apache-rocketmq - apache-thrift - apache-tika - apache-velocity - - asciidoctor - asm - - atomix - - aws-modules - - axon azure - - bazel - cdi checker-plugin - code-generation - - core-groovy-modules core-java-modules couchbase - custom-pmd - - dagger - data-structures - ddd - deeplearning4j - discord4j - disruptor - dozer - drools - dubbo - - feign - flyway-cdi-extension - - geotools - google-cloud gradle-modules/gradle/maven-to-gradle - graphql-modules - grpc - guava-modules - - guice - hazelcast + + apache-httpclient - httpclient-simple - hystrix + apache-httpclient4 + jackson-modules - jackson-simple - java-blockchain + javafx java-jdi - java-rmi - java-spi java-websocket - javax-sound - javaxval - javaxval-2 - javax-validation-advanced + jaxb jersey - jgit - jgroups jhipster-5 - jib - jmeter + jmh - java-native - jsf - json-modules - jsoup + kubernetes-modules - ksqldb + language-interop - libraries-2 libraries-3 - libraries-7 - libraries-apache-commons - libraries-apache-commons-collections - libraries-apache-commons-io - libraries-data - libraries-data-2 libraries-data-db - libraries-data-io - libraries-files - libraries-http - libraries-http-2 - libraries-io - libraries-primitive - libraries-rpc - libraries-security - libraries-server - libraries-server-2 - libraries-testing + logging-modules lombok-modules - lucene - mapstruct maven-modules - mesos-marathon - metrics + messaging-modules + microservices-modules muleesb - mustache - mybatis + netflix-modules - netty - orika osgi - patterns-modules - pdf - pdf-2 - performance-tests + persistence-modules - protobuffer - quarkus-modules - - rabbitmq - reactor-core - rsocket - rule-engines-modules - rxjava-modules - atomikos - reactive-systems - security-modules - slack vavr-modules web-modules @@ -536,107 +434,48 @@ parent-spring-5 parent-java - saas - spf4j - spring-4 - - spring-5 - spring-reactive-modules - spring-5-webflux - spring-5-webflux-2 - - spring-activiti - spring-amqp spring-aop - spring-aop-2 - spring-apache-camel - spring-batch - spring-batch-2 spring-bom spring-boot-modules spring-boot-rest - - spring-caching - spring-caching-2 - spring-cloud-modules - spring-core - spring-core-2 - spring-core-3 spring-core-4 - spring-core-5 - spring-cucumber - spring-di spring-di-2 - spring-di-3 spring-drools - spring-ejb-modules + spring-exceptions - - spring-freemarker - spring-integration - spring-jenkins-pipeline spring-jersey - - spring-jms - - spring-kafka + spring-jinq spring-katharsis - spring-mobile - spring-native - spring-protobuf - spring-quartz - - spring-reactor spring-remoting-modules - spring-roo - spring-scheduling + + spring-security-modules spring-shell spring-soap spring-spel - spring-state-machine spring-static-resources spring-swagger-codegen - - spring-threads - spring-vault - spring-web-modules - spring-webflux-amqp spring-websockets - static-analysis - stripe - - tensorflow-java testing-modules - - twilio - twitter4j - - undertow - vertx-modules video-tutorials - - webrtc - wildfly xml xml-2 - xstream @@ -682,7 +521,7 @@ image-processing - jenkins + jenkins-modules jhipster-modules jhipster-5 jws @@ -691,7 +530,6 @@ libraries-4 libraries-5 libraries-6 - spring-boot-modules/spring-boot-react spring-ejb-modules/ejb-beans @@ -732,164 +570,60 @@ parent-spring-5 parent-java - akka-modules - - algorithms-modules - annotations - antlr - - apache-cxf-modules - apache-kafka - apache-kafka-2 - apache-libraries - apache-olingo - apache-poi - apache-poi-2 - apache-rocketmq - apache-thrift - apache-tika - apache-velocity - - asciidoctor - asm - - atomix - - aws-modules - - axon azure - - bazel - cdi checker-plugin - code-generation - - core-groovy-modules core-java-modules - couchbase - custom-pmd - - dagger - data-structures - ddd - deeplearning4j - discord4j - disruptor - dozer - drools - dubbo - - - feign - flyway-cdi-extension - - geotools - google-cloud gradle-modules/gradle/maven-to-gradle - graphql-modules - grpc - guava-modules - guice - hazelcast apache-httpclient - httpclient-simple - hystrix + apache-httpclient4 + jackson-modules - jackson-simple - java-blockchain + javafx java-jdi - java-rmi - java-spi java-websocket - javax-sound - javaxval - javaxval-2 - javax-validation-advanced + jaxb jersey - jgit - jgroups jhipster-5 - jib - jmeter jmh - java-native - jsf - json-modules - jsoup + kubernetes-modules - ksqldb + language-interop - libraries-2 libraries-3 - libraries-apache-commons - libraries-apache-commons-collections - libraries-apache-commons-io - libraries-data - libraries-data-2 libraries-data-db - libraries-data-io - libraries-files - libraries-http - libraries-http-2 - libraries-io - libraries-primitive - libraries-rpc - libraries-security - libraries-server - libraries-server-2 - libraries-testing + logging-modules lombok-modules - lucene - mapstruct maven-modules - mesos-marathon - metrics + messaging-modules + microservices-modules muleesb - mustache - mybatis netflix-modules - netty - orika osgi - patterns-modules - pdf - performance-tests + + persistence-modules - protobuffer - quarkus-modules - - rabbitmq - reactor-core - rsocket - rule-engines-modules - rxjava-modules - atomikos - reactive-systems - security-modules - slack vavr-modules web-modules @@ -928,108 +662,47 @@ parent-spring-5 parent-java - saas spf4j - spring-4 - - spring-5 - spring-reactive-modules - spring-5-webflux - spring-5-webflux-2 - - - spring-activiti - spring-amqp - spring-aop - spring-aop-2 - spring-apache-camel - spring-batch - spring-batch-2 spring-bom spring-boot-modules spring-boot-rest - - spring-caching - spring-caching-2 - spring-cloud-modules - spring-core - spring-core-2 - spring-core-3 spring-core-4 - spring-core-5 - spring-cucumber - spring-di spring-di-2 - spring-di-3 spring-drools - spring-ejb-modules spring-exceptions - - spring-freemarker - spring-integration - spring-jenkins-pipeline spring-jersey spring-jinq - spring-jms - - spring-kafka spring-katharsis - spring-mobile - spring-native - spring-protobuf - spring-quartz - - spring-reactor spring-remoting-modules - spring-roo - spring-scheduling + + spring-security-modules spring-shell spring-soap spring-spel - spring-state-machine spring-static-resources spring-swagger-codegen - - spring-threads - spring-vault - spring-web-modules - spring-webflux-amqp spring-websockets - static-analysis - stripe - - tensorflow-java testing-modules - - twilio - twitter4j - - undertow - vertx-modules video-tutorials - - webrtc - wildfly xml xml-2 - xstream @@ -1067,7 +740,7 @@ image-processing - jenkins + jenkins-modules jhipster-modules jhipster-5 jws @@ -1076,12 +749,10 @@ libraries-4 libraries-5 libraries-6 - spring-boot-modules/spring-boot-react spring-ejb-modules/ejb-beans - vaadin - vavr-modules + vavr-modules @@ -1147,62 +818,226 @@ + libraries-security + performance-tests + security-modules + libraries-server-2 + orika + + patterns-modules + json-modules + libraries-data + saas-modules + server-modules + apache-cxf-modules + + + spring-aop + jmeter + spring-aop-2 + + algorithms-modules + apache-libraries + apache-poi + apache-velocity + di-modules + asciidoctor + aws-modules + + couchbase + core-groovy-modules + core-java-modules/core-java-9 core-java-modules/core-java-9-improvements core-java-modules/core-java-9-jigsaw - core-java-modules/core-java-9-streams - core-java-modules/core-java-10 - core-java-modules/core-java-11 - core-java-modules/core-java-11-2 - core-java-modules/core-java-11-3 - - - - - - - core-java-modules/core-java-collections-set - core-java-modules/core-java-collections-list-4 - core-java-modules/core-java-collections-maps-4 - core-java-modules/core-java-concurrency-simple - core-java-modules/core-java-date-operations-1 - core-java-modules/core-java-datetime-conversion - core-java-modules/core-java-datetime-string - core-java-modules/core-java-io-conversions-2 - core-java-modules/core-java-jpms - core-java-modules/core-java-os - core-java-modules/core-java-streams-4 - core-java-modules/core-java-string-algorithms-3 - core-java-modules/core-java-string-operations-3 - core-java-modules/core-java-string-operations-4 - core-java-modules/core-java-time-measurements - core-java-modules/core-java-networking-3 - core-java-modules/core-java-strings - core-java-modules/core-java-httpclient - spring-core-6 - ddd-contexts - docker-modules - apache-httpclient-2 - libraries-concurrency - maven-modules/compiler-plugin-java-9 - maven-modules/maven-generate-war - maven-modules/multimodulemavenproject - optaplanner - persistence-modules/sirix - persistence-modules/spring-data-cassandra-2 - quarkus-modules/quarkus-vs-springboot - quarkus-modules/quarkus-jandex - spring-boot-modules/spring-boot-cassandre - spring-boot-modules/spring-boot-camel - spring-boot-modules/spring-boot-3 - spring-boot-modules/spring-boot-3-native - spring-swagger-codegen/custom-validations-opeanpi-codegen - testing-modules/testing-assertions - persistence-modules/fauna - lightrun - tablesaw + core-java-modules/core-java-9-streams + core-java-modules/core-java-10 + core-java-modules/core-java-11 + core-java-modules/core-java-11-2 + core-java-modules/core-java-11-3 + + + + + + + + core-java-modules/core-java-collections-set + core-java-modules/core-java-collections-list-4 + core-java-modules/core-java-collections-array-list + core-java-modules/core-java-collections-maps-4 + core-java-modules/core-java-collections-maps-5 + core-java-modules/core-java-concurrency-simple + core-java-modules/core-java-date-operations-1 + core-java-modules/core-java-datetime-conversion + core-java-modules/core-java-datetime-string + core-java-modules/core-java-io-conversions-2 + core-java-modules/core-java-jpms + core-java-modules/core-java-os + core-java-modules/core-java-streams-4 + core-java-modules/core-java-string-algorithms-3 + core-java-modules/core-java-string-operations-3 + core-java-modules/core-java-string-operations-4 + core-java-modules/core-java-string-operations-5 + core-java-modules/core-java-time-measurements + core-java-modules/core-java-networking-3 + core-java-modules/core-java-strings + core-java-modules/core-java-httpclient + custom-pmd + spring-core-6 + data-structures + ddd-contexts + deeplearning4j + docker-modules + drools + guava-modules + apache-httpclient-2 + kubernetes-modules/kubernetes-spring + libraries-concurrency + libraries-testing + maven-modules/compiler-plugin-java-9 + maven-modules/maven-generate-war + maven-modules/multimodulemavenproject + optaplanner + persistence-modules/sirix + persistence-modules/spring-data-cassandra-2 + quarkus-modules + spring-boot-modules/spring-boot-cassandre + spring-boot-modules/spring-boot-3 + spring-boot-modules/spring-boot-3-native + spring-boot-modules/spring-boot-3-observation + spring-boot-modules/spring-boot-3-test-pitfalls + spring-reactive-modules + spring-swagger-codegen/custom-validations-opeanpi-codegen + testing-modules/testing-assertions + persistence-modules/fauna + + rule-engines-modules + + reactive-systems + rxjava-modules + + lightrun + tablesaw + geotools + + + + akka-modules + annotations + apache-httpclient + httpclient-simple + antlr + apache-kafka + apache-kafka-2 + apache-olingo + + apache-poi-2 + apache-rocketmq + apache-thrift + apache-tika + + asm + atomikos + atomix + + + bazel + code-generation + ddd + discord4j + disruptor + dozer + dubbo + feign + google-cloud + graphql-modules + grpc + hazelcast + hystrix + jackson-simple + java-blockchain + + java-rmi + java-spi + javax-sound + javaxval + javaxval-2 + javax-validation-advanced + jgit + jib + + java-native + jsoup + ksqldb + jsf + libraries-2 + libraries-7 + libraries-apache-commons + libraries-apache-commons-collections + libraries-apache-commons-io + libraries-data-2 + libraries-data-io + libraries-files + libraries-http + libraries-http-2 + libraries-io + libraries-primitive + libraries-rpc + libraries-server + + lucene + mapstruct + mesos-marathon + metrics + mustache + mybatis + pdf + pdf-2 + protobuffer + reactor-core + rsocket + slack + + + + spring-5 + spring-5-webflux + spring-5-webflux-2 + spring-activiti + spring-batch-2 + spring-boot-modules/spring-caching-2 + spring-core-2 + spring-core-3 + spring-core-5 + spring-di-3 + spring-cucumber + + spring-kafka + + spring-native + spring-security-modules/spring-security-oauth2-testing + spring-protobuf + spring-quartz + + spring-scheduling + + spring-state-machine + spring-threads + tensorflow-java + xstream + webrtc + persistence-modules/java-mongodb + messaging-modules/spring-apache-camel + + + UTF-8 + 11 + 11 + 11 + @@ -1228,6 +1063,30 @@ + libraries-security + performance-tests + security-modules + libraries-server-2 + orika + + patterns-modules + json-modules + libraries-data + saas-modules + server-modules + apache-cxf-modules + + algorithms-modules + apache-libraries + apache-poi + apache-velocity + di-modules + asciidoctor + aws-modules + + couchbase + + core-groovy-modules core-java-modules/core-java-9 core-java-modules/core-java-9-improvements core-java-modules/core-java-9-jigsaw @@ -1243,9 +1102,12 @@ + core-java-modules/core-java-collections-set core-java-modules/core-java-collections-list-4 + core-java-modules/core-java-collections-array-list core-java-modules/core-java-collections-maps-4 + core-java-modules/core-java-collections-maps-5 core-java-modules/core-java-concurrency-simple core-java-modules/core-java-date-operations-1 core-java-modules/core-java-datetime-conversion @@ -1253,35 +1115,186 @@ core-java-modules/core-java-io-conversions-2 core-java-modules/core-java-jpms core-java-modules/core-java-os + core-java-modules/core-java-streams-4 core-java-modules/core-java-string-algorithms-3 core-java-modules/core-java-string-operations-3 core-java-modules/core-java-string-operations-4 + core-java-modules/core-java-string-operations-5 core-java-modules/core-java-time-measurements core-java-modules/core-java-networking-3 core-java-modules/core-java-strings + core-java-modules/core-java-httpclient + spring-aop + spring-aop-2 + custom-pmd + spring-core-6 + data-structures ddd-contexts + deeplearning4j + jmeter docker-modules + drools + guava-modules apache-httpclient-2 + kubernetes-modules/kubernetes-spring libraries-concurrency + libraries-testing maven-modules/compiler-plugin-java-9 maven-modules/maven-generate-war maven-modules/multimodulemavenproject optaplanner persistence-modules/sirix persistence-modules/spring-data-cassandra-2 - quarkus-modules/quarkus-vs-springboot - quarkus-modules/quarkus-jandex + quarkus-modules spring-boot-modules/spring-boot-cassandre - spring-boot-modules/spring-boot-camel spring-boot-modules/spring-boot-3 spring-boot-modules/spring-boot-3-native + spring-boot-modules/spring-boot-3-observation + spring-boot-modules/spring-boot-3-test-pitfalls + spring-reactive-modules spring-swagger-codegen/custom-validations-opeanpi-codegen testing-modules/testing-assertions persistence-modules/fauna + + rule-engines-modules + + reactive-systems + rxjava-modules + lightrun - spring-core-6 tablesaw + geotools + + + + akka-modules + annotations + apache-httpclient + antlr + apache-kafka + apache-kafka-2 + apache-olingo + + apache-poi-2 + apache-rocketmq + apache-thrift + apache-tika + + asm + atomikos + atomix + + + bazel + code-generation + ddd + discord4j + disruptor + dozer + + dubbo + feign + google-cloud + graphql-modules + grpc + hazelcast + httpclient-simple + hystrix + jackson-simple + java-blockchain + + java-rmi + java-spi + javax-sound + javaxval + javaxval-2 + javax-validation-advanced + jgit + jib + + java-native + jsoup + jsf + ksqldb + + libraries-7 + libraries-apache-commons + libraries-apache-commons-collections + libraries-apache-commons-io + libraries-data-2 + libraries-data-io + libraries-files + libraries-http + libraries-http-2 + libraries-io + libraries-primitive + libraries-rpc + libraries-server + + lucene + mapstruct + mesos-marathon + metrics + mustache + mybatis + pdf + pdf-2 + protobuffer + reactor-core + rsocket + slack + + + + + spring-5 + spring-5-webflux + spring-5-webflux-2 + spring-activiti + spring-batch-2 + spring-boot-modules/spring-caching-2 + spring-core-2 + spring-core-3 + spring-core-5 + spring-di-3 + spring-cucumber + + spring-kafka + + spring-native + spring-protobuf + spring-quartz + + spring-scheduling + + spring-state-machine + spring-threads + tensorflow-java + xstream + webrtc + persistence-modules/java-mongodb + libraries-2 + messaging-modules/spring-apache-camel + + + UTF-8 + 11 + 11 + 11 + + + + + parents + + parent-boot-1 + parent-boot-2 + parent-spring-4 + parent-spring-5 + parent-java + + @@ -1339,8 +1352,8 @@ 1.2 2.13.3 1.4 - 1.8.1 - 5.8.1 + 1.9.2 + 5.9.2 1.3.2 0.3.1 2.5.2 diff --git a/quarkus-modules/pom.xml b/quarkus-modules/pom.xml index 94fe1ae10f..ab9f7c3906 100644 --- a/quarkus-modules/pom.xml +++ b/quarkus-modules/pom.xml @@ -16,7 +16,8 @@ quarkus quarkus-extension - + quarkus-jandex + quarkus-vs-springboot \ No newline at end of file diff --git a/quarkus-modules/quarkus-funqy/README.md b/quarkus-modules/quarkus-funqy/README.md new file mode 100644 index 0000000000..a97005bb00 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Guide to Quarkus Funqy](https://www.baeldung.com/java-quarkus-funqy) diff --git a/quarkus-modules/quarkus-funqy/pom.xml b/quarkus-modules/quarkus-funqy/pom.xml new file mode 100644 index 0000000000..603f458287 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + com.baeldung.quarkus + quarkus-funqy + 1.0.0-SNAPSHOT + + 3.10.1 + false + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 2.16.0.Final + 3.0.0-M7 + + + com.baeldung + quarkus-modules + 1.0.0-SNAPSHOT + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-funqy-http + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-funqy-knative-events + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + native + + + native + + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + native + + + + diff --git a/quarkus-modules/quarkus-funqy/src/main/docker/Dockerfile.jvm b/quarkus-modules/quarkus-funqy/src/main/docker/Dockerfile.jvm new file mode 100644 index 0000000000..2119ae0891 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/src/main/docker/Dockerfile.jvm @@ -0,0 +1,93 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the container image run: +# +# ./mvnw package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/quarkus-funqy-project-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/quarkus-funqy-project-jvm +# +# If you want to include the debug port into your docker image +# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 +# +# Then run the container using : +# +# docker run -i --rm -p 8080:8080 quarkus/quarkus-funqy-project-jvm +# +# This image uses the `run-java.sh` script to run the application. +# This scripts computes the command line to execute your Java application, and +# includes memory/GC tuning. +# You can configure the behavior using the following environment properties: +# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") +# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options +# in JAVA_OPTS (example: "-Dsome.property=foo") +# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is +# used to calculate a default maximal heap memory based on a containers restriction. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio +# of the container available memory as set here. The default is `50` which means 50% +# of the available memory is used as an upper boundary. You can skip this mechanism by +# setting this value to `0` in which case no `-Xmx` option is added. +# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This +# is used to calculate a default initial heap memory based on the maximum heap memory. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio +# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` +# is used as the initial heap size. You can skip this mechanism by setting this value +# to `0` in which case no `-Xms` option is added (example: "25") +# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. +# This is used to calculate the maximum value of the initial heap memory. If used in +# a container without any memory constraints for the container then this option has +# no effect. If there is a memory constraint then `-Xms` is limited to the value set +# here. The default is 4096MB which means the calculated value of `-Xms` never will +# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") +# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output +# when things are happening. This option, if set to true, will set +# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). +# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: +# true"). +# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). +# - CONTAINER_CORE_LIMIT: A calculated core limit as described in +# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") +# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). +# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. +# (example: "20") +# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. +# (example: "40") +# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. +# (example: "4") +# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus +# previous GC times. (example: "90") +# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") +# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") +# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should +# contain the necessary JRE command-line options to specify the required GC, which +# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). +# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") +# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") +# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be +# accessed directly. (example: "foo.example.com,bar.example.com") +# +### +FROM registry.access.redhat.com/ubi8/openjdk-17:1.11 + +ENV LANGUAGE='en_US:en' + + +# We make four distinct layers so if there are application changes the library layers can be re-used +COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ +COPY --chown=185 target/quarkus-app/*.jar /deployments/ +COPY --chown=185 target/quarkus-app/app/ /deployments/app/ +COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ + +EXPOSE 8080 +USER 185 +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" + diff --git a/quarkus-modules/quarkus-funqy/src/main/java/com/baeldung/quarkus/MyFunctions.java b/quarkus-modules/quarkus-funqy/src/main/java/com/baeldung/quarkus/MyFunctions.java new file mode 100644 index 0000000000..cf5f0ce4e4 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/src/main/java/com/baeldung/quarkus/MyFunctions.java @@ -0,0 +1,27 @@ +package com.baeldung.quarkus; + +import org.jboss.logging.Logger; +import io.quarkus.funqy.Funq; + +public class MyFunctions { + private static final Logger log = Logger.getLogger(MyFunctions.class); + @Funq("GreetUser") + public String fun(FunInput input) { + log.info("Function Triggered"); + String name = input != null ? input.name : "Funqy"; + return String.format("Hello %s!", name); + } + public static class FunInput { + public String name; + public FunInput() { } + public FunInput(String name) { + this.name = name; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + } +} diff --git a/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative-trigger.yaml b/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative-trigger.yaml new file mode 100644 index 0000000000..8384fc42c1 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative-trigger.yaml @@ -0,0 +1,14 @@ +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: baeldung-event +spec: + broker: baeldung + filter: + attributes: + type: GreetUser + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: quarkus-funqy-project \ No newline at end of file diff --git a/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative.yaml b/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative.yaml new file mode 100644 index 0000000000..4264053c02 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/src/main/kubernetes/knative.yaml @@ -0,0 +1,11 @@ +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: quarkus-funqy-project +spec: + template: + metadata: + name: quarkus-funqy-project-v1 + spec: + containers: + - image: docker.io/<>/quarkus-funqy-project \ No newline at end of file diff --git a/quarkus-modules/quarkus-funqy/src/main/resources/application.properties b/quarkus-modules/quarkus-funqy/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/quarkus-modules/quarkus-funqy/src/test/java/com/baeldung/quarkus/MyFunctionsUnitTest.java b/quarkus-modules/quarkus-funqy/src/test/java/com/baeldung/quarkus/MyFunctionsUnitTest.java new file mode 100644 index 0000000000..c9163c81b1 --- /dev/null +++ b/quarkus-modules/quarkus-funqy/src/test/java/com/baeldung/quarkus/MyFunctionsUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.quarkus; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; + +import java.util.UUID; + +@QuarkusTest +public class MyFunctionsUnitTest { + + @Test + public void givenFunctionAPI_whenCallWithoutBody_thenShouldReturnDefault() { + given() + .post("/GreetUser") + .then() + .statusCode(200) + .body(containsString("Hello Funqy!")); + } + + @Test + public void givenFunctionAPI_whenCallWithName_thenShouldReturnName() { + given() + .contentType(ContentType.JSON) + .body("{\"name\": \"Friend\"}") + .post("/GreetUser") + .then() + .statusCode(200) + .body(containsString("Hello Friend!")); + } + + @Test + public void givenFunctionAPI_whenCallWithEvent_thenShouldReturn200() { + RestAssured.given().contentType("application/json") + .header("ce-specversion", "1.0") + .header("ce-id", UUID.randomUUID().toString()) + .header("ce-type", "GreetUser") + .header("ce-source", "test") + .body("{ \"name\": \"Baeldung\" }") + .post("/") + .then().statusCode(200); + } + +} \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml index 69e1dc3ab0..13508d7086 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml @@ -71,8 +71,8 @@ test - mysql - mysql-connector-java + com.mysql + mysql-connector-j test diff --git a/quarkus-modules/quarkus/pom.xml b/quarkus-modules/quarkus/pom.xml index 3e1cbff01c..99d18579c3 100644 --- a/quarkus-modules/quarkus/pom.xml +++ b/quarkus-modules/quarkus/pom.xml @@ -182,7 +182,7 @@ - 1.7.0.Final + 2.16.3.Final 3.3.0 diff --git a/rule-engines-modules/easy-rules/pom.xml b/rule-engines-modules/easy-rules/pom.xml index c8e875944c..6f43307e89 100644 --- a/rule-engines-modules/easy-rules/pom.xml +++ b/rule-engines-modules/easy-rules/pom.xml @@ -23,7 +23,7 @@ - 3.0.0 + 4.1.0 \ No newline at end of file diff --git a/rule-engines-modules/evrete/pom.xml b/rule-engines-modules/evrete/pom.xml index d94da2853f..5b7f195722 100644 --- a/rule-engines-modules/evrete/pom.xml +++ b/rule-engines-modules/evrete/pom.xml @@ -30,7 +30,7 @@ - 2.1.04 + 3.0.01 \ No newline at end of file diff --git a/rule-engines-modules/openl-tablets/pom.xml b/rule-engines-modules/openl-tablets/pom.xml index 204efce6c5..a24e06c44d 100644 --- a/rule-engines-modules/openl-tablets/pom.xml +++ b/rule-engines-modules/openl-tablets/pom.xml @@ -28,7 +28,7 @@ - 5.19.4 + 5.26.5 \ No newline at end of file diff --git a/rule-engines-modules/rulebook/pom.xml b/rule-engines-modules/rulebook/pom.xml index 55e312289e..88feb148e2 100644 --- a/rule-engines-modules/rulebook/pom.xml +++ b/rule-engines-modules/rulebook/pom.xml @@ -23,7 +23,7 @@ - 0.6.2 + 0.12 \ No newline at end of file diff --git a/rxjava-modules/pom.xml b/rxjava-modules/pom.xml index cd46270d92..2f2597b644 100644 --- a/rxjava-modules/pom.xml +++ b/rxjava-modules/pom.xml @@ -17,6 +17,7 @@ rxjava-core + rxjava-core-2 rxjava-libraries rxjava-observables rxjava-operators diff --git a/rxjava-modules/rxjava-core-2/README.md b/rxjava-modules/rxjava-core-2/README.md new file mode 100644 index 0000000000..122f411256 --- /dev/null +++ b/rxjava-modules/rxjava-core-2/README.md @@ -0,0 +1,6 @@ +## RxJava + +This module contains articles about RxJava. + +### Relevant articles: +- [RxJava Single.just() vs Single.fromCallable()](https://www.baeldung.com/rxjava-single-just-single-fromcallable) diff --git a/rxjava-modules/rxjava-core-2/pom.xml b/rxjava-modules/rxjava-core-2/pom.xml new file mode 100644 index 0000000000..ccadf38ba3 --- /dev/null +++ b/rxjava-modules/rxjava-core-2/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + rxjava-core-2 + 1.0-SNAPSHOT + rxjava-core-2 + + + com.baeldung.rxjava-modules + rxjava-modules + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/rxjava-modules/rxjava-core-2/src/main/java/com/baeldung/rxjava/justvscallable/EmployeeRepository.java b/rxjava-modules/rxjava-core-2/src/main/java/com/baeldung/rxjava/justvscallable/EmployeeRepository.java new file mode 100644 index 0000000000..03d95e2c8a --- /dev/null +++ b/rxjava-modules/rxjava-core-2/src/main/java/com/baeldung/rxjava/justvscallable/EmployeeRepository.java @@ -0,0 +1,5 @@ +package com.baeldung.rxjava.justvscallable; + +public interface EmployeeRepository { + String findById(Long id); +} diff --git a/spring-apache-camel/src/main/resources/logback.xml b/rxjava-modules/rxjava-core-2/src/main/resources/logback.xml similarity index 100% rename from spring-apache-camel/src/main/resources/logback.xml rename to rxjava-modules/rxjava-core-2/src/main/resources/logback.xml diff --git a/rxjava-modules/rxjava-core-2/src/test/java/com/baeldung/rxjava/justvscallable/SingleJustVsFromCallableTest.java b/rxjava-modules/rxjava-core-2/src/test/java/com/baeldung/rxjava/justvscallable/SingleJustVsFromCallableTest.java new file mode 100644 index 0000000000..a693432343 --- /dev/null +++ b/rxjava-modules/rxjava-core-2/src/test/java/com/baeldung/rxjava/justvscallable/SingleJustVsFromCallableTest.java @@ -0,0 +1,70 @@ +package com.baeldung.rxjava.justvscallable; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import rx.Single; +import rx.observers.TestSubscriber; + +class SingleJustVsFromCallableUnitTest { + + public EmployeeRepository repository = mock(EmployeeRepository.class); + + @BeforeEach + public void beforeEach() { + reset(repository); + } + + @Test + void givenNoSubscriber_whenUsingJust_thenDataIsFetched() { + Mockito.when(repository.findById(123L)) + .thenReturn("John Doe"); + + Single employee = Single.just(repository.findById(123L)); + + Mockito.verify(repository, times(1)) + .findById(123L); + } + + @Test + void givenASubscriber_whenUsingJust_thenReturnTheCorrectValue() { + TestSubscriber testSubscriber = new TestSubscriber<>(); + Mockito.when(repository.findById(123L)) + .thenReturn("John Doe"); + + Single employee = Single.just(repository.findById(123L)); + employee.subscribe(testSubscriber); + + testSubscriber.assertValue("John Doe"); + testSubscriber.assertCompleted(); + } + + @Test + void givenNoSubscriber_whenUsingFromCallable_thenNoDataIsFetched() { + Single employee = Single.fromCallable(() -> repository.findById(123L)); + + Mockito.verify(repository, never()) + .findById(123L); + } + + @Test + void givenASubscriber_whenUsingFromCallable_thenReturnCorrectValue() { + TestSubscriber testSubscriber = new TestSubscriber<>(); + Mockito.when(repository.findById(123L)) + .thenReturn("John Doe"); + + Single employee = Single.fromCallable(() -> repository.findById(123L)); + employee.subscribe(testSubscriber); + + Mockito.verify(repository, times(1)) + .findById(123L); + testSubscriber.assertCompleted(); + testSubscriber.assertValue("John Doe"); + } +} \ No newline at end of file diff --git a/rxjava-modules/rxjava-core/README.md b/rxjava-modules/rxjava-core/README.md index 148713c8e3..16625435e6 100644 --- a/rxjava-modules/rxjava-core/README.md +++ b/rxjava-modules/rxjava-core/README.md @@ -13,3 +13,4 @@ This module contains articles about RxJava. - [RxJava Maybe](https://www.baeldung.com/rxjava-maybe) - [Combining RxJava Completables](https://www.baeldung.com/rxjava-completable) - [RxJava Hooks](https://www.baeldung.com/rxjava-hooks) +- [Retry with Delay in RxJava](https://www.baeldung.com/rxjava-retry-with-delay) diff --git a/saas/.gitignore b/saas-modules/jira-rest-integration/.gitignore similarity index 100% rename from saas/.gitignore rename to saas-modules/jira-rest-integration/.gitignore diff --git a/saas/README.md b/saas-modules/jira-rest-integration/README.md similarity index 53% rename from saas/README.md rename to saas-modules/jira-rest-integration/README.md index 4effb2afa9..5ae79ab5ea 100644 --- a/saas/README.md +++ b/saas-modules/jira-rest-integration/README.md @@ -1,6 +1,6 @@ -## SAAS +## Jira Rest Integration -This module contains articles about software as a service (SAAS) +This module contains articles about Jira Rest Integration ## Relevant articles: diff --git a/saas/pom.xml b/saas-modules/jira-rest-integration/pom.xml similarity index 88% rename from saas/pom.xml rename to saas-modules/jira-rest-integration/pom.xml index 87f273939c..ebf36646e4 100644 --- a/saas/pom.xml +++ b/saas-modules/jira-rest-integration/pom.xml @@ -3,16 +3,14 @@ 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 - saas - 0.1.0-SNAPSHOT - saas + jira-rest-integration + jira-rest-integration jar com.baeldung - parent-java - 0.0.1-SNAPSHOT - ../parent-java + saas-modules + 1.0.0-SNAPSHOT @@ -29,7 +27,7 @@ - saas + jira-rest-integration src/main/resources diff --git a/saas/src/main/java/com/baeldung/saas/jira/MyJiraClient.java b/saas-modules/jira-rest-integration/src/main/java/com/baeldung/saas/jira/MyJiraClient.java similarity index 100% rename from saas/src/main/java/com/baeldung/saas/jira/MyJiraClient.java rename to saas-modules/jira-rest-integration/src/main/java/com/baeldung/saas/jira/MyJiraClient.java diff --git a/spring-caching/src/main/resources/logback.xml b/saas-modules/jira-rest-integration/src/main/resources/logback.xml similarity index 100% rename from spring-caching/src/main/resources/logback.xml rename to saas-modules/jira-rest-integration/src/main/resources/logback.xml diff --git a/saas-modules/pom.xml b/saas-modules/pom.xml new file mode 100644 index 0000000000..7e8adebdd9 --- /dev/null +++ b/saas-modules/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + saas-modules + saas-modules + 1.0.0-SNAPSHOT + pom + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + jira-rest-integration + stripe + twilio + twitter4j + sentry-servlet + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + \ No newline at end of file diff --git a/saas-modules/sentry-servlet/README.md b/saas-modules/sentry-servlet/README.md new file mode 100644 index 0000000000..b2f03453b5 --- /dev/null +++ b/saas-modules/sentry-servlet/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Quick Guide to Sentry](https://www.baeldung.com/ops/java-sentry) diff --git a/saas-modules/sentry-servlet/pom.xml b/saas-modules/sentry-servlet/pom.xml new file mode 100644 index 0000000000..2e4f95b5fb --- /dev/null +++ b/saas-modules/sentry-servlet/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + com.baeldung + saas-modules + 1.0.0-SNAPSHOT + + sentry-servlet + sentry-servlet + war + + + 6.11.0 + 1.10.4 + 3.3.2 + + + + + io.sentry + sentry-servlet + ${sentry.version} + + + + javax.servlet + javax.servlet-api + provided + + + + + + + org.codehaus.cargo + cargo-maven3-plugin + ${cargo.version} + + + tomcat9x + embedded + + + + + + \ No newline at end of file diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java new file mode 100644 index 0000000000..7a32094221 --- /dev/null +++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java @@ -0,0 +1,32 @@ +package com.baeldung.sentry.servlet; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(urlPatterns = "/fault", loadOnStartup = 1) +public class FaultyServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + + String op = req.getParameter("op"); + if( "fault".equals(op) ) { + resp.sendError(500, "Something bad happened !"); + } + else if ( "exception".equals(op) ) { + throw new IllegalArgumentException("Internal error"); + } + else { + resp.setStatus(200); + resp.setContentType("text/plain"); + resp.getWriter().println("OK"); + } + } +} diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java new file mode 100644 index 0000000000..6f25dd36aa --- /dev/null +++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java @@ -0,0 +1,39 @@ +package com.baeldung.sentry.support; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +import io.sentry.Sentry; +import io.sentry.SentryLevel; + +@WebListener +public class SentryContextListener implements ServletContextListener { + @Override + public void contextInitialized(ServletContextEvent sce) { + + // Besides standard supported locations, let's also allow the DSN to be + // passed using servlet container managed parameters. This can be useful if your app + // is hosted in a shared application server. + ServletContext context = sce.getServletContext(); + String sentryDsn = context.getInitParameter("sentry.dsn"); + + if ( sentryDsn != null ) { + context.log("[I21] sentry.dsn init parameter found. Configuring Sentry SDK..."); + Sentry.init(sentryDsn); + } + else { + context.log("[I25] sentry.dsn init parameter not found. Configuring Sentry SDK with defaults"); + Sentry.init(); + } + + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + sce.getServletContext().log("[I34] shutting down context"); + Sentry.captureMessage("[I35] contextDestroyed", SentryLevel.INFO); + Sentry.close(); + } +} diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java new file mode 100644 index 0000000000..51055f321d --- /dev/null +++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java @@ -0,0 +1,32 @@ +package com.baeldung.sentry.support; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; + +import io.sentry.Sentry; +import io.sentry.SentryLevel; + +@WebFilter(urlPatterns = "/*") +public class SentryFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + try { + chain.doFilter(request, response); + int rc = ((HttpServletResponse) response).getStatus(); + if (rc / 100 == 5) { + Sentry.captureMessage("Application error: code=" + rc, SentryLevel.ERROR); + } + } catch (Throwable t) { + Sentry.captureException(t); + throw t; + } + } +} diff --git a/saas-modules/sentry-servlet/src/main/resources/sentry.properties b/saas-modules/sentry-servlet/src/main/resources/sentry.properties new file mode 100644 index 0000000000..cd8b3005dd --- /dev/null +++ b/saas-modules/sentry-servlet/src/main/resources/sentry.properties @@ -0,0 +1,3 @@ +# Sentry configuration file +# put your own DSN here. This one is NOT valid !!! +dsn=https://c295098aadd04f719f1c9f50d801f93e@o75061.ingest.sentry.io/4504455033978880 \ No newline at end of file diff --git a/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml b/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..e89de5f352 --- /dev/null +++ b/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java b/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java new file mode 100644 index 0000000000..3db0d1c66e --- /dev/null +++ b/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java @@ -0,0 +1,46 @@ +package com.baeldung.sentry.servlet; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.HttpURLConnection; +import java.net.URL; + +import org.junit.jupiter.api.Test; + +class FaultyServletLiveTest { + + + @Test + void testGivenFaultyRequestWithNoQueryString_thenSuccess() throws Exception { + + //int port = getServerPort(); + URL u = new URL("http://localhost:8080/sentry-servlet/fault"); + HttpURLConnection conn = (HttpURLConnection)u.openConnection(); + int rc = conn.getResponseCode(); + assertThat(rc) + .isEqualTo(200); + } + + @Test + void testGivenFaultyRequestWithFaultString_thenFail() throws Exception { + + //int port = getServerPort(); + URL u = new URL("http://localhost:8080/sentry-servlet/fault?fault=true"); + HttpURLConnection conn = (HttpURLConnection)u.openConnection(); + int rc = conn.getResponseCode(); + assertThat(rc) + .isEqualTo(500); + } + + @Test + void testGivenFaultyRequestWithExceptionString_thenFail() throws Exception { + + //int port = getServerPort(); + URL u = new URL("http://localhost:8080/sentry-servlet/fault?exception=true"); + HttpURLConnection conn = (HttpURLConnection)u.openConnection(); + int rc = conn.getResponseCode(); + assertThat(rc) + .isEqualTo(500); + } + +} diff --git a/stripe/.gitignore b/saas-modules/stripe/.gitignore similarity index 100% rename from stripe/.gitignore rename to saas-modules/stripe/.gitignore diff --git a/stripe/README.md b/saas-modules/stripe/README.md similarity index 100% rename from stripe/README.md rename to saas-modules/stripe/README.md diff --git a/stripe/pom.xml b/saas-modules/stripe/pom.xml similarity index 87% rename from stripe/pom.xml rename to saas-modules/stripe/pom.xml index cfd281b4a8..44bc5be4a8 100644 --- a/stripe/pom.xml +++ b/saas-modules/stripe/pom.xml @@ -5,16 +5,14 @@ 4.0.0 com.baeldung.stripe stripe - 0.0.1-SNAPSHOT stripe jar Demo project for Stripe API com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../parent-boot-2 + saas-modules + 1.0.0-SNAPSHOT diff --git a/stripe/src/main/java/com/baeldung/stripe/ChargeController.java b/saas-modules/stripe/src/main/java/com/baeldung/stripe/ChargeController.java similarity index 100% rename from stripe/src/main/java/com/baeldung/stripe/ChargeController.java rename to saas-modules/stripe/src/main/java/com/baeldung/stripe/ChargeController.java diff --git a/stripe/src/main/java/com/baeldung/stripe/ChargeRequest.java b/saas-modules/stripe/src/main/java/com/baeldung/stripe/ChargeRequest.java similarity index 100% rename from stripe/src/main/java/com/baeldung/stripe/ChargeRequest.java rename to saas-modules/stripe/src/main/java/com/baeldung/stripe/ChargeRequest.java diff --git a/stripe/src/main/java/com/baeldung/stripe/CheckoutController.java b/saas-modules/stripe/src/main/java/com/baeldung/stripe/CheckoutController.java similarity index 100% rename from stripe/src/main/java/com/baeldung/stripe/CheckoutController.java rename to saas-modules/stripe/src/main/java/com/baeldung/stripe/CheckoutController.java diff --git a/stripe/src/main/java/com/baeldung/stripe/StripeApplication.java b/saas-modules/stripe/src/main/java/com/baeldung/stripe/StripeApplication.java similarity index 100% rename from stripe/src/main/java/com/baeldung/stripe/StripeApplication.java rename to saas-modules/stripe/src/main/java/com/baeldung/stripe/StripeApplication.java diff --git a/stripe/src/main/java/com/baeldung/stripe/StripeService.java b/saas-modules/stripe/src/main/java/com/baeldung/stripe/StripeService.java similarity index 100% rename from stripe/src/main/java/com/baeldung/stripe/StripeService.java rename to saas-modules/stripe/src/main/java/com/baeldung/stripe/StripeService.java diff --git a/stripe/src/main/resources/application.properties b/saas-modules/stripe/src/main/resources/application.properties similarity index 100% rename from stripe/src/main/resources/application.properties rename to saas-modules/stripe/src/main/resources/application.properties diff --git a/spring-freemarker/src/main/resources/logback.xml b/saas-modules/stripe/src/main/resources/logback.xml similarity index 100% rename from spring-freemarker/src/main/resources/logback.xml rename to saas-modules/stripe/src/main/resources/logback.xml diff --git a/stripe/src/main/resources/static/index.html b/saas-modules/stripe/src/main/resources/static/index.html similarity index 100% rename from stripe/src/main/resources/static/index.html rename to saas-modules/stripe/src/main/resources/static/index.html diff --git a/stripe/src/main/resources/templates/checkout.html b/saas-modules/stripe/src/main/resources/templates/checkout.html similarity index 100% rename from stripe/src/main/resources/templates/checkout.html rename to saas-modules/stripe/src/main/resources/templates/checkout.html diff --git a/stripe/src/main/resources/templates/result.html b/saas-modules/stripe/src/main/resources/templates/result.html similarity index 100% rename from stripe/src/main/resources/templates/result.html rename to saas-modules/stripe/src/main/resources/templates/result.html diff --git a/twilio/README.md b/saas-modules/twilio/README.md similarity index 100% rename from twilio/README.md rename to saas-modules/twilio/README.md diff --git a/twilio/pom.xml b/saas-modules/twilio/pom.xml similarity index 89% rename from twilio/pom.xml rename to saas-modules/twilio/pom.xml index 327242749b..9c1b1cde9d 100644 --- a/twilio/pom.xml +++ b/saas-modules/twilio/pom.xml @@ -4,12 +4,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 twilio - 1.0-SNAPSHOT twilio com.baeldung - parent-modules + saas-modules 1.0.0-SNAPSHOT diff --git a/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsExample.java b/saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsExample.java similarity index 100% rename from twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsExample.java rename to saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsExample.java diff --git a/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsMediaExample.java b/saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsMediaExample.java similarity index 100% rename from twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsMediaExample.java rename to saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsMediaExample.java diff --git a/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusAsyncExample.java b/saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusAsyncExample.java similarity index 100% rename from twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusAsyncExample.java rename to saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusAsyncExample.java diff --git a/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusExample.java b/saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusExample.java similarity index 100% rename from twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusExample.java rename to saas-modules/twilio/src/main/java/com/baeldung/twilio/sms/TwilioSmsStatusExample.java diff --git a/spring-jms/src/main/resources/logback.xml b/saas-modules/twilio/src/main/resources/logback.xml similarity index 100% rename from spring-jms/src/main/resources/logback.xml rename to saas-modules/twilio/src/main/resources/logback.xml diff --git a/twitter4j/README.md b/saas-modules/twitter4j/README.md similarity index 100% rename from twitter4j/README.md rename to saas-modules/twitter4j/README.md diff --git a/twitter4j/pom.xml b/saas-modules/twitter4j/pom.xml similarity index 93% rename from twitter4j/pom.xml rename to saas-modules/twitter4j/pom.xml index 3e9bcd550a..ca46365c49 100644 --- a/twitter4j/pom.xml +++ b/saas-modules/twitter4j/pom.xml @@ -9,7 +9,7 @@ com.baeldung - parent-modules + saas-modules 1.0.0-SNAPSHOT diff --git a/twitter4j/src/main/java/com/baeldung/Application.java b/saas-modules/twitter4j/src/main/java/com/baeldung/Application.java similarity index 100% rename from twitter4j/src/main/java/com/baeldung/Application.java rename to saas-modules/twitter4j/src/main/java/com/baeldung/Application.java diff --git a/spring-reactor/src/main/resources/logback.xml b/saas-modules/twitter4j/src/main/resources/logback.xml similarity index 100% rename from spring-reactor/src/main/resources/logback.xml rename to saas-modules/twitter4j/src/main/resources/logback.xml diff --git a/twitter4j/src/main/resources/twitter4j.properties b/saas-modules/twitter4j/src/main/resources/twitter4j.properties similarity index 100% rename from twitter4j/src/main/resources/twitter4j.properties rename to saas-modules/twitter4j/src/main/resources/twitter4j.properties diff --git a/twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java b/saas-modules/twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java similarity index 100% rename from twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java rename to saas-modules/twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java diff --git a/security-modules/cas/README.md b/security-modules/cas/README.md index 6ceeaea0c4..a50159d2d8 100644 --- a/security-modules/cas/README.md +++ b/security-modules/cas/README.md @@ -15,4 +15,3 @@ The server starts at https://localhost:8443. `casuser`/`Mellon` are the username ### Relevant Articles: -- [CAS SSO With Spring Security](https://www.baeldung.com/spring-security-cas-sso) \ No newline at end of file diff --git a/security-modules/cas/cas-server/README.md b/security-modules/cas/cas-server/README.md new file mode 100644 index 0000000000..6c9372a729 --- /dev/null +++ b/security-modules/cas/cas-server/README.md @@ -0,0 +1,2 @@ +# Relevant Articles +- [CAS SSO With Spring Security](https://www.baeldung.com/spring-security-cas-sso) diff --git a/security-modules/jwt/.gitignore b/security-modules/jwt/.gitignore new file mode 100644 index 0000000000..f83e8cf07c --- /dev/null +++ b/security-modules/jwt/.gitignore @@ -0,0 +1,3 @@ +.idea +target +*.iml diff --git a/security-modules/jwt/README.md b/security-modules/jwt/README.md new file mode 100644 index 0000000000..42f761bb36 --- /dev/null +++ b/security-modules/jwt/README.md @@ -0,0 +1,4 @@ +## Relevant Articles + +- [Managing JWT With Auth0 java-jwt](https://www.baeldung.com/java-auth0-jwt) +- [Check JWT Expiry Without Throwing Exceptions](https://www.baeldung.com/java-jwt-check-expiry-no-exception) diff --git a/security-modules/jwt/pom.xml b/security-modules/jwt/pom.xml new file mode 100644 index 0000000000..5ec563dcfa --- /dev/null +++ b/security-modules/jwt/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + jwt + jwt + jar + + + com.baeldung + security-modules + 1.0.0-SNAPSHOT + + + + + com.auth0 + java-jwt + ${auth0-jwt.version} + + + + + 4.2.1 + + + \ No newline at end of file diff --git a/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java new file mode 100644 index 0000000000..0d5e7a4839 --- /dev/null +++ b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java @@ -0,0 +1,99 @@ +package com.baeldung.jwt.auth0; + +import java.util.Date; +import java.util.UUID; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; + +public class Auth0JsonWebToken { + + private static final String SECRET = "baeldung"; + private static final String ISSUER = "Baeldung"; + private static final String SUBJECT = "Baeldung Details"; + private static final String DATA_CLAIM = "userId"; + private static final String DATA = "1234"; + private static final long TOKEN_VALIDITY_IN_MILLIS = 5000L; + + private static Algorithm algorithm; + private static JWTVerifier verifier; + + public static void initialize() { + algorithm = Algorithm.HMAC256(SECRET); + + verifier = JWT.require(algorithm) + .withIssuer(ISSUER) + .build(); + } + + private static String createJWT() { + String jwtToken = JWT.create() + .withIssuer(ISSUER) + .withSubject(SUBJECT) + .withClaim(DATA_CLAIM, DATA) + .withIssuedAt(new Date()) + .withExpiresAt(new Date(System.currentTimeMillis() + TOKEN_VALIDITY_IN_MILLIS)) + .withJWTId(UUID.randomUUID() + .toString()) + .withNotBefore(new Date(System.currentTimeMillis() + 1000L)) + .sign(algorithm); + + return jwtToken; + } + + private static DecodedJWT verifyJWT(String jwtToken) { + try { + DecodedJWT decodedJWT = verifier.verify(jwtToken); + return decodedJWT; + } catch (JWTVerificationException e) { + System.out.println(e.getMessage()); + } + return null; + } + + private static boolean isJWTExpired(DecodedJWT decodedJWT) { + Date expiresAt = decodedJWT.getExpiresAt(); + return expiresAt.getTime() < System.currentTimeMillis(); + } + + private static String getClaim(DecodedJWT decodedJWT, String claimName) { + Claim claim = decodedJWT.getClaim(claimName); + return claim != null ? claim.asString() : null; + } + + public static void main(String args[]) throws InterruptedException { + + initialize(); + + String jwtToken = createJWT(); + System.out.println("Created JWT : " + jwtToken); + + DecodedJWT decodedJWT = verifyJWT(jwtToken); + if (decodedJWT == null) { + System.out.println("JWT Verification Failed"); + } + + Thread.sleep(1000L); + + decodedJWT = verifyJWT(jwtToken); + if (decodedJWT != null) { + System.out.println("Token Issued At : " + decodedJWT.getIssuedAt()); + System.out.println("Token Expires At : " + decodedJWT.getExpiresAt()); + System.out.println("Subject : " + decodedJWT.getSubject()); + System.out.println("Data : " + getClaim(decodedJWT, DATA_CLAIM)); + System.out.println("Header : " + decodedJWT.getHeader()); + System.out.println("Payload : " + decodedJWT.getPayload()); + System.out.println("Signature : " + decodedJWT.getSignature()); + System.out.println("Algorithm : " + decodedJWT.getAlgorithm()); + System.out.println("JWT Id : " + decodedJWT.getId()); + + Boolean isExpired = isJWTExpired(decodedJWT); + System.out.println("Is Expired : " + isExpired); + } + } + +} diff --git a/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/JWTDecode.java b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/JWTDecode.java new file mode 100644 index 0000000000..61c40ec9c5 --- /dev/null +++ b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/JWTDecode.java @@ -0,0 +1,90 @@ +package com.baeldung.jwt.auth0; + +import java.util.Date; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; + +public class JWTDecode { + + private static final String SECRET = "baeldung"; + private static final String ISSUER = "Baeldung"; + private static final String SUBJECT = "Baeldung Details"; + private static final long TOKEN_VALIDITY_IN_MILLIS = 500L; + + private static Algorithm algorithm; + private static JWTVerifier verifier; + + public static void initialize() { + algorithm = Algorithm.HMAC256(SECRET); + + verifier = JWT.require(algorithm) + .withIssuer(ISSUER) + .build(); + } + + private static String createJWT() { + String jwtToken = JWT.create() + .withIssuer(ISSUER) + .withSubject(SUBJECT) + .withIssuedAt(new Date()) + .withExpiresAt(new Date(System.currentTimeMillis() + TOKEN_VALIDITY_IN_MILLIS)) + .sign(algorithm); + + return jwtToken; + } + + private static DecodedJWT verifyJWT(String jwtToken) { + try { + DecodedJWT decodedJWT = verifier.verify(jwtToken); + return decodedJWT; + } catch (JWTVerificationException e) { + System.out.println(e.getMessage()); + } + return null; + } + + private static DecodedJWT decodedJWT(String jwtToken) { + try { + DecodedJWT decodedJWT = JWT.decode(jwtToken); + return decodedJWT; + } catch (JWTDecodeException e) { + System.out.println(e.getMessage()); + } + return null; + } + + private static boolean isJWTExpired(DecodedJWT decodedJWT) { + Date expiresAt = decodedJWT.getExpiresAt(); + return expiresAt.before(new Date()); + } + + public static void main(String args[]) throws InterruptedException { + + initialize(); + + String jwtToken = createJWT(); + System.out.println("Created JWT : " + jwtToken); + + Thread.sleep(1000L); + + DecodedJWT decodedJWT = verifyJWT(jwtToken); + if (decodedJWT == null) { + System.out.println("JWT Verification Failed"); + } + + decodedJWT = decodedJWT(jwtToken); + if (decodedJWT != null) { + System.out.println("Token Issued At : " + decodedJWT.getIssuedAt()); + System.out.println("Token Expires At : " + decodedJWT.getExpiresAt()); + + Boolean isExpired = isJWTExpired(decodedJWT); + System.out.println("Is Expired : " + isExpired); + } + } + +} 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 new file mode 100644 index 0000000000..a9c3b4185d --- /dev/null +++ b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java @@ -0,0 +1,127 @@ +package com.baeldung.jwt.auth0; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Date; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.IncorrectClaimException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; + +public class Auth0JsonWebTokenUnitTest { + + private static final String SECRET = "baeldung"; + private static final String SECRET_NEW = "baeldung.com"; + private static final String ISSUER = "Baeldung"; + private static final String DATA_CLAIM = "userId"; + private static final String DATA = "1234"; + + private static Algorithm algorithm; + private static Algorithm algorithmWithDifferentSecret; + private static JWTVerifier verifier; + private static String jwtToken; + + @BeforeAll + public static void setUp() { + algorithm = Algorithm.HMAC256(SECRET); + + algorithmWithDifferentSecret = Algorithm.HMAC256(SECRET_NEW); + + verifier = JWT.require(algorithm) + .withIssuer(ISSUER) + .build(); + } + + private static boolean isJWTExpired(DecodedJWT decodedJWT) { + Date expiresAt = decodedJWT.getExpiresAt(); + return expiresAt.getTime() < System.currentTimeMillis(); + } + + private static DecodedJWT verifyJWT(String jwtToken) { + DecodedJWT decodedJWT = verifier.verify(jwtToken); + return decodedJWT; + } + + @Test + public void givenJWT_whenNotExpired_thenCheckingIfNotExpired() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withClaim(DATA_CLAIM, DATA) + .withExpiresAt(new Date(System.currentTimeMillis() + 1000L)) + .sign(algorithm); + + DecodedJWT decodedJWT = verifyJWT(jwtToken); + assertNotNull(decodedJWT); + assertFalse(isJWTExpired(decodedJWT)); + } + + @Test + public void givenJWT_whenExpired_thenCheckingIfExpired() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withClaim(DATA_CLAIM, DATA) + .withExpiresAt(new Date(System.currentTimeMillis() - 1000L)) + .sign(algorithm); + + assertThrows(TokenExpiredException.class, () -> { + verifyJWT(jwtToken); + }); + } + + @Test + public void givenJWT_whenCreatedWithCustomClaim_thenCheckingForCustomClaim() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withClaim(DATA_CLAIM, DATA) + .withExpiresAt(new Date(System.currentTimeMillis() + 1000L)) + .sign(algorithm); + + DecodedJWT decodedJWT = verifyJWT(jwtToken); + assertNotNull(decodedJWT); + + Claim claim = decodedJWT.getClaim(DATA_CLAIM); + assertEquals(DATA, claim.asString()); + } + + @Test + public void givenJWT_whenCreatedWithNotBefore_thenThrowException() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withClaim(DATA_CLAIM, DATA) + .withNotBefore(new Date(System.currentTimeMillis() + 1000L)) + .sign(algorithm); + + assertThrows(IncorrectClaimException.class, () -> { + verifyJWT(jwtToken); + }); + } + + @Test + public void givenJWT_whenVerifyingUsingDifferentSecret_thenThrowException() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withClaim(DATA_CLAIM, DATA) + .withExpiresAt(new Date(System.currentTimeMillis() + 1000L)) + .sign(algorithmWithDifferentSecret); + + assertThrows(SignatureVerificationException.class, () -> { + verifyJWT(jwtToken); + }); + } +} diff --git a/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/JWTDecodeUnitTest.java b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/JWTDecodeUnitTest.java new file mode 100644 index 0000000000..8e51de63dc --- /dev/null +++ b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/JWTDecodeUnitTest.java @@ -0,0 +1,71 @@ +package com.baeldung.jwt.auth0; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Date; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; + +public class JWTDecodeUnitTest { + + private static final String SECRET = "baeldung"; + private static final String ISSUER = "Baeldung"; + private static final long TOKEN_VALIDITY_IN_MILLIS = 1000L; + + private static Algorithm algorithm; + private static JWTVerifier verifier; + private static String jwtToken; + + @BeforeAll + public static void setUp() { + algorithm = Algorithm.HMAC256(SECRET); + + verifier = JWT.require(algorithm) + .withIssuer(ISSUER) + .build(); + } + + private static boolean isJWTExpired(DecodedJWT decodedJWT) { + Date expiresAt = decodedJWT.getExpiresAt(); + return expiresAt.before(new Date()); + } + + private static DecodedJWT decodedJWT(String jwtToken) { + return JWT.decode(jwtToken); + } + + @Test + public void givenNotExpiredJWT_whenDecoded_thenCheckingIfNotExpired() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withExpiresAt(new Date(System.currentTimeMillis() + TOKEN_VALIDITY_IN_MILLIS)) + .sign(algorithm); + + DecodedJWT decodedJWT = decodedJWT(jwtToken); + assertNotNull(decodedJWT); + assertFalse(isJWTExpired(decodedJWT)); + } + + @Test + public void givenExpiredJWT_whenDecoded_thenCheckingIfExpired() { + + jwtToken = JWT.create() + .withIssuer(ISSUER) + .withExpiresAt(new Date(System.currentTimeMillis() - TOKEN_VALIDITY_IN_MILLIS)) + .sign(algorithm); + + DecodedJWT decodedJWT = decodedJWT(jwtToken); + assertNotNull(decodedJWT); + assertTrue(isJWTExpired(decodedJWT)); + } + +} diff --git a/security-modules/pom.xml b/security-modules/pom.xml index 480ee0819e..ed88ef842e 100644 --- a/security-modules/pom.xml +++ b/security-modules/pom.xml @@ -20,8 +20,13 @@ jee-7-security jjwt + jwt oauth2-framework-impl sql-injection-samples + + 3.3.2 + + \ No newline at end of file diff --git a/security-modules/sql-injection-samples/.gitignore b/security-modules/sql-injection-samples/.gitignore index 82eca336e3..c167b56208 100644 --- a/security-modules/sql-injection-samples/.gitignore +++ b/security-modules/sql-injection-samples/.gitignore @@ -22,4 +22,7 @@ /nbbuild/ /dist/ /nbdist/ -/.nb-gradle/ \ No newline at end of file +/.nb-gradle/ + +derby.log + diff --git a/apache-tomcat/pom.xml b/server-modules/apache-tomcat/pom.xml similarity index 86% rename from apache-tomcat/pom.xml rename to server-modules/apache-tomcat/pom.xml index 36487f2108..6d93a4a636 100644 --- a/apache-tomcat/pom.xml +++ b/server-modules/apache-tomcat/pom.xml @@ -3,16 +3,13 @@ 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 apache-tomcat - 1.0.0-SNAPSHOT apache-tomcat pom com.baeldung - parent-modules + server-modules 1.0.0-SNAPSHOT @@ -31,4 +28,5 @@ + \ No newline at end of file diff --git a/apache-tomcat/sso/.dockerignore b/server-modules/apache-tomcat/sso/.dockerignore similarity index 100% rename from apache-tomcat/sso/.dockerignore rename to server-modules/apache-tomcat/sso/.dockerignore diff --git a/apache-tomcat/sso/README.md b/server-modules/apache-tomcat/sso/README.md similarity index 100% rename from apache-tomcat/sso/README.md rename to server-modules/apache-tomcat/sso/README.md diff --git a/apache-tomcat/sso/docker-compose.yml b/server-modules/apache-tomcat/sso/docker-compose.yml similarity index 100% rename from apache-tomcat/sso/docker-compose.yml rename to server-modules/apache-tomcat/sso/docker-compose.yml diff --git a/apache-tomcat/sso/pom.xml b/server-modules/apache-tomcat/sso/pom.xml similarity index 98% rename from apache-tomcat/sso/pom.xml rename to server-modules/apache-tomcat/sso/pom.xml index d46fe45f66..e11c22efc9 100644 --- a/apache-tomcat/sso/pom.xml +++ b/server-modules/apache-tomcat/sso/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.apache_tomcat sso 1.0.0-SNAPSHOT @@ -15,4 +14,4 @@ 1.0.0-SNAPSHOT - + \ No newline at end of file diff --git a/apache-tomcat/sso/res/conf/catalina.policy b/server-modules/apache-tomcat/sso/res/conf/catalina.policy similarity index 100% rename from apache-tomcat/sso/res/conf/catalina.policy rename to server-modules/apache-tomcat/sso/res/conf/catalina.policy diff --git a/apache-tomcat/sso/res/conf/catalina.properties b/server-modules/apache-tomcat/sso/res/conf/catalina.properties similarity index 100% rename from apache-tomcat/sso/res/conf/catalina.properties rename to server-modules/apache-tomcat/sso/res/conf/catalina.properties diff --git a/apache-tomcat/sso/res/conf/context.xml b/server-modules/apache-tomcat/sso/res/conf/context.xml similarity index 100% rename from apache-tomcat/sso/res/conf/context.xml rename to server-modules/apache-tomcat/sso/res/conf/context.xml diff --git a/apache-tomcat/sso/res/conf/jaspic-providers.xml b/server-modules/apache-tomcat/sso/res/conf/jaspic-providers.xml similarity index 100% rename from apache-tomcat/sso/res/conf/jaspic-providers.xml rename to server-modules/apache-tomcat/sso/res/conf/jaspic-providers.xml diff --git a/apache-tomcat/sso/res/conf/jaspic-providers.xsd b/server-modules/apache-tomcat/sso/res/conf/jaspic-providers.xsd similarity index 100% rename from apache-tomcat/sso/res/conf/jaspic-providers.xsd rename to server-modules/apache-tomcat/sso/res/conf/jaspic-providers.xsd diff --git a/apache-tomcat/sso/res/conf/logging.properties b/server-modules/apache-tomcat/sso/res/conf/logging.properties similarity index 100% rename from apache-tomcat/sso/res/conf/logging.properties rename to server-modules/apache-tomcat/sso/res/conf/logging.properties diff --git a/apache-tomcat/sso/res/conf/server.xml b/server-modules/apache-tomcat/sso/res/conf/server.xml similarity index 100% rename from apache-tomcat/sso/res/conf/server.xml rename to server-modules/apache-tomcat/sso/res/conf/server.xml diff --git a/apache-tomcat/sso/res/conf/tomcat-users.xml b/server-modules/apache-tomcat/sso/res/conf/tomcat-users.xml similarity index 100% rename from apache-tomcat/sso/res/conf/tomcat-users.xml rename to server-modules/apache-tomcat/sso/res/conf/tomcat-users.xml diff --git a/apache-tomcat/sso/res/conf/tomcat-users.xsd b/server-modules/apache-tomcat/sso/res/conf/tomcat-users.xsd similarity index 100% rename from apache-tomcat/sso/res/conf/tomcat-users.xsd rename to server-modules/apache-tomcat/sso/res/conf/tomcat-users.xsd diff --git a/apache-tomcat/sso/res/conf/web.xml b/server-modules/apache-tomcat/sso/res/conf/web.xml similarity index 100% rename from apache-tomcat/sso/res/conf/web.xml rename to server-modules/apache-tomcat/sso/res/conf/web.xml diff --git a/apache-tomcat/sso/webapps/ping/WEB-INF/web.xml b/server-modules/apache-tomcat/sso/webapps/ping/WEB-INF/web.xml similarity index 100% rename from apache-tomcat/sso/webapps/ping/WEB-INF/web.xml rename to server-modules/apache-tomcat/sso/webapps/ping/WEB-INF/web.xml diff --git a/apache-tomcat/sso/webapps/ping/index.html b/server-modules/apache-tomcat/sso/webapps/ping/index.html similarity index 100% rename from apache-tomcat/sso/webapps/ping/index.html rename to server-modules/apache-tomcat/sso/webapps/ping/index.html diff --git a/apache-tomcat/sso/webapps/ping/logging.html b/server-modules/apache-tomcat/sso/webapps/ping/logging.html similarity index 100% rename from apache-tomcat/sso/webapps/ping/logging.html rename to server-modules/apache-tomcat/sso/webapps/ping/logging.html diff --git a/apache-tomcat/sso/webapps/ping/logging_error.html b/server-modules/apache-tomcat/sso/webapps/ping/logging_error.html similarity index 100% rename from apache-tomcat/sso/webapps/ping/logging_error.html rename to server-modules/apache-tomcat/sso/webapps/ping/logging_error.html diff --git a/apache-tomcat/sso/webapps/ping/private/index.html b/server-modules/apache-tomcat/sso/webapps/ping/private/index.html similarity index 100% rename from apache-tomcat/sso/webapps/ping/private/index.html rename to server-modules/apache-tomcat/sso/webapps/ping/private/index.html diff --git a/apache-tomcat/sso/webapps/pong/WEB-INF/web.xml b/server-modules/apache-tomcat/sso/webapps/pong/WEB-INF/web.xml similarity index 100% rename from apache-tomcat/sso/webapps/pong/WEB-INF/web.xml rename to server-modules/apache-tomcat/sso/webapps/pong/WEB-INF/web.xml diff --git a/apache-tomcat/sso/webapps/pong/index.html b/server-modules/apache-tomcat/sso/webapps/pong/index.html similarity index 100% rename from apache-tomcat/sso/webapps/pong/index.html rename to server-modules/apache-tomcat/sso/webapps/pong/index.html diff --git a/apache-tomcat/sso/webapps/pong/private/index.html b/server-modules/apache-tomcat/sso/webapps/pong/private/index.html similarity index 100% rename from apache-tomcat/sso/webapps/pong/private/index.html rename to server-modules/apache-tomcat/sso/webapps/pong/private/index.html diff --git a/netty/README.md b/server-modules/netty/README.md similarity index 100% rename from netty/README.md rename to server-modules/netty/README.md diff --git a/netty/pom.xml b/server-modules/netty/pom.xml similarity index 91% rename from netty/pom.xml rename to server-modules/netty/pom.xml index c235ec9f4a..401bd2cb61 100644 --- a/netty/pom.xml +++ b/server-modules/netty/pom.xml @@ -4,12 +4,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 netty - 0.0.1-SNAPSHOT netty com.baeldung - parent-modules + server-modules 1.0.0-SNAPSHOT diff --git a/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java b/server-modules/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java similarity index 100% rename from netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java rename to server-modules/netty/src/main/java/com/baeldung/http/server/CustomHttpServerHandler.java diff --git a/netty/src/main/java/com/baeldung/http/server/HttpServer.java b/server-modules/netty/src/main/java/com/baeldung/http/server/HttpServer.java similarity index 100% rename from netty/src/main/java/com/baeldung/http/server/HttpServer.java rename to server-modules/netty/src/main/java/com/baeldung/http/server/HttpServer.java diff --git a/netty/src/main/java/com/baeldung/http/server/RequestUtils.java b/server-modules/netty/src/main/java/com/baeldung/http/server/RequestUtils.java similarity index 100% rename from netty/src/main/java/com/baeldung/http/server/RequestUtils.java rename to server-modules/netty/src/main/java/com/baeldung/http/server/RequestUtils.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/Http2Util.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/Http2Util.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/Http2Util.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/Http2Util.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientInitializer.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientInitializer.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientInitializer.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientInitializer.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientResponseHandler.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientResponseHandler.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientResponseHandler.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2ClientResponseHandler.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/client/Http2SettingsHandler.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2SettingsHandler.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/client/Http2SettingsHandler.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/client/Http2SettingsHandler.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/server/Http2Server.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/server/Http2Server.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/server/Http2Server.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/server/Http2Server.java diff --git a/netty/src/main/java/com/baeldung/netty/http2/server/Http2ServerResponseHandler.java b/server-modules/netty/src/main/java/com/baeldung/netty/http2/server/Http2ServerResponseHandler.java similarity index 100% rename from netty/src/main/java/com/baeldung/netty/http2/server/Http2ServerResponseHandler.java rename to server-modules/netty/src/main/java/com/baeldung/netty/http2/server/Http2ServerResponseHandler.java diff --git a/spring-webflux-amqp/src/main/resources/logback.xml b/server-modules/netty/src/main/resources/logback.xml similarity index 100% rename from spring-webflux-amqp/src/main/resources/logback.xml rename to server-modules/netty/src/main/resources/logback.xml diff --git a/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java b/server-modules/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java similarity index 100% rename from netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java rename to server-modules/netty/src/test/java/com/baeldung/http/server/HttpServerLiveTest.java diff --git a/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java b/server-modules/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java similarity index 100% rename from netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java rename to server-modules/netty/src/test/java/com/baeldung/http/server/ResponseAggregator.java diff --git a/netty/src/test/java/com/baeldung/netty/Http2ClientLiveTest.java b/server-modules/netty/src/test/java/com/baeldung/netty/Http2ClientLiveTest.java similarity index 100% rename from netty/src/test/java/com/baeldung/netty/Http2ClientLiveTest.java rename to server-modules/netty/src/test/java/com/baeldung/netty/Http2ClientLiveTest.java diff --git a/server-modules/pom.xml b/server-modules/pom.xml new file mode 100644 index 0000000000..fa69c9637a --- /dev/null +++ b/server-modules/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + server-modules + server-modules + pom + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + + apache-tomcat + netty + undertow + wildfly + + + \ No newline at end of file diff --git a/undertow/README.md b/server-modules/undertow/README.md similarity index 100% rename from undertow/README.md rename to server-modules/undertow/README.md diff --git a/undertow/pom.xml b/server-modules/undertow/pom.xml similarity index 94% rename from undertow/pom.xml rename to server-modules/undertow/pom.xml index 47e512daad..7d446c29d2 100644 --- a/undertow/pom.xml +++ b/server-modules/undertow/pom.xml @@ -5,14 +5,12 @@ 4.0.0 com.baeldung.undertow undertow - 1.0-SNAPSHOT undertow jar - http://maven.apache.org com.baeldung - parent-modules + server-modules 1.0.0-SNAPSHOT diff --git a/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java b/server-modules/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java similarity index 100% rename from undertow/src/main/java/com/baeldung/undertow/SimpleServer.java rename to server-modules/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java diff --git a/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java b/server-modules/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java similarity index 100% rename from undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java rename to server-modules/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java diff --git a/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java b/server-modules/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java similarity index 100% rename from undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java rename to server-modules/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java diff --git a/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java b/server-modules/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java similarity index 100% rename from undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java rename to server-modules/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java diff --git a/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java b/server-modules/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java similarity index 100% rename from undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java rename to server-modules/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java diff --git a/stripe/src/main/resources/logback.xml b/server-modules/undertow/src/main/resources/logback.xml similarity index 100% rename from stripe/src/main/resources/logback.xml rename to server-modules/undertow/src/main/resources/logback.xml diff --git a/wildfly/README.md b/server-modules/wildfly/README.md similarity index 100% rename from wildfly/README.md rename to server-modules/wildfly/README.md diff --git a/wildfly/pom.xml b/server-modules/wildfly/pom.xml similarity index 91% rename from wildfly/pom.xml rename to server-modules/wildfly/pom.xml index eaec4d176c..af742c7bd3 100644 --- a/wildfly/pom.xml +++ b/server-modules/wildfly/pom.xml @@ -13,7 +13,7 @@ com.baeldung parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-2 + ../../parent-boot-2 @@ -63,6 +63,7 @@ org.apache.maven.plugins maven-war-plugin + ${maven-war-plugin.version} @@ -74,4 +75,8 @@ + + 3.3.2 + + \ No newline at end of file diff --git a/wildfly/src/main/java/hello/Application.java b/server-modules/wildfly/src/main/java/hello/Application.java similarity index 100% rename from wildfly/src/main/java/hello/Application.java rename to server-modules/wildfly/src/main/java/hello/Application.java diff --git a/wildfly/src/main/java/hello/HelloController.java b/server-modules/wildfly/src/main/java/hello/HelloController.java similarity index 100% rename from wildfly/src/main/java/hello/HelloController.java rename to server-modules/wildfly/src/main/java/hello/HelloController.java diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java index 7fc3732ba5..9bf934b504 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java @@ -1,22 +1,22 @@ package com.baeldung.webflux.caching; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; -import reactor.cache.CacheMono; + import reactor.core.publisher.Mono; @Service public class ItemService { private final ItemRepository repository; - private final LoadingCache cache; + private final LoadingCache> cache; public ItemService(ItemRepository repository) { this.repository = repository; - this.cache = Caffeine.newBuilder() - .build(this::getItem_withAddons); + this.cache = Caffeine.newBuilder().build(this::getItem_withCaffeine); } @Cacheable("items") @@ -34,9 +34,7 @@ public class ItemService { } @Cacheable("items") - public Mono getItem_withAddons(String id) { - return CacheMono.lookup(cache.asMap(), id) - .onCacheMissResume(() -> repository.findById(id).cast(Object.class)).cast(Item.class); + public Mono getItem_withCaffeine(String id) { + return cache.asMap().computeIfAbsent(id, k -> repository.findById(id).cast(Item.class)); } - } diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java index 028a6d33a3..2075c1e77e 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java @@ -73,19 +73,19 @@ public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { } @Test - public void givenItem_whenGetItemWithAddonsIsCalled_thenMonoResultIsCached() { + public void givenItem_whenGetItemWithCaffeineIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); String id = glass.block().get_id(); - Mono mono = itemService.getItem_withAddons(id); + Mono mono = itemService.getItem_withCaffeine(id); Item item = mono.block(); assertThat(item).isNotNull(); assertThat(item.getName()).isEqualTo("glass"); assertThat(item.getPrice()).isEqualTo(1.00); - Mono mono2 = itemService.getItem_withAddons(id); + Mono mono2 = itemService.getItem_withCaffeine(id); Item item2 = mono2.block(); assertThat(item2).isNotNull(); diff --git a/spring-activiti/pom.xml b/spring-activiti/pom.xml index 9de7e473f8..b7fdfdfc60 100644 --- a/spring-activiti/pom.xml +++ b/spring-activiti/pom.xml @@ -9,12 +9,10 @@ Demo project for Spring Boot - - com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../parent-boot-1 + ../parent-boot-2 @@ -32,18 +30,21 @@ org.activiti - activiti-spring-boot-starter-basic - ${activiti.version} - - - org.activiti - activiti-spring-boot-starter-security + activiti-spring-boot-starter ${activiti.version} + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-thymeleaf + + org.springframework.boot + spring-boot-starter-security + com.h2database h2 @@ -70,7 +71,7 @@ - 6.0.0 + 7.1.0.M6 2.17.1 diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/ProcessController.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/config/ProcessController.java index 671b246328..c680af304d 100644 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/ProcessController.java +++ b/spring-activiti/src/main/java/com/baeldung/activiti/security/config/ProcessController.java @@ -2,14 +2,11 @@ package com.baeldung.activiti.security.config; import java.util.List; -import org.activiti.engine.IdentityService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; -import org.activiti.spring.SpringProcessEngineConfiguration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -22,21 +19,9 @@ public class ProcessController { @Autowired private TaskService taskService; - @Autowired - private IdentityService identityService; - - @Autowired - SpringProcessEngineConfiguration config; - @GetMapping("/protected-process") public String startProcess() { - String userId = SecurityContextHolder.getContext() - .getAuthentication() - .getName(); - - identityService.setAuthenticatedUserId(userId); - ProcessInstance pi = runtimeService.startProcessInstanceByKey("protected-process"); List usertasks = taskService.createTaskQuery() diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityGroupManager.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityGroupManager.java deleted file mode 100644 index 00fc674e22..0000000000 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityGroupManager.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.baeldung.activiti.security.config; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.activiti.engine.identity.Group; -import org.activiti.engine.identity.GroupQuery; -import org.activiti.engine.impl.GroupQueryImpl; -import org.activiti.engine.impl.Page; -import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.activiti.engine.impl.persistence.entity.GroupEntityImpl; -import org.activiti.engine.impl.persistence.entity.GroupEntityManagerImpl; -import org.activiti.engine.impl.persistence.entity.data.GroupDataManager; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.provisioning.JdbcUserDetailsManager; - -public class SpringSecurityGroupManager extends GroupEntityManagerImpl { - - private JdbcUserDetailsManager userManager; - - public SpringSecurityGroupManager(ProcessEngineConfigurationImpl processEngineConfiguration, GroupDataManager groupDataManager) { - super(processEngineConfiguration, groupDataManager); - } - - @Override - public List findGroupByQueryCriteria(GroupQueryImpl query, Page page) { - - if (query.getUserId() != null) { - return findGroupsByUser(query.getUserId()); - } - return null; - } - - @Override - public long findGroupCountByQueryCriteria(GroupQueryImpl query) { - return findGroupByQueryCriteria(query, null).size(); - } - - @Override - public List findGroupsByUser(String userId) { - UserDetails userDetails = userManager.loadUserByUsername(userId); - System.out.println("group manager"); - if (userDetails != null) { - List groups = userDetails.getAuthorities() - .stream() - .map(a -> a.getAuthority()) - .map(a -> { - Group g = new GroupEntityImpl(); - g.setId(a); - return g; - }) - .collect(Collectors.toList()); - return groups; - } - return null; - } - - public void setUserManager(JdbcUserDetailsManager userManager) { - this.userManager = userManager; - } - - public Group createNewGroup(String groupId) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - - @Override - public void delete(String groupId) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - - public GroupQuery createNewGroupQuery() { - throw new UnsupportedOperationException("This operation is not supported!"); - } - - public List findGroupsByNativeQuery(Map parameterMap, int firstResult, int maxResults) { - throw new UnsupportedOperationException("This operation is not supported!"); - } - - public long findGroupCountByNativeQuery(Map parameterMap) { - throw new UnsupportedOperationException("This operation is not supported!"); - } - -} diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityUserManager.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityUserManager.java deleted file mode 100644 index ce9863eb6c..0000000000 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/config/SpringSecurityUserManager.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.baeldung.activiti.security.config; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.activiti.engine.identity.Group; -import org.activiti.engine.identity.User; -import org.activiti.engine.identity.UserQuery; -import org.activiti.engine.impl.Page; -import org.activiti.engine.impl.UserQueryImpl; -import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.activiti.engine.impl.persistence.entity.GroupEntityImpl; -import org.activiti.engine.impl.persistence.entity.UserEntity; -import org.activiti.engine.impl.persistence.entity.UserEntityImpl; -import org.activiti.engine.impl.persistence.entity.UserEntityManagerImpl; -import org.activiti.engine.impl.persistence.entity.data.UserDataManager; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.provisioning.JdbcUserDetailsManager; - -public class SpringSecurityUserManager extends UserEntityManagerImpl { - - private JdbcUserDetailsManager userManager; - - public SpringSecurityUserManager(ProcessEngineConfigurationImpl processEngineConfiguration, UserDataManager userDataManager, JdbcUserDetailsManager userManager) { - super(processEngineConfiguration, userDataManager); - this.userManager = userManager; - } - - @Override - public UserEntity findById(String userId) { - UserDetails userDetails = userManager.loadUserByUsername(userId); - if (userDetails != null) { - UserEntityImpl user = new UserEntityImpl(); - user.setId(userId); - return user; - } - return null; - - } - - @Override - public List findUserByQueryCriteria(UserQueryImpl query, Page page) { - List users = null; - if (query.getGroupId() != null) { - users = userManager.findUsersInGroup(query.getGroupId()) - .stream() - .map(username -> { - User user = new UserEntityImpl(); - user.setId(username); - return user; - }) - .collect(Collectors.toList()); - if (page != null) { - return users.subList(page.getFirstResult(), page.getFirstResult() + page.getMaxResults()); - - } - return users; - } - - if (query.getId() != null) { - UserDetails userDetails = userManager.loadUserByUsername(query.getId()); - if (userDetails != null) { - UserEntityImpl user = new UserEntityImpl(); - user.setId(query.getId()); - return Collections.singletonList(user); - } - } - return null; - } - - @Override - public Boolean checkPassword(String userId, String password) { - return true; - } - - public void setUserManager(JdbcUserDetailsManager userManager) { - this.userManager = userManager; - } - - public User createNewUser(String userId) { - throw new UnsupportedOperationException("This operation is not supported!"); - } - - public void updateUser(User updatedUser) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - - public void delete(UserEntity userEntity) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - - @Override - public void deletePicture(User user) { - UserEntity userEntity = (UserEntity) user; - if (userEntity.getPictureByteArrayRef() != null) { - userEntity.getPictureByteArrayRef() - .delete(); - } - } - - public void delete(String userId) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - - public long findUserCountByQueryCriteria(UserQueryImpl query) { - return findUserByQueryCriteria(query, null).size(); - } - - public List findGroupsByUser(String userId) { - UserDetails userDetails = userManager.loadUserByUsername(userId); - if (userDetails != null) { - List groups = userDetails.getAuthorities() - .stream() - .map(a -> a.getAuthority()) - .map(a -> { - Group g = new GroupEntityImpl(); - g.setId(a); - return g; - }) - .collect(Collectors.toList()); - return groups; - } - return null; - } - - public UserQuery createNewUserQuery() { - throw new UnsupportedOperationException("This operation is not supported!"); - } - - public List findUsersByNativeQuery(Map parameterMap, int firstResult, int maxResults) { - throw new UnsupportedOperationException("This operation is not supported!"); - } - - public long findUserCountByNativeQuery(Map parameterMap) { - throw new UnsupportedOperationException("This operation is not supported!"); - - } - -} diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SecurityConfig.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SecurityConfig.java deleted file mode 100644 index f471600553..0000000000 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SecurityConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.activiti.security.withactiviti; - -import org.activiti.engine.IdentityService; -import org.activiti.spring.security.IdentityServiceUserDetailsService; -import org.springframework.beans.factory.annotation.Autowired; -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.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -@Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - protected void configure(HttpSecurity http) throws Exception { - http.antMatcher("/**") - .authorizeRequests() - .antMatchers("/protected-process*") - .authenticated() - .anyRequest() - .permitAll() - .and() - .formLogin() - .loginPage("/login") - .defaultSuccessUrl("/homepage") - .failureUrl("/login?error=true") - .and() - .csrf() - .disable() - .logout() - .logoutSuccessUrl("/login"); - } - - @Autowired - private IdentityService identityService; - - @Bean - public IdentityServiceUserDetailsService userDetailsService() { - return new IdentityServiceUserDetailsService(identityService); - } - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService()); - } - -} diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SpringSecurityActivitiApplication.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SpringSecurityActivitiApplication.java deleted file mode 100644 index 2270a4d684..0000000000 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/withactiviti/SpringSecurityActivitiApplication.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.activiti.security.withactiviti; - -import org.activiti.engine.IdentityService; -import org.activiti.engine.identity.Group; -import org.activiti.engine.identity.User; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; - -@SpringBootApplication(scanBasePackages = { "com.baeldung.activiti.security.config", "com.baeldung.activiti.security.withactiviti" }) -public class SpringSecurityActivitiApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringSecurityActivitiApplication.class, args); - } - - @Bean - InitializingBean usersAndGroupsInitializer(IdentityService identityService) { - return new InitializingBean() { - public void afterPropertiesSet() throws Exception { - User user = identityService.newUser("activiti_user"); - user.setPassword("pass"); - identityService.saveUser(user); - - Group group = identityService.newGroup("user"); - group.setName("ROLE_USER"); - group.setType("USER"); - identityService.saveGroup(group); - identityService.createMembership(user.getId(), group.getId()); - } - }; - } -} diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/ActivitiSpringSecurityApplication.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/ActivitiSpringSecurityApplication.java deleted file mode 100644 index 5878a5d678..0000000000 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/ActivitiSpringSecurityApplication.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.baeldung.activiti.security.withspring; - -import org.activiti.engine.impl.persistence.entity.data.impl.MybatisGroupDataManager; -import org.activiti.engine.impl.persistence.entity.data.impl.MybatisUserDataManager; -import org.activiti.spring.SpringProcessEngineConfiguration; -import org.activiti.spring.boot.SecurityAutoConfiguration; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.security.provisioning.JdbcUserDetailsManager; - -import com.baeldung.activiti.security.config.SpringSecurityGroupManager; -import com.baeldung.activiti.security.config.SpringSecurityUserManager; - -@SpringBootApplication(exclude = SecurityAutoConfiguration.class, scanBasePackages = { "com.baeldung.activiti.security.config", "com.baeldung.activiti.security.withspring" }) -public class ActivitiSpringSecurityApplication { - - public static void main(String[] args) { - SpringApplication.run(ActivitiSpringSecurityApplication.class, args); - } - - @Autowired - private SpringProcessEngineConfiguration processEngineConfiguration; - - @Autowired - private JdbcUserDetailsManager userManager; - - @Bean - InitializingBean processEngineInitializer() { - return new InitializingBean() { - public void afterPropertiesSet() throws Exception { - processEngineConfiguration.setUserEntityManager(new SpringSecurityUserManager(processEngineConfiguration, new MybatisUserDataManager(processEngineConfiguration), userManager)); - processEngineConfiguration.setGroupEntityManager(new SpringSecurityGroupManager(processEngineConfiguration, new MybatisGroupDataManager(processEngineConfiguration))); - } - }; - } -} diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SecurityConfig.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SecurityConfig.java index df1991c3e4..8dc3eee05e 100644 --- a/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SecurityConfig.java +++ b/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SecurityConfig.java @@ -1,22 +1,19 @@ package com.baeldung.activiti.security.withspring; -import javax.sql.DataSource; - -import org.springframework.beans.factory.annotation.Autowired; 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.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.provisioning.JdbcUserDetailsManager; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; @Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - @Autowired - private DataSource dataSource; - - protected void configure(HttpSecurity http) throws Exception { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/protected-process*") @@ -33,18 +30,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .disable() .logout() .logoutSuccessUrl("/login"); + return http.build(); } @Bean - public JdbcUserDetailsManager userDetailsManager() { - JdbcUserDetailsManager manager = new JdbcUserDetailsManager(); - manager.setDataSource(dataSource); - return manager; - } + public UserDetailsService userDetailsService() { + UserDetails user = User.withUsername("user") + .password("{noop}pass") + .authorities("ROLE_ACTIVITI_USER") + .build(); - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsManager()); + return new InMemoryUserDetailsManager(user); } - } diff --git a/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SpringSecurityActivitiApplication.java b/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SpringSecurityActivitiApplication.java new file mode 100644 index 0000000000..84aa4b2b0d --- /dev/null +++ b/spring-activiti/src/main/java/com/baeldung/activiti/security/withspring/SpringSecurityActivitiApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.activiti.security.withspring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = { "com.baeldung.activiti.security.config", "com.baeldung.activiti.security.withspring" }) +public class SpringSecurityActivitiApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityActivitiApplication.class, args); + } + +} diff --git a/spring-activiti/src/main/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplication.java b/spring-activiti/src/main/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplication.java index d43ae3cc35..b3cf66b0f7 100644 --- a/spring-activiti/src/main/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplication.java +++ b/spring-activiti/src/main/java/com/baeldung/activitiwithspring/ActivitiWithSpringApplication.java @@ -2,9 +2,8 @@ package com.baeldung.activitiwithspring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; -@SpringBootApplication(exclude = {SecurityAutoConfiguration.class}) +@SpringBootApplication public class ActivitiWithSpringApplication { public static void main(String[] args) { SpringApplication.run(ActivitiWithSpringApplication.class, args); diff --git a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java index 7f99483fcf..43a159efbd 100644 --- a/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java +++ b/spring-activiti/src/test/java/com/baeldung/activitiwithspring/ActivitiSpringSecurityIntegrationTest.java @@ -1,33 +1,22 @@ package com.baeldung.activitiwithspring; -import org.activiti.engine.IdentityService; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; -import com.baeldung.activiti.security.withspring.ActivitiSpringSecurityApplication; +import com.baeldung.activiti.security.withspring.SpringSecurityActivitiApplication; @RunWith(SpringRunner.class) -@SpringBootTest(classes = ActivitiSpringSecurityApplication.class) +@SpringBootTest(classes = SpringSecurityActivitiApplication.class) @WebAppConfiguration @AutoConfigureTestDatabase public class ActivitiSpringSecurityIntegrationTest { - @Autowired - private IdentityService identityService; @Test - public void whenUserExists_thenOk() { - identityService.setUserPicture("spring_user", null); - } - - @Test(expected = UsernameNotFoundException.class) - public void whenUserNonExistent_thenSpringException() { - identityService.setUserPicture("user3", null); + public void contextLoads() { } } diff --git a/spring-aop-2/pom.xml b/spring-aop-2/pom.xml index 76e4780e72..cb84ed4ca2 100644 --- a/spring-aop-2/pom.xml +++ b/spring-aop-2/pom.xml @@ -39,8 +39,22 @@ + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + + + + - 1.11 + 1.14.0 + 3.3.2 \ No newline at end of file diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index 0d48c479ca..ae5ab5fce1 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -69,11 +69,20 @@ + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + - 1.11 + 1.14.0 + 3.3.2 \ No newline at end of file diff --git a/spring-apache-camel/.gitignore b/spring-apache-camel/.gitignore deleted file mode 100644 index eac473ac50..0000000000 --- a/spring-apache-camel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/src/test/destination-folder/* \ No newline at end of file diff --git a/spring-apache-camel/pom.xml b/spring-apache-camel/pom.xml deleted file mode 100644 index de7bd1287a..0000000000 --- a/spring-apache-camel/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - 4.0.0 - org.apache.camel - spring-apache-camel - 1.0-SNAPSHOT - spring-apache-camel - jar - http://maven.apache.org - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - org.apache.camel - camel-core - ${env.camel.version} - - - org.apache.camel - camel-spring - ${env.camel.version} - - - commons-logging - commons-logging - - - - - org.apache.camel - camel-stream - ${env.camel.version} - - - org.springframework - spring-context - ${env.spring.version} - - - org.apache.camel - camel-spring-javaconfig - ${env.camel.version} - - - org.apache.camel - camel-jackson - ${env.camel.version} - - - org.apache.camel - camel-test - ${env.camel.version} - test - - - - - 2.18.1 - 4.3.4.RELEASE - - - \ No newline at end of file diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index b11c2c9afb..7fdfac4b93 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -50,6 +50,8 @@ spring-boot-keycloak-2 spring-boot-libraries spring-boot-libraries-2 + spring-boot-process-automation + spring-boot-logging-logback spring-boot-logging-log4j2 spring-boot-mvc spring-boot-mvc-2 @@ -66,6 +68,7 @@ spring-boot-properties-3 spring-boot-properties-migrator-demo spring-boot-property-exp + spring-boot-request-params spring-boot-runtime spring-boot-runtime-2 spring-boot-security @@ -81,6 +84,7 @@ spring-boot-data-2 spring-boot-validation spring-boot-data-3 + spring-caching diff --git a/spring-boot-modules/spring-boot-3-native/README.md b/spring-boot-modules/spring-boot-3-native/README.md new file mode 100644 index 0000000000..025a40c1d0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-native/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [Native Images with Spring Boot and GraalVM](https://www.baeldung.com/spring-native-intro) +- [Ahead of Time Optimizations in Spring 6](https://www.baeldung.com/spring-6-ahead-of-time-optimizations) diff --git a/spring-boot-modules/spring-boot-3-native/pom.xml b/spring-boot-modules/spring-boot-3-native/pom.xml index 9e664efc02..5382b8413c 100644 --- a/spring-boot-modules/spring-boot-3-native/pom.xml +++ b/spring-boot-modules/spring-boot-3-native/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-native 0.0.1-SNAPSHOT @@ -12,7 +12,7 @@ com.baeldung parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-3/pom.xml + ../../parent-boot-3 @@ -23,7 +23,7 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - ${spring-doc.version} + ${springdoc.version} org.springframework.boot @@ -47,13 +47,28 @@ true - - - + + + + + + + - - - + + + + native @@ -77,10 +92,9 @@ - 3.0.0-RC2 - 2.0.0-RC1 + 2.0.0 + 3.0.0-M7 0.9.17 - com.baeldung.sample.TodoApplication - + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-observation/README.md b/spring-boot-modules/spring-boot-3-observation/README.md new file mode 100644 index 0000000000..edfb23ce2b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Observability with Spring Boot 3](https://www.baeldung.com/spring-boot-3-observability) diff --git a/spring-boot-modules/spring-boot-3-observation/pom.xml b/spring-boot-modules/spring-boot-3-observation/pom.xml new file mode 100644 index 0000000000..ed613ee98e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + spring-boot-3-observation + 0.0.1-SNAPSHOT + spring-boot-3-observation + Demo project for Spring Boot 3 Observation + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + io.micrometer + micrometer-tracing + + + io.micrometer + micrometer-tracing-bridge-brave + + + + io.micrometer + micrometer-observation-test + test + + + io.micrometer + micrometer-tracing-test + test + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/GreetingApplication.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/GreetingApplication.java new file mode 100644 index 0000000000..f5014a8abd --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/GreetingApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.samples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GreetingApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/SimpleObservationApplication.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/SimpleObservationApplication.java new file mode 100644 index 0000000000..4434535939 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/SimpleObservationApplication.java @@ -0,0 +1,66 @@ +package com.baeldung.samples; + +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.ObservationTextPublisher; + +import java.util.Optional; +import java.util.stream.StreamSupport; + +public class SimpleObservationApplication { + + // we can run this as a simple command line application + public static void main(String[] args) { + // create registry + final var observationRegistry = ObservationRegistry.create(); + // create meter registry and observation handler + final var meterRegistry = new SimpleMeterRegistry(); + final var meterObservationHandler = new DefaultMeterObservationHandler(meterRegistry); + // create simple logging observation handler + final var loggingObservationHandler = new ObservationTextPublisher(System.out::println); + // register observation handlers + observationRegistry + .observationConfig() + .observationHandler(meterObservationHandler) + .observationHandler(loggingObservationHandler); + // make an observation + Observation.Context context = new Observation.Context(); + String observationName = "obs1"; + Observation observation = Observation + .createNotStarted(observationName, () -> context, observationRegistry) + .lowCardinalityKeyValue("gender", "male") + .highCardinalityKeyValue("age", "41"); + + for (int i = 0; i < 10; i++) { + observation.observe(SimpleObservationApplication::doSomeAction); + } + + meterRegistry.getMeters().forEach(m -> { + System.out.println(m.getId() + "\n============"); + m.measure().forEach(ms -> System.out.println(ms.getValue() + " [" + ms.getStatistic() + "]")); + System.out.println("----------------------------"); + }); + Optional maximumDuration = meterRegistry.getMeters().stream() + .filter(m -> "obs1".equals(m.getId().getName())) + .flatMap(m -> StreamSupport.stream(m.measure().spliterator(), false)) + .filter(ms -> ms.getStatistic() == Statistic.MAX) + .findFirst() + .map(Measurement::getValue); + + System.out.println(maximumDuration); + } + + private static void doSomeAction() { + try { + Thread.sleep(Math.round(Math.random() * 1000)); + System.out.println("Hello World!"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/GreetingController.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/GreetingController.java new file mode 100644 index 0000000000..bc179540f8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/GreetingController.java @@ -0,0 +1,26 @@ +package com.baeldung.samples.boundary; + +import com.baeldung.samples.domain.GreetingService; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping("/greet") +public class GreetingController { + + private final GreetingService service; + + public GreetingController(GreetingService service) { + this.service = service; + } + + @GetMapping(produces = MediaType.TEXT_PLAIN_VALUE) + @ResponseBody + public String sayHello() { + return this.service.sayHello(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/ObservationFilterConfiguration.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/ObservationFilterConfiguration.java new file mode 100644 index 0000000000..c39af961a1 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/boundary/ObservationFilterConfiguration.java @@ -0,0 +1,22 @@ +package com.baeldung.samples.boundary; + +import io.micrometer.observation.ObservationRegistry; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ServerHttpObservationFilter; + +@Configuration +public class ObservationFilterConfiguration { + + // if an ObservationRegistry is already configured + @ConditionalOnBean(ObservationRegistry.class) + // if we do not use Actuator + @ConditionalOnMissingBean(ServerHttpObservationFilter.class) + @Bean + public ServerHttpObservationFilter observationFilter(ObservationRegistry registry) { + return new ServerHttpObservationFilter(registry); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationHandlerLogger.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationHandlerLogger.java new file mode 100644 index 0000000000..0a1f52f9c1 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationHandlerLogger.java @@ -0,0 +1,28 @@ +package com.baeldung.samples.config; + +import io.micrometer.observation.ObservationHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +public class ObservationHandlerLogger { + + private static final Logger log = LoggerFactory.getLogger(ObservationHandlerLogger.class); + + private static String toString(ObservationHandler handler) { + return handler.getClass().getName() + " [ " + handler + "]"; + } + + @EventListener(ContextRefreshedEvent.class) + public void logObservationHandlers(ContextRefreshedEvent evt) { + evt.getApplicationContext().getBeansOfType(ObservationHandler.class) + .values() + .stream() + .map(ObservationHandlerLogger::toString) + .forEach(log::info); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationTextPublisherConfiguration.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationTextPublisherConfiguration.java new file mode 100644 index 0000000000..29637166c9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservationTextPublisherConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.samples.config; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationHandler; +import io.micrometer.observation.ObservationTextPublisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ObservationTextPublisherConfiguration { + + private static final Logger log = LoggerFactory.getLogger(ObservationTextPublisherConfiguration.class); + + @Bean + public ObservationHandler observationTextPublisher() { + return new ObservationTextPublisher(log::info); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservedAspectConfiguration.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservedAspectConfiguration.java new file mode 100644 index 0000000000..cd475113c7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/ObservedAspectConfiguration.java @@ -0,0 +1,20 @@ +package com.baeldung.samples.config; + +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.aop.ObservedAspect; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; + +@AutoConfiguration +@ConditionalOnClass(ObservedAspect.class) +public class ObservedAspectConfiguration { + + @Bean + @ConditionalOnMissingBean + public ObservedAspect observedAspect(ObservationRegistry observationRegistry) { + return new ObservedAspect(observationRegistry); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/SimpleLoggingHandler.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/SimpleLoggingHandler.java new file mode 100644 index 0000000000..c87aa68085 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/config/SimpleLoggingHandler.java @@ -0,0 +1,59 @@ +package com.baeldung.samples.config; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class SimpleLoggingHandler implements ObservationHandler { + + private static final Logger log = LoggerFactory.getLogger(SimpleLoggingHandler.class); + + private static String toString(Observation.Context context) { + return null == context ? "(no context)" : context.getName() + + " (" + context.getClass().getName() + "@" + System.identityHashCode(context) + ")"; + } + + private static String toString(Observation.Event event) { + return null == event ? "(no event)" : event.getName(); + } + + @Override + public boolean supportsContext(Observation.Context context) { + return true; + } + + @Override + public void onStart(Observation.Context context) { + log.info("Starting context " + toString(context)); + } + + @Override + public void onError(Observation.Context context) { + log.info("Error for context " + toString(context)); + } + + @Override + public void onEvent(Observation.Event event, Observation.Context context) { + log.info("Event for context " + toString(context) + " [" + toString(event) + "]"); + } + + @Override + public void onScopeOpened(Observation.Context context) { + log.info("Scope opened for context " + toString(context)); + + } + + @Override + public void onScopeClosed(Observation.Context context) { + log.info("Scope closed for context " + toString(context)); + } + + @Override + public void onStop(Observation.Context context) { + log.info("Stopping context " + toString(context)); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/domain/GreetingService.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/domain/GreetingService.java new file mode 100644 index 0000000000..ec362dd3cc --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/samples/domain/GreetingService.java @@ -0,0 +1,14 @@ +package com.baeldung.samples.domain; + +import io.micrometer.observation.annotation.Observed; +import org.springframework.stereotype.Service; + +@Observed(name = "greetingService") +@Service +public class GreetingService { + + public String sayHello() { + return "Hello World!"; + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-observation/src/main/resources/application.yml new file mode 100644 index 0000000000..9f91e8a03a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/resources/application.yml @@ -0,0 +1,6 @@ +management: + endpoints: + web: + exposure: + include: '*' + #health,info,beans,metrics,startup diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/config/SimpleLoggingHandlerUnitTest.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/config/SimpleLoggingHandlerUnitTest.java new file mode 100644 index 0000000000..5a6d1bd23f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/config/SimpleLoggingHandlerUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.samples.config; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationHandler; +import io.micrometer.observation.tck.AnyContextObservationHandlerCompatibilityKit; + +class SimpleLoggingHandlerUnitTest + extends AnyContextObservationHandlerCompatibilityKit { + + SimpleLoggingHandler handler = new SimpleLoggingHandler(); + + @Override + public ObservationHandler handler() { + return handler; + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/EnableTestObservation.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/EnableTestObservation.java new file mode 100644 index 0000000000..8e4e2a1da0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/EnableTestObservation.java @@ -0,0 +1,44 @@ +package com.baeldung.samples.domain; + +import com.baeldung.samples.config.ObservedAspectConfiguration; +import io.micrometer.observation.tck.TestObservationRegistry; +import io.micrometer.tracing.test.simple.SimpleTracer; +import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@AutoConfigureObservability +@Import({ + ObservedAspectConfiguration.class, + EnableTestObservation.ObservationTestConfiguration.class +}) +public @interface EnableTestObservation { + + @TestConfiguration + class ObservationTestConfiguration { + + @Bean + TestObservationRegistry observationRegistry() { + return TestObservationRegistry.create(); + } + + @Bean + SimpleTracer simpleTracer() { + return new SimpleTracer(); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceObservationIntegrationTest.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceObservationIntegrationTest.java new file mode 100644 index 0000000000..98fa175660 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceObservationIntegrationTest.java @@ -0,0 +1,35 @@ +package com.baeldung.samples.domain; + +import io.micrometer.observation.tck.TestObservationRegistry; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat; + +@ExtendWith(SpringExtension.class) +@ComponentScan(basePackageClasses = GreetingService.class) +@EnableAutoConfiguration +@EnableTestObservation +class GreetingServiceObservationIntegrationTest { + + @Autowired + GreetingService service; + @Autowired + TestObservationRegistry registry; + + @Test + void testObservation() { + // invoke service + service.sayHello(); + assertThat(registry) + .hasObservationWithNameEqualTo("greetingService") + .that() + .hasBeenStarted() + .hasBeenStopped(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceTracingIntegrationTest.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceTracingIntegrationTest.java new file mode 100644 index 0000000000..0199c0e7ef --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/samples/domain/GreetingServiceTracingIntegrationTest.java @@ -0,0 +1,42 @@ +package com.baeldung.samples.domain; + +import io.micrometer.tracing.test.simple.SimpleTracer; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static io.micrometer.tracing.test.simple.TracerAssert.assertThat; + +@ExtendWith(SpringExtension.class) +@ComponentScan(basePackageClasses = GreetingService.class) +@EnableAutoConfiguration +@EnableTestObservation +class GreetingServiceTracingIntegrationTest { + + @Autowired + GreetingService service; + @Value("${management.tracing.enabled:true}") + boolean tracingEnabled; + @Autowired + SimpleTracer tracer; + + @Test + void testEnabledTracing() { + Assertions.assertThat(tracingEnabled).isTrue(); + } + + @Test + void testTracingForGreeting() { + service.sayHello(); + assertThat(tracer) + .onlySpan() + .hasNameEqualTo("greeting-service#say-hello") + .isEnded(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/README.md b/spring-boot-modules/spring-boot-3-test-pitfalls/README.md new file mode 100644 index 0000000000..1290cbfcc7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Pitfalls on Testing with Spring Boot](https://www.baeldung.com/spring-boot-testing-pitfalls) diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml new file mode 100644 index 0000000000..90e4ba022a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + spring-boot-3-test-pitfalls + 0.0.1-SNAPSHOT + spring-boot-3-test-pitfalls + Demo project for Spring Boot Testing Pitfalls + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + true + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + + + + + + + + 1.5.3.Final + 3.0.0-M7 + + + + diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java new file mode 100644 index 0000000000..17ba1abb2e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PetsApplication { + + public static void main(String[] args) { + SpringApplication.run(PetsApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java new file mode 100644 index 0000000000..62b1202ce8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.boundary; + +import lombok.Data; + +@Data +public class PetDto { + + private String name; + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java new file mode 100644 index 0000000000..07fbb77f2e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.Pet; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface PetDtoMapper { + + PetDto map(Pet source); + + Pet map(PetDto source); + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java new file mode 100644 index 0000000000..d95d43028b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java @@ -0,0 +1,28 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collection; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/pets") +@RequiredArgsConstructor +public class PetsController { + + private final PetService service; + private final PetDtoMapper mapper; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public Collection readAll() { + return service.getPets().stream() + .map(mapper::map) + .collect(Collectors.toList()); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java new file mode 100644 index 0000000000..3dfe5e1a47 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java @@ -0,0 +1,4 @@ +package com.baeldung.sample.pets.domain; + +public record Pet(String name) { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java new file mode 100644 index 0000000000..c5f83047b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java @@ -0,0 +1,14 @@ +package com.baeldung.sample.pets.domain; + +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class PetService { + + @Delegate + private final PetServiceRepository repo; + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java new file mode 100644 index 0000000000..1900f72a1c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets.domain; + +import java.util.Collection; + +public interface PetServiceRepository { + + boolean add(Pet pet); + + void clear(); + + Collection getPets(); + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java new file mode 100644 index 0000000000..d1d4bba175 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java @@ -0,0 +1,29 @@ +package com.baeldung.sample.pets.domain; + +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Component +public class PetServiceRepositoryImpl implements PetServiceRepository { + + private final Set pets = new HashSet<>(); + + @Override + public Set getPets() { + return Collections.unmodifiableSet(pets); + } + + @Override + public boolean add(Pet pet) { + return this.pets.add(pet); + } + + @Override + public void clear() { + this.pets.clear(); + } + +} diff --git a/patterns-modules/hexagonal-architecture/src/main/resources/application.properties b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml similarity index 100% rename from patterns-modules/hexagonal-architecture/src/main/resources/application.properties rename to spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java new file mode 100644 index 0000000000..14b12cb6e9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +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.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@ExtendWith(SpringExtension.class) +public class PetDtoMapperIntegrationTest { + + @Configuration + @ComponentScan(basePackageClasses = PetDtoMapper.class) + static class PetDtoMapperTestConfig { + + /* + * This would be necessary because the controller is also initialized + * and needs the service, although we do not want to test it here. + * + * Solutions: + * - place the mapper into a separate sub package + * - do not test the mapper separately, test it integrated within the controller + * (recommended) + */ + @Bean + PetService createServiceMock() { + return mock(PetService.class, MockReset.withSettings(MockReset.AFTER)); + } + + } + + @Autowired + PetDtoMapper mapper; + + @Test + void shouldExist() { // simply test correct test setup + assertThat(mapper).isNotNull(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java new file mode 100644 index 0000000000..2a83b364c3 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.boundary; + +import org.springframework.context.annotation.ComponentScan; + +/** + * Just an interface to use for compiler-checked component scanning during tests. + * @see ComponentScan#basePackageClasses() + */ +public interface PetsBoundaryLayer { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java new file mode 100644 index 0000000000..9a5df7b727 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +import com.baeldung.sample.test.slices.PetsBoundaryTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.Collections; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@PetsBoundaryTest +class PetsControllerMvcIntegrationTest { + + @Autowired + MockMvc mvc; + @Autowired + PetService service; + + @Test + void shouldReturnEmptyArrayWhenGetPets() throws Exception { + when(service.getPets()).thenReturn(Collections.emptyList()); + mvc.perform( + get("/pets") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("[]")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java new file mode 100644 index 0000000000..5e2ec41089 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.sample.pets.domain; + +import com.baeldung.sample.test.slices.PetsDomainTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@PetsDomainTest +class PetServiceIntegrationTest { + + @Autowired + PetService service; + @Autowired // Mock + PetServiceRepository repository; + + @Test + void shouldAddPetWhenNotAlreadyExisting() { + var pet = new Pet("Dog"); + when(repository.add(pet)).thenReturn(true); + var result = service.add(pet); + assertThat(result).isTrue(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java new file mode 100644 index 0000000000..b0ecdfaeb7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.sample.pets.domain; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PetServiceUnitTest { + + PetService service = new PetService(new PetServiceRepositoryImpl()); + + @Test + void shouldAddPetWhenNotAlreadyExisting() { + var pet = new Pet("Dog"); + var result = service.add(pet); + assertThat(result).isTrue(); + assertThat(service.getPets()).hasSize(1); + } + + @Test + void shouldNotAddPetWhenAlreadyExisting() { + var pet = new Pet("Cat"); + var result = service.add(pet); + assertThat(result).isTrue(); + // try a second time + result = service.add(pet); + assertThat(result).isFalse(); + assertThat(service.getPets()).hasSize(1); + } + + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java new file mode 100644 index 0000000000..f32fd189e0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.domain; + +import org.springframework.context.annotation.ComponentScan; + +/** + * Just an interface to use for compiler-checked component scanning during tests. + * @see ComponentScan#basePackageClasses() + */ +public interface PetsDomainLayer { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java new file mode 100644 index 0000000000..f58239f971 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java @@ -0,0 +1,52 @@ +package com.baeldung.sample.test.slices; + +import com.baeldung.sample.pets.boundary.PetsBoundaryLayer; +import com.baeldung.sample.pets.boundary.PetsController; +import com.baeldung.sample.pets.domain.PetService; +import org.junit.jupiter.api.Tag; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ActiveProfiles; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.mockito.Mockito.mock; + +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@WebMvcTest(controllers = PetsController.class) +@ComponentScan(basePackageClasses = PetsBoundaryLayer.class) +@Import(PetsBoundaryTest.PetBoundaryTestConfiguration.class) +// further features that can help to configure and execute tests +@ActiveProfiles({ "test", "boundary-test" }) +@Tag("integration-test") +@Tag("boundary-test") +public @interface PetsBoundaryTest { + + @TestConfiguration + class PetBoundaryTestConfiguration { + + @Primary + @Bean + PetService createPetServiceMock() { + return mock( + PetService.class, + MockReset.withSettings(MockReset.AFTER) + ); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java new file mode 100644 index 0000000000..b061889135 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java @@ -0,0 +1,52 @@ +package com.baeldung.sample.test.slices; + +import com.baeldung.sample.pets.domain.PetServiceRepository; +import com.baeldung.sample.pets.domain.PetsDomainLayer; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.mockito.Mockito.mock; + +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@ExtendWith(SpringExtension.class) +@ComponentScan(basePackageClasses = PetsDomainLayer.class) +@Import(PetsDomainTest.PetServiceTestConfiguration.class) +// further features that can help to configure and execute tests +@ActiveProfiles({"test", "domain-test"}) +@Tag("integration-test") +@Tag("domain-test") +public @interface PetsDomainTest { + + @TestConfiguration + class PetServiceTestConfiguration { + + @Primary + @Bean + PetServiceRepository createPetsRepositoryMock() { + return mock( + PetServiceRepository.class, + MockReset.withSettings(MockReset.AFTER) + ); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml new file mode 100644 index 0000000000..9801fe9e7e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml @@ -0,0 +1,11 @@ +logging: + level: + root: info + org: + springframework: + test: + context: + cache: DEBUG +spring: + main: + allow-bean-definition-overriding: true diff --git a/spring-boot-modules/spring-boot-3/README.md b/spring-boot-modules/spring-boot-3/README.md index ea30573163..5fa884a053 100644 --- a/spring-boot-modules/spring-boot-3/README.md +++ b/spring-boot-modules/spring-boot-3/README.md @@ -2,3 +2,5 @@ ### Relevant Articles: - [Spring Boot 3 and Spring Framework 6.0 – What’s New](https://www.baeldung.com/spring-boot-3-spring-6-new) +- [Singleton Design Pattern vs Singleton Beans in Spring Boot](https://www.baeldung.com/spring-boot-singleton-vs-beans) +- [Migrate Application From Spring Boot 2 to Spring Boot 3](https://www.baeldung.com/spring-boot-3-migration) diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index a5e9ca903c..cc8e7e1426 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -49,9 +49,11 @@ spring-boot-configuration-processor true - - - + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + org.projectlombok lombok @@ -120,7 +122,8 @@ 1.5.2.Final - com.baeldung.sample.TodoApplication + 2.0.0 + 3.0.0-M7 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/ServerConfiguration.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/ServerConfiguration.java new file mode 100644 index 0000000000..5533fe1b7d --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/ServerConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.sample.boundary; + +import org.apache.catalina.connector.Connector; +import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ServerConfiguration implements WebServerFactoryCustomizer { + + @Override + public void customize(TomcatServletWebServerFactory factory) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + @Override + public void customize(Connector connector) { + connector.setProperty("maxHttpResponseHeaderSize", "100000"); + } + }); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/TodosController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/TodosController.java index 7efa7dfee3..cf21303659 100644 --- a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/TodosController.java +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/TodosController.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RestController; import java.net.URI; import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; @@ -35,6 +36,13 @@ public class TodosController { // Mapping zwischen den Schichten private final TodoDtoMapper mapper; + + @GetMapping(value = {"/name"},produces = DEFAULT_MEDIA_TYPE) + public List findAllName(){ + return List.of("Hello", "World"); + } + + @GetMapping(produces = DEFAULT_MEDIA_TYPE) public Collection findAll() { return service.findAll().stream() @@ -80,4 +88,4 @@ public class TodosController { service.delete(id); } -} +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/WebConfiguration.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/WebConfiguration.java new file mode 100644 index 0000000000..24bbc223ae --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/boundary/WebConfiguration.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.boundary; + +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +public class WebConfiguration implements WebMvcConfigurer { + + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setUseTrailingSlashMatch(true); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/SingletonBeanConfig.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/SingletonBeanConfig.java new file mode 100644 index 0000000000..1c40097ba5 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/SingletonBeanConfig.java @@ -0,0 +1,29 @@ +package com.baeldung.sample.singleton; + +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +public class SingletonBeanConfig { + + @Bean + @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) + public SingletonBean singletonBean() { + return new SingletonBean(); + } + + @Bean + @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) + public SingletonBean anotherSingletonBean() { + return new SingletonBean(); + } + + static class SingletonBean { + public String getValue() { + return "test"; + } + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/ThreadSafeSingleInstance.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/ThreadSafeSingleInstance.java new file mode 100644 index 0000000000..ae6e85bf2b --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/sample/singleton/ThreadSafeSingleInstance.java @@ -0,0 +1,24 @@ +package com.baeldung.sample.singleton; + +public final class ThreadSafeSingleInstance { + + private static volatile ThreadSafeSingleInstance instance = null; + + private ThreadSafeSingleInstance() {} + + public static ThreadSafeSingleInstance getInstance() { + if (instance == null) { + synchronized(ThreadSafeSingleInstance.class) { + if (instance == null) { + instance = new ThreadSafeSingleInstance(); + } + } + } + return instance; + } + + public String getValue() { + return "test"; + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/boundary/TodosControllerApiIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/boundary/TodosControllerApiIntegrationTest.java index 680b6c85bb..3a80bc8a6c 100644 --- a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/boundary/TodosControllerApiIntegrationTest.java +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/boundary/TodosControllerApiIntegrationTest.java @@ -215,4 +215,18 @@ class TodosControllerApiIntegrationTest { .andExpect(status().isNotFound()); } + @Test + void whenThereIsNoSlashMatching_ThenHttpStatusIs404() throws Exception { + mvc + .perform(get(BASEURL + "/name/").contentType(DEFAULT_MEDIA_TYPE)) + .andExpect(status().isNotFound()); + } + + @Test + void whenThereIsNoSlashMatching_ThenHttpStatusIs200() throws Exception { + mvc + .perform(get(BASEURL + "/name").contentType(DEFAULT_MEDIA_TYPE)) + .andExpect(status().isOk()); + } + } diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/SingletonBeanUnitTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/SingletonBeanUnitTest.java new file mode 100644 index 0000000000..72c1ae4170 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/SingletonBeanUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.sample.singleton; + +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SingletonBeanUnitTest { + + @Autowired + @Qualifier("singletonBean") + private SingletonBeanConfig.SingletonBean beanOne; + + @Autowired + @Qualifier("singletonBean") + private SingletonBeanConfig.SingletonBean beanTwo; + + @Autowired + @Qualifier("anotherSingletonBean") + private SingletonBeanConfig.SingletonBean beanThree; + + @Test + void givenTwoBeansWithSameId_whenInjectingThem_thenSameInstancesAreReturned() { + assertSame(beanOne, beanTwo); + } + + @Test + void givenTwoBeansWithDifferentId_whenInjectingThem_thenDifferentInstancesAreReturned() { + assertNotSame(beanOne, beanThree); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/ThreadSafeSingleInstanceUnitTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/ThreadSafeSingleInstanceUnitTest.java new file mode 100644 index 0000000000..0753f92e31 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/sample/singleton/ThreadSafeSingleInstanceUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.sample.singleton; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertSame; + +class ThreadSafeSingleInstanceUnitTest { + + @Test + void givenTwoSingletonInstances_whenGettingThem_thenSameInstancesAreReturned() { + ThreadSafeSingleInstance instanceOne = ThreadSafeSingleInstance.getInstance(); + ThreadSafeSingleInstance instanceTwo = ThreadSafeSingleInstance.getInstance(); + assertSame(instanceOne, instanceTwo); + } + +} diff --git a/spring-boot-modules/spring-boot-artifacts-2/README.md b/spring-boot-modules/spring-boot-artifacts-2/README.md index 5d0a6ebcd1..a6601adc0f 100644 --- a/spring-boot-modules/spring-boot-artifacts-2/README.md +++ b/spring-boot-modules/spring-boot-artifacts-2/README.md @@ -6,4 +6,5 @@ This module contains articles about configuring the Spring Boot build process 2. - [Difference Between spring-boot:repackage and Maven package](https://www.baeldung.com/spring-boot-repackage-vs-mvn-package) - [Intro to Spring Boot Starters](https://www.baeldung.com/spring-boot-starters) +- [Fixing the No Main Manifest Attribute in Spring Boot](https://www.baeldung.com/spring-boot-fix-the-no-main-manifest-attribute) - More articles: [[<-- prev]](/spring-boot-modules/spring-boot-artifacts) diff --git a/spring-boot-modules/spring-boot-artifacts-2/pom.xml b/spring-boot-modules/spring-boot-artifacts-2/pom.xml index d0e12caa53..5fcee8d609 100644 --- a/spring-boot-modules/spring-boot-artifacts-2/pom.xml +++ b/spring-boot-modules/spring-boot-artifacts-2/pom.xml @@ -27,6 +27,10 @@ org.springframework.boot spring-boot-maven-plugin + + com.baeldung.demo.DemoApplication + JAR + diff --git a/spring-boot-modules/spring-boot-autoconfiguration/pom.xml b/spring-boot-modules/spring-boot-autoconfiguration/pom.xml index ef5d4f66dd..7a3f9f01e8 100644 --- a/spring-boot-modules/spring-boot-autoconfiguration/pom.xml +++ b/spring-boot-modules/spring-boot-autoconfiguration/pom.xml @@ -38,8 +38,8 @@ test - mysql - mysql-connector-java + com.mysql + mysql-connector-j org.springframework.boot diff --git a/spring-boot-modules/spring-boot-bootstrap/pom.xml b/spring-boot-modules/spring-boot-bootstrap/pom.xml index efcfcb71ee..4ceae26f60 100644 --- a/spring-boot-modules/spring-boot-bootstrap/pom.xml +++ b/spring-boot-modules/spring-boot-bootstrap/pom.xml @@ -32,8 +32,8 @@ h2 - mysql - mysql-connector-java + com.mysql + mysql-connector-j org.springframework.boot diff --git a/spring-boot-modules/spring-boot-camel/.gitignore b/spring-boot-modules/spring-boot-camel/.gitignore deleted file mode 100644 index 16be8f2193..0000000000 --- a/spring-boot-modules/spring-boot-camel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/output/ diff --git a/spring-boot-modules/spring-boot-camel/README.md b/spring-boot-modules/spring-boot-camel/README.md deleted file mode 100644 index d797f1a0b5..0000000000 --- a/spring-boot-modules/spring-boot-camel/README.md +++ /dev/null @@ -1,30 +0,0 @@ -## Spring Boot Camel - -This module contains articles about Spring Boot with Apache Camel - -### Example for the Article on Camel API with SpringBoot - -To start, run: - -`mvn spring-boot:run` - -Then, make a POST http request to: - -`http://localhost:8080/camel/api/bean` - -Include the HEADER: Content-Type: application/json, - -and a BODY Payload like: - -`{"id": 1,"name": "World"}` - -We will get a return code of 201 and the response: `Hello, World` - if the transform() method from Application class is uncommented and the process() method is commented - -or return code of 201 and the response: `{"id": 10,"name": "Hello, World"}` - if the transform() method from Application class is commented and the process() method is uncommented - -## Relevant articles: - -- [Apache Camel with Spring Boot](https://www.baeldung.com/apache-camel-spring-boot) -- [Apache Camel Routes Testing in Spring Boot](https://www.baeldung.com/spring-boot-apache-camel-routes-testing) -- [Apache Camel Conditional Routing](https://www.baeldung.com/spring-apache-camel-conditional-routing) -- [Apache Camel Exception Handling](https://www.baeldung.com/java-apache-camel-exception-handling) diff --git a/spring-boot-modules/spring-boot-camel/pom.xml b/spring-boot-modules/spring-boot-camel/pom.xml deleted file mode 100644 index ecf7143808..0000000000 --- a/spring-boot-modules/spring-boot-camel/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - 4.0.0 - com.example - spring-boot-camel - 0.0.1-SNAPSHOT - spring-boot-camel - - - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT - - - - - org.apache.camel.springboot - camel-servlet-starter - ${camel.version} - - - org.apache.camel.springboot - camel-jackson-starter - ${camel.version} - - - org.apache.camel.springboot - camel-swagger-java-starter - ${camel.version} - - - org.apache.camel.springboot - camel-spring-boot-starter - ${camel.version} - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - org.apache.camel - camel-test-spring-junit5 - ${camel.version} - test - - - - - spring-boot:run - - - org.springframework.boot - spring-boot-maven-plugin - - - - repackage - - - com.baeldung.camel.boot.testing.GreetingsFileSpringApplication - - - - - - - - - 11 - 3.15.0 - - - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-camel/src/main/resources/logback.xml b/spring-boot-modules/spring-boot-camel/src/main/resources/logback.xml deleted file mode 100644 index d0b4334f5a..0000000000 --- a/spring-boot-modules/spring-boot-camel/src/main/resources/logback.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/readonlyrepository/BookRepository.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/readonlyrepository/BookRepository.java index 363b310c8c..11a75ba881 100644 --- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/readonlyrepository/BookRepository.java +++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/readonlyrepository/BookRepository.java @@ -2,5 +2,5 @@ package com.baeldung.boot.readonlyrepository; import org.springframework.data.repository.CrudRepository; -public interface BookRepository extends BookReadOnlyRepository, CrudRepository { +public interface BookRepository extends CrudRepository { } diff --git a/spring-boot-modules/spring-boot-data-3/pom.xml b/spring-boot-modules/spring-boot-data-3/pom.xml index cac5016ebd..cf53c25697 100644 --- a/spring-boot-modules/spring-boot-data-3/pom.xml +++ b/spring-boot-modules/spring-boot-data-3/pom.xml @@ -25,8 +25,8 @@ spring-boot-starter-data-jpa - mysql - mysql-connector-java + com.mysql + mysql-connector-j runtime diff --git a/spring-boot-modules/spring-boot-graphql/README.md b/spring-boot-modules/spring-boot-graphql/README.md index cee4f7eae1..5f78461ce1 100644 --- a/spring-boot-modules/spring-boot-graphql/README.md +++ b/spring-boot-modules/spring-boot-graphql/README.md @@ -12,6 +12,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Error Handling in GraphQL With Spring Boot](https://www.baeldung.com/spring-graphql-error-handling) - [How to Test GraphQL Using Postman](https://www.baeldung.com/graphql-postman) - [GraphQL vs REST](https://www.baeldung.com/graphql-vs-rest) +- [REST vs. GraphQL vs. gRPC – Which API to Choose?](https://www.baeldung.com/rest-vs-graphql-vs-grpc) ### GraphQL sample queries diff --git a/spring-boot-modules/spring-boot-graphql/pom.xml b/spring-boot-modules/spring-boot-graphql/pom.xml index 32399f4123..bb475679ad 100644 --- a/spring-boot-modules/spring-boot-graphql/pom.xml +++ b/spring-boot-modules/spring-boot-graphql/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 spring-boot-graphql spring-boot-graphql @@ -13,6 +13,47 @@ 1.0.0-SNAPSHOT + + + + kr.motd.maven + os-maven-plugin + 1.7.0 + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-plugin.version} + + com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + + compile + compile-custom + + + + + + + + + 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 @@ -34,6 +75,27 @@ com.h2database h2 + + io.grpc + grpc-stub + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + + + jakarta.annotation + jakarta.annotation-api + ${jakarta.annotation.version} + true + + + net.devh + grpc-spring-boot-starter + ${grpc.spring.version} + org.springframework.boot spring-boot-starter-test @@ -49,6 +111,12 @@ spring-graphql-test test + + org.skyscreamer + jsonassert + ${jsonassert.version} + test + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/ChooseApiApp.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/ChooseApiApp.java new file mode 100644 index 0000000000..ded6a92597 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/ChooseApiApp.java @@ -0,0 +1,14 @@ +package com.baeldung.chooseapi; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ChooseApiApp { + + public static void main(String[] args) { + System.setProperty("spring.profiles.default", "chooseapi"); + SpringApplication.run(ChooseApiApp.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQL.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQL.java new file mode 100644 index 0000000000..1e5f226d45 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQL.java @@ -0,0 +1,25 @@ +package com.baeldung.chooseapi.controllers; + +import com.baeldung.chooseapi.dtos.Book; +import com.baeldung.chooseapi.services.BooksService; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import org.springframework.graphql.data.method.annotation.QueryMapping; + +@RestController +public class BooksControllerGraphQL { + + private final BooksService booksService; + + public BooksControllerGraphQL(BooksService booksService) { + this.booksService = booksService; + } + + @QueryMapping + public List books() { + return booksService.getBooks(); + } + +} + diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerRest.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerRest.java new file mode 100644 index 0000000000..78cc64b2f4 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/controllers/BooksControllerRest.java @@ -0,0 +1,24 @@ +package com.baeldung.chooseapi.controllers; + +import com.baeldung.chooseapi.dtos.Book; +import com.baeldung.chooseapi.services.BooksService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class BooksControllerRest { + + private final BooksService booksService; + + public BooksControllerRest(BooksService booksService) { + this.booksService = booksService; + } + + @GetMapping("/rest/books") + public List books() { + return booksService.getBooks(); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Author.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Author.java new file mode 100644 index 0000000000..498f727ec1 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Author.java @@ -0,0 +1,40 @@ +package com.baeldung.chooseapi.dtos; + +import java.util.Objects; + +public class Author { + + private final String firstName; + private final String lastName; + + public Author(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Author author = (Author) o; + return firstName.equals(author.firstName) && lastName.equals(author.lastName); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Book.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Book.java new file mode 100644 index 0000000000..0fd752c1ba --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/dtos/Book.java @@ -0,0 +1,46 @@ +package com.baeldung.chooseapi.dtos; + +import java.util.Objects; + +public class Book { + + private final String title; + private final Author author; + private final int year; + + public Book(String title, Author author, int year) { + this.title = title; + this.author = author; + this.year = year; + } + + public String getTitle() { + return title; + } + + public Author getAuthor() { + return author; + } + + public int getYear() { + return year; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + return year == book.year && title.equals(book.title) && author.equals(book.author); + } + + @Override + public int hashCode() { + return Objects.hash(title, author, year); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/BooksServiceGrpc.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/BooksServiceGrpc.java new file mode 100644 index 0000000000..c0b70e2adf --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/BooksServiceGrpc.java @@ -0,0 +1,32 @@ +package com.baeldung.chooseapi.grpc; + +import com.baeldung.chooseapi.BooksServiceGrpc.BooksServiceImplBase; +import com.baeldung.chooseapi.BooksServiceOuterClass.BooksRequest; +import com.baeldung.chooseapi.BooksServiceOuterClass.BooksResponse; + +import com.baeldung.chooseapi.dtos.Book; +import com.baeldung.chooseapi.services.BooksService; +import io.grpc.stub.StreamObserver; +import net.devh.boot.grpc.server.service.GrpcService; + +import java.util.List; + +@GrpcService +public class BooksServiceGrpc extends BooksServiceImplBase { + + private final BooksService booksService; + + public BooksServiceGrpc(BooksService booksService) { + this.booksService = booksService; + } + + @Override + public void books(BooksRequest request, StreamObserver responseObserver) { + List books = booksService.getBooks(); + BooksResponse.Builder responseBuilder = BooksResponse.newBuilder(); + books.forEach(book -> responseBuilder.addBook(GrpcBooksMapper.mapBookToProto(book))); + responseObserver.onNext(responseBuilder.build()); + responseObserver.onCompleted(); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/GrpcBooksMapper.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/GrpcBooksMapper.java new file mode 100644 index 0000000000..f66fb9c16c --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/grpc/GrpcBooksMapper.java @@ -0,0 +1,26 @@ +package com.baeldung.chooseapi.grpc; + +import com.baeldung.chooseapi.BooksServiceOuterClass; +import com.baeldung.chooseapi.dtos.Author; +import com.baeldung.chooseapi.dtos.Book; + +public class GrpcBooksMapper { + + public static BooksServiceOuterClass.BookProto mapBookToProto(Book book) { + return BooksServiceOuterClass.BookProto.newBuilder() + .setTitle(book.getTitle()) + .setAuthor(BooksServiceOuterClass.AuthorProto.newBuilder() + .setFirstName(book.getAuthor().getFirstName()) + .setLastName(book.getAuthor().getLastName()) + .build()) + .setYear(book.getYear()) + .build(); + } + + public static Book mapProtoToBook(BooksServiceOuterClass.BookProto bookProto) { + return new Book(bookProto.getTitle(), + new Author(bookProto.getAuthor().getFirstName(), bookProto.getAuthor().getLastName()), + bookProto.getYear()); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/services/BooksService.java b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/services/BooksService.java new file mode 100644 index 0000000000..d9094f53fd --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/java/com/baeldung/chooseapi/services/BooksService.java @@ -0,0 +1,26 @@ +package com.baeldung.chooseapi.services; + +import com.baeldung.chooseapi.dtos.Author; +import com.baeldung.chooseapi.dtos.Book; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Service +public class BooksService { + + private static final Author AUTHOR = new Author("Joanne", "Rowling"); + + private static final List BOOKS = new ArrayList<>(Arrays.asList( + new Book("Philosopher's Stone", AUTHOR, 1997), + new Book("Goblet of Fire", AUTHOR, 2000), + new Book("Deathly Hallows", AUTHOR, 2007) + )); + + public List getBooks() { + return BOOKS; + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/proto/BooksService.proto b/spring-boot-modules/spring-boot-graphql/src/main/proto/BooksService.proto new file mode 100644 index 0000000000..2bd2bd719d --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/proto/BooksService.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; +package com.baeldung.chooseapi; + +message BooksRequest {} + +message AuthorProto { + string firstName = 1; + string lastName = 2; +} + +message BookProto { + string title = 1; + AuthorProto author = 2; + int32 year = 3; +} + +message BooksResponse { + repeated BookProto book = 1; +} + +service BooksService { + rpc books(BooksRequest) returns (BooksResponse); +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-graphql/src/main/resources/application-chooseapi.yml b/spring-boot-modules/spring-boot-graphql/src/main/resources/application-chooseapi.yml new file mode 100644 index 0000000000..0036bb3284 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/resources/application-chooseapi.yml @@ -0,0 +1,11 @@ +server: + port: 8082 + +spring: + main: + allow-bean-definition-overriding: true + graphql: + graphiql: + enabled: true + schema: + locations: classpath:chooseapi/ diff --git a/spring-boot-modules/spring-boot-graphql/src/main/resources/chooseapi/chooseapi.graphqls b/spring-boot-modules/spring-boot-graphql/src/main/resources/chooseapi/chooseapi.graphqls new file mode 100644 index 0000000000..5b0e991d48 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/main/resources/chooseapi/chooseapi.graphqls @@ -0,0 +1,14 @@ +type Author { + firstName: String! + lastName: String! +} + +type Book { + title: String! + year: Int! + author: Author! +} + +type Query { + books: [Book] +} diff --git a/spring-boot-modules/spring-boot-graphql/src/main/resources/graphql-vs-rest/schema.graphqls b/spring-boot-modules/spring-boot-graphql/src/main/resources/graphql-vs-rest/schema.graphqls index 520f26648c..e11897fa6c 100644 --- a/spring-boot-modules/spring-boot-graphql/src/main/resources/graphql-vs-rest/schema.graphqls +++ b/spring-boot-modules/spring-boot-graphql/src/main/resources/graphql-vs-rest/schema.graphqls @@ -43,7 +43,6 @@ input ProductUpdateModel { stock: Int } - # The Root Query for the application type Query { products(size: Int, page: Int): [Product]! diff --git a/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQLIntegrationTest.java b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQLIntegrationTest.java new file mode 100644 index 0000000000..48ed73fbde --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerGraphQLIntegrationTest.java @@ -0,0 +1,35 @@ +package com.baeldung.chooseapi.controllers; + +import com.baeldung.chooseapi.ChooseApiApp; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.graphql.test.tester.HttpGraphQlTester; +import org.springframework.test.context.ActiveProfiles; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "grpc.server.port=-1" }, // Disable gRPC external server + classes = ChooseApiApp.class) +@ActiveProfiles("chooseapi") +class BooksControllerGraphQLIntegrationTest { + + @Autowired + private HttpGraphQlTester graphQlTester; + + @Test + void givenBooksServiceThatReturnThreeBooks_whenCallingGraphQLEndpoint_thenThreeBooksAreReturned() throws Exception { + String document = "query { books { title year author { firstName lastName }}}"; + Path expectedResponse = Paths.get("src/test/resources/graphql-test/books_expected_response.json"); + String expectedJson = new String(Files.readAllBytes(expectedResponse)); + + this.graphQlTester.document(document) + .execute() + .path("books") + .matchesJson(expectedJson); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerRestIntegrationTest.java b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerRestIntegrationTest.java new file mode 100644 index 0000000000..4f2f8e8e51 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/controllers/BooksControllerRestIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.chooseapi.controllers; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +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.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@SpringBootTest(properties = { "grpc.server.port=-1" }) // Disable gRPC external server +@ActiveProfiles("chooseapi") +@AutoConfigureMockMvc +class BooksControllerRestIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void givenBooksServiceThatReturnThreeBooks_whenCallingRestEndpoint_thenThreeBooksAreReturned() throws Exception { + Path expectedResponse = Paths.get("src/test/resources/graphql-test/books_expected_response.json"); + String expectedJson = new String(Files.readAllBytes(expectedResponse)); + + this.mockMvc.perform(get("/rest/books")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().json(expectedJson)); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/BooksServiceGrpcIntegrationTest.java b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/BooksServiceGrpcIntegrationTest.java new file mode 100644 index 0000000000..e446073cea --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/BooksServiceGrpcIntegrationTest.java @@ -0,0 +1,55 @@ +package com.baeldung.chooseapi.grpc; + +import com.baeldung.chooseapi.dtos.Book; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.devh.boot.grpc.client.inject.GrpcClient; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import com.baeldung.chooseapi.BooksServiceOuterClass.BooksRequest; +import com.baeldung.chooseapi.BooksServiceOuterClass.BooksResponse; + +import com.baeldung.chooseapi.BooksServiceGrpc.BooksServiceBlockingStub; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +@SpringBootTest(properties = { + "grpc.server.inProcessName=test", // Enable inProcess server + "grpc.server.port=-1", // Disable external server + "grpc.client.inProcess.address=in-process:test" // Configure the client to connect to the inProcess server +}) +@SpringJUnitConfig(GrpcIntegrationTestConfig.class) +@DirtiesContext // Ensures that the grpc-server is properly shutdown after each test +class BooksServiceGrpcIntegrationTest { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @GrpcClient("inProcess") + private BooksServiceBlockingStub booksServiceGrpc; + + @Test + @DirtiesContext + void givenBooksServiceThatReturnThreeBooks_whenCallingGrpcEndpoint_thenThreeBooksAreReturned() throws IOException, JSONException { + Path expectedResponse = Paths.get("src/test/resources/graphql-test/books_expected_response.json"); + String expectedJson = new String(Files.readAllBytes(expectedResponse)); + + BooksRequest request = BooksRequest.newBuilder().build(); + BooksResponse response = booksServiceGrpc.books(request); + + List books = response.getBookList().stream() + .map(GrpcBooksMapper::mapProtoToBook) + .collect(Collectors.toList()); + + JSONAssert.assertEquals(objectMapper.writeValueAsString(books), expectedJson, true); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/GrpcIntegrationTestConfig.java b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/GrpcIntegrationTestConfig.java new file mode 100644 index 0000000000..d70c6e46a5 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/test/java/com/baeldung/chooseapi/grpc/GrpcIntegrationTestConfig.java @@ -0,0 +1,28 @@ +package com.baeldung.chooseapi.grpc; + +import com.baeldung.chooseapi.services.BooksService; +import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration; +import net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration; +import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ImportAutoConfiguration({ + GrpcServerAutoConfiguration.class, // Create required server beans + GrpcServerFactoryAutoConfiguration.class, // Select server implementation + GrpcClientAutoConfiguration.class}) // Support @GrpcClient annotation +class GrpcIntegrationTestConfig { + + @Bean + BooksService booksService() { + return new BooksService(); + } + + @Bean + BooksServiceGrpc booksServiceGrpc() { + return new BooksServiceGrpc(booksService()); + } + +} diff --git a/spring-boot-modules/spring-boot-graphql/src/test/resources/graphql-test/books_expected_response.json b/spring-boot-modules/spring-boot-graphql/src/test/resources/graphql-test/books_expected_response.json new file mode 100644 index 0000000000..066795ee91 --- /dev/null +++ b/spring-boot-modules/spring-boot-graphql/src/test/resources/graphql-test/books_expected_response.json @@ -0,0 +1,26 @@ +[ + { + "title": "Philosopher's Stone", + "year": 1997, + "author": { + "firstName": "Joanne", + "lastName": "Rowling" + } + }, + { + "title": "Goblet of Fire", + "year": 2000, + "author": { + "firstName": "Joanne", + "lastName": "Rowling" + } + }, + { + "title": "Deathly Hallows", + "year": 2007, + "author": { + "firstName": "Joanne", + "lastName": "Rowling" + } + } +] \ 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 a119a09561..8b1eec2e4e 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-2/pom.xml @@ -17,18 +17,6 @@ ../../parent-boot-2 - - - - org.keycloak.bom - keycloak-adapter-bom - ${keycloak-adapter-bom.version} - pom - import - - - - org.springframework.boot @@ -39,8 +27,12 @@ spring-boot-starter-security - org.keycloak - keycloak-spring-boot-starter + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-oauth2-client org.springframework.boot @@ -58,8 +50,4 @@ - - 15.0.2 - - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakConfiguration.java b/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakConfiguration.java deleted file mode 100644 index a9a2ea6a18..0000000000 --- a/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakConfiguration.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.baeldung.disablingkeycloak; - -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class KeycloakConfiguration { - - @Bean - public KeycloakSpringBootConfigResolver keycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } -} diff --git a/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakSecurityConfig.java b/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakSecurityConfig.java index d48c99d8fd..b41b64077c 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakSecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak-2/src/main/java/com/baeldung/disablingkeycloak/KeycloakSecurityConfig.java @@ -1,38 +1,34 @@ package com.baeldung.disablingkeycloak; -import org.keycloak.adapters.springsecurity.KeycloakConfiguration; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; +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.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; -@KeycloakConfiguration +@Configuration +@EnableWebSecurity @ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true) -public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { +public class KeycloakSecurityConfig { - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - auth.authenticationProvider(keycloakAuthenticationProvider()); + @Bean + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new NullAuthenticatedSessionStrategy(); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - super.configure(http); - + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf() .disable() - .authorizeRequests() - .anyRequest() - .authenticated(); + .authorizeHttpRequests(auth -> auth.anyRequest() + .authenticated()); + http.oauth2Login(); + http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + return http.build(); } } diff --git a/spring-boot-modules/spring-boot-keycloak-2/src/main/resources/application-disabling-keycloak.properties b/spring-boot-modules/spring-boot-keycloak-2/src/main/resources/application-disabling-keycloak.properties index 21263cf725..1f08eac234 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/src/main/resources/application-disabling-keycloak.properties +++ b/spring-boot-modules/spring-boot-keycloak-2/src/main/resources/application-disabling-keycloak.properties @@ -1,7 +1,10 @@ -# Keycloak authentication is enabled for production. +server.port=8081 keycloak.enabled=true -keycloak.realm=SpringBootKeycloak -keycloak.auth-server-url=http://localhost:8180/auth -keycloak.resource=login-app -keycloak.bearer-only=true -keycloak.ssl-required=external + +spring.security.oauth2.client.registration.keycloak.client-id=login-app +spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.keycloak.scope=openid +spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak +spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username + +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/README.md b/spring-boot-modules/spring-boot-keycloak-adapters/README.md new file mode 100644 index 0000000000..d24d315f50 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/README.md @@ -0,0 +1,7 @@ +## Spring Boot Keycloak + +This module contains articles about Keycloak in Spring Boot projects. + +## Relevant articles: +- [Custom User Attributes with Keycloak](https://www.baeldung.com/keycloak-custom-user-attributes) +- [Get Keycloak User ID in Spring](https://www.baeldung.com/spring-keycloak-get-user-id) diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml new file mode 100644 index 0000000000..0da8d920d1 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + com.baeldung.keycloak + spring-boot-keycloak-adapters + 0.0.1 + spring-boot-keycloak-adapters + jar + This is a simple application demonstrating integration between Keycloak and Spring Boot. + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + + org.keycloak.bom + keycloak-adapter-bom + ${keycloak-adapter-bom.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter + + + org.keycloak + keycloak-spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.hsqldb + hsqldb + runtime + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 15.0.2 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java similarity index 100% rename from spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java rename to spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/Customer.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/Customer.java new file mode 100644 index 0000000000..3293446b1d --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/Customer.java @@ -0,0 +1,49 @@ +package com.baeldung.keycloak; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Customer { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; + private String serviceRendered; + private String address; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getServiceRendered() { + return serviceRendered; + } + + public void setServiceRendered(String serviceRendered) { + this.serviceRendered = serviceRendered; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + +} diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomerDAO.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomerDAO.java new file mode 100644 index 0000000000..20d992d335 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomerDAO.java @@ -0,0 +1,7 @@ +package com.baeldung.keycloak; + +import org.springframework.data.repository.CrudRepository; + +public interface CustomerDAO extends CrudRepository { + +} diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakConfig.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakConfig.java similarity index 100% rename from spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/KeycloakConfig.java rename to spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakConfig.java diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java new file mode 100644 index 0000000000..06c41e9b1d --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakLogoutHandler.java @@ -0,0 +1,45 @@ +package com.baeldung.keycloak; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.web.authentication.logout.LogoutHandler; +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; + +@Component +public class KeycloakLogoutHandler implements LogoutHandler { + + private static final Logger logger = LoggerFactory.getLogger(KeycloakLogoutHandler.class); + private final RestTemplate restTemplate; + + public KeycloakLogoutHandler(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) { + logoutFromKeycloak((OidcUser) auth.getPrincipal()); + } + + private void logoutFromKeycloak(OidcUser user) { + String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout"; + UriComponentsBuilder builder = UriComponentsBuilder + .fromUriString(endSessionEndpoint) + .queryParam("id_token_hint", user.getIdToken().getTokenValue()); + + ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class); + if (logoutResponse.getStatusCode().is2xxSuccessful()) { + logger.info("Successfulley logged out from Keycloak"); + } else { + logger.error("Could not propagate logout to Keycloak"); + } + } + +} diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java new file mode 100644 index 0000000000..c39e37cfaa --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -0,0 +1,41 @@ +package com.baeldung.keycloak; + +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.session.SessionRegistryImpl; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; + +@Configuration +@EnableWebSecurity +class SecurityConfig { + + private final KeycloakLogoutHandler keycloakLogoutHandler; + + SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) { + this.keycloakLogoutHandler = keycloakLogoutHandler; + } + + @Bean + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/customers*", "/users*") + .hasRole("USER") + .anyRequest() + .permitAll(); + http.oauth2Login() + .and() + .logout() + .addLogoutHandler(keycloakLogoutHandler) + .logoutSuccessUrl("/"); + return http.build(); + } +} diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SpringBoot.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SpringBoot.java new file mode 100644 index 0000000000..90d7e774a4 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SpringBoot.java @@ -0,0 +1,20 @@ +package com.baeldung.keycloak; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication + +public class SpringBoot { + + public static void main(String[] args) { + SpringApplication.run(SpringBoot.class, args); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/WebController.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/WebController.java new file mode 100644 index 0000000000..bbd96c8135 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/WebController.java @@ -0,0 +1,60 @@ +package com.baeldung.keycloak; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import java.security.Principal; + +import org.springframework.beans.factory.annotation.Autowired; + +import javax.servlet.http.HttpServletRequest; + +@Controller +public class WebController { + + @Autowired + private CustomerDAO customerDAO; + + @GetMapping(path = "/") + public String index() { + return "external"; + } + + @GetMapping("/logout") + public String logout(HttpServletRequest request) throws Exception { + request.logout(); + return "redirect:/"; + } + + @GetMapping(path = "/customers") + public String customers(Principal principal, Model model) { + addCustomers(); + Iterable customers = customerDAO.findAll(); + model.addAttribute("customers", customers); + model.addAttribute("username", principal.getName()); + return "customers"; + } + + // add customers for demonstration + public void addCustomers() { + + Customer customer1 = new Customer(); + customer1.setAddress("1111 foo blvd"); + customer1.setName("Foo Industries"); + customer1.setServiceRendered("Important services"); + customerDAO.save(customer1); + + Customer customer2 = new Customer(); + customer2.setAddress("2222 bar street"); + customer2.setName("Bar LLP"); + customer2.setServiceRendered("Important services"); + customerDAO.save(customer2); + + Customer customer3 = new Customer(); + customer3.setAddress("33 main street"); + customer3.setName("Big LLC"); + customer3.setServiceRendered("Important services"); + customerDAO.save(customer3); + } +} diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/resources/application-embedded.properties b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application-embedded.properties similarity index 100% rename from spring-boot-modules/spring-boot-keycloak/src/main/resources/application-embedded.properties rename to spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application-embedded.properties diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties new file mode 100644 index 0000000000..323617e2ef --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties @@ -0,0 +1,15 @@ +### server port +server.port=8081 + +#Keycloak Configuration +keycloak.auth-server-url=http://localhost:8180/auth +keycloak.realm=SpringBootKeycloak +keycloak.resource=login-app +keycloak.public-client=true +keycloak.principal-attribute=preferred_username + +spring.security.oauth2.client.registration.keycloak.client-id=login-app +spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.keycloak.scope=openid +spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/auth/realms/SpringBootKeycloak +spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username \ No newline at end of file diff --git a/twilio/src/main/resources/logback.xml b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/logback.xml similarity index 100% rename from twilio/src/main/resources/logback.xml rename to spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/logback.xml diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/customers.html b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/customers.html new file mode 100644 index 0000000000..de2df93ef1 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/customers.html @@ -0,0 +1,34 @@ + + + + + +
+

+ Hello, --name--. +

+ + + + + + + + + + + + + + + + + +
IDNameAddressService Rendered
Text ...Text ...Text ...Text...
+ + Logout +
+ + + diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/external.html b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/external.html new file mode 100644 index 0000000000..2f9cc76961 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/external.html @@ -0,0 +1,31 @@ + + + + + +
+
+

Customer Portal

+
+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam + erat lectus, vehicula feugiat ultricies at, tempus sed ante. Cras + arcu erat, lobortis vitae quam et, mollis pharetra odio. Nullam sit + amet congue ipsum. Nunc dapibus odio ut ligula venenatis porta non + id dui. Duis nec tempor tellus. Suspendisse id blandit ligula, sit + amet varius mauris. Nulla eu eros pharetra, tristique dui quis, + vehicula libero. Aenean a neque sit amet tellus porttitor rutrum nec + at leo.

+ +

Existing Customers

+
+ Enter the intranet: customers +
+
+ +
+ + + + diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/layout.html b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/layout.html new file mode 100644 index 0000000000..bab0c2982b --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/layout.html @@ -0,0 +1,18 @@ + + + +Customer Portal + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/resources/templates/userInfo.html b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html similarity index 100% rename from spring-boot-modules/spring-boot-keycloak/src/main/resources/templates/userInfo.html rename to spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java similarity index 100% rename from spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java rename to spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java diff --git a/spring-boot-modules/spring-boot-keycloak/README.md b/spring-boot-modules/spring-boot-keycloak/README.md index e95ada0e05..b4545e121c 100644 --- a/spring-boot-modules/spring-boot-keycloak/README.md +++ b/spring-boot-modules/spring-boot-keycloak/README.md @@ -4,9 +4,8 @@ This module contains articles about Keycloak in Spring Boot projects. ## Relevant articles: - [A Quick Guide to Using Keycloak With Spring Boot](https://www.baeldung.com/spring-boot-keycloak) -- [Custom User Attributes with Keycloak](https://www.baeldung.com/keycloak-custom-user-attributes) - [Customizing the Login Page for Keycloak](https://www.baeldung.com/keycloak-custom-login-page) - [Keycloak User Self-Registration](https://www.baeldung.com/keycloak-user-registration) - [Customizing Themes for Keycloak](https://www.baeldung.com/spring-keycloak-custom-themes) - [Securing SOAP Web Services With Keycloak](https://www.baeldung.com/soap-keycloak) -- [Get Keycloak User ID in Spring](https://www.baeldung.com/spring-keycloak-get-user-id) + diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index 4f30d32bec..34e93299ae 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -17,26 +17,10 @@ ../../parent-boot-2 - - - - org.keycloak.bom - keycloak-adapter-bom - ${keycloak-adapter-bom.version} - pom - import - - - - org.springframework.boot - spring-boot-starter - - - org.keycloak - keycloak-spring-boot-starter + spring-boot-starter-oauth2-resource-server org.springframework.boot @@ -105,16 +89,16 @@ com.baeldung - src/main/resources/products.xsd + /${project.basedir}/src/main/resources/products.xsd - - - 15.0.2 + + + com.baeldung.keycloak.SpringBoot \ No newline at end of file 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 c39e37cfaa..1ad22d9397 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,8 +2,11 @@ package com.baeldung.keycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; @@ -27,7 +30,7 @@ class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeRequests() - .antMatchers("/customers*", "/users*") + .antMatchers("/customers*") .hasRole("USER") .anyRequest() .permitAll(); @@ -36,6 +39,13 @@ class SecurityConfig { .logout() .addLogoutHandler(keycloakLogoutHandler) .logoutSuccessUrl("/"); + http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); } + + @Bean + public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { + return http.getSharedObject(AuthenticationManagerBuilder.class) + .build(); + } } diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java index 66a17f4967..e55d307e33 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java @@ -1,54 +1,27 @@ package com.baeldung.keycloaksoap; -import org.keycloak.adapters.KeycloakConfigResolver; -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; -import org.keycloak.adapters.springsecurity.KeycloakConfiguration; -import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; -import org.springframework.security.core.session.SessionRegistryImpl; -import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +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.web.SecurityFilterChain; -@KeycloakConfiguration +@Configuration +@EnableWebSecurity @ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true") @EnableGlobalMethodSecurity(jsr250Enabled = true) -public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - super.configure(http); - //@formatter:off - http - .csrf() - .disable() - .authorizeRequests() - .anyRequest() - .permitAll(); - //@formatter:on - } - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); - keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); - auth.authenticationProvider(keycloakAuthenticationProvider); - } +public class KeycloakSecurityConfig { @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf() + .disable() + .authorizeHttpRequests(auth -> auth.anyRequest() + .authenticated()) + .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + return http.build(); } - - @Bean - public KeycloakConfigResolver keycloakSpringBootConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } - } diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/resources/application-keycloak.properties b/spring-boot-modules/spring-boot-keycloak/src/main/resources/application-keycloak.properties index 0a28b7ac48..474e671ce3 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/resources/application-keycloak.properties +++ b/spring-boot-modules/spring-boot-keycloak/src/main/resources/application-keycloak.properties @@ -1,14 +1,8 @@ server.port=18080 keycloak.enabled=true -keycloak.realm=baeldung-soap-services -keycloak.auth-server-url=http://localhost:8080/auth -keycloak.bearer-only=true -keycloak.credentials.secret=14da6f9e-261f-489a-9bf0-1441e4a9ddc4 -keycloak.ssl-required=external -keycloak.resource=baeldung-soap-services -keycloak.use-resource-role-mappings=true +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/baeldung-soap-services # Custom properties begin here ws.api.path=/ws/api/v1/* diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/resources/application.properties b/spring-boot-modules/spring-boot-keycloak/src/main/resources/application.properties index 323617e2ef..df2fadabae 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/resources/application.properties +++ b/spring-boot-modules/spring-boot-keycloak/src/main/resources/application.properties @@ -1,15 +1,10 @@ ### server port server.port=8081 -#Keycloak Configuration -keycloak.auth-server-url=http://localhost:8180/auth -keycloak.realm=SpringBootKeycloak -keycloak.resource=login-app -keycloak.public-client=true -keycloak.principal-attribute=preferred_username - spring.security.oauth2.client.registration.keycloak.client-id=login-app spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.keycloak.scope=openid -spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/auth/realms/SpringBootKeycloak -spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username \ No newline at end of file +spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak +spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username + +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak \ No newline at end of file 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 new file mode 100644 index 0000000000..336c8364aa --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java @@ -0,0 +1,18 @@ +package com.baeldung.keycloak; + +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 }) +public class KeycloakContextIntegrationTest { + + @Test + public void whenLoadApplication_thenSuccess() { + + } + +} 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 0327915399..171c7bf330 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 @@ -105,7 +105,7 @@ class KeycloakSoapLiveTest { void givenAccessToken_whenDeleteProduct_thenReturnSuccess() { HttpHeaders headers = new HttpHeaders(); headers.set("content-type", "text/xml"); - headers.set("Authorization", "Bearer " + generateToken("jhondoe", "password")); + headers.set("Authorization", "Bearer " + generateToken("johndoe", "password")); HttpEntity request = new HttpEntity<>(Utility.getDeleteProductsRequest(), headers); ResponseEntity responseEntity = restTemplate.postForEntity("http://localhost:" + port + "/ws/api/v1/", request, String.class); diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/resources/application-test.properties b/spring-boot-modules/spring-boot-keycloak/src/test/resources/application-test.properties index a818b5be7a..609d59b4bf 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/test/resources/application-test.properties +++ b/spring-boot-modules/spring-boot-keycloak/src/test/resources/application-test.properties @@ -1,4 +1,7 @@ grant.type=password client.id=baeldung-soap-services client.secret=d2ba7af8-f7d2-4c97-b4a5-3c88b59920ae -url=http://localhost:8080/auth/realms/baeldung-soap-services/protocol/openid-connect/token +url=http://localhost:8080/realms/baeldung-soap-services/protocol/openid-connect/token + +keycloak.enabled=true +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/baeldung-soap-services diff --git a/spring-boot-modules/spring-boot-libraries/pom.xml b/spring-boot-modules/spring-boot-libraries/pom.xml index 7ac7043abc..d8ca53f013 100644 --- a/spring-boot-modules/spring-boot-libraries/pom.xml +++ b/spring-boot-modules/spring-boot-libraries/pom.xml @@ -226,8 +226,8 @@ 2.1 2.6.0 3.3.0 - 4.10.0 - 0.2.0 + 7.6.0 + 0.7.0 2.8.2 diff --git a/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/ratelimiting/bucket4japp/service/PricingPlanService.java b/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/ratelimiting/bucket4japp/service/PricingPlanService.java index 7d8a718601..c4f7747171 100644 --- a/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/ratelimiting/bucket4japp/service/PricingPlanService.java +++ b/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/ratelimiting/bucket4japp/service/PricingPlanService.java @@ -7,7 +7,6 @@ import org.springframework.stereotype.Service; import io.github.bucket4j.Bandwidth; import io.github.bucket4j.Bucket; -import io.github.bucket4j.Bucket4j; @Service public class PricingPlanService { @@ -24,7 +23,7 @@ public class PricingPlanService { } private Bucket bucket(Bandwidth limit) { - return Bucket4j.builder() + return Bucket.builder() .addLimit(limit) .build(); } diff --git a/spring-boot-modules/spring-boot-libraries/src/test/java/com/baeldung/ratelimiting/bucket4japp/Bucket4jUsageUnitTest.java b/spring-boot-modules/spring-boot-libraries/src/test/java/com/baeldung/ratelimiting/bucket4japp/Bucket4jUsageUnitTest.java index fbf63ba403..8b9fba6dd3 100644 --- a/spring-boot-modules/spring-boot-libraries/src/test/java/com/baeldung/ratelimiting/bucket4japp/Bucket4jUsageUnitTest.java +++ b/spring-boot-modules/spring-boot-libraries/src/test/java/com/baeldung/ratelimiting/bucket4japp/Bucket4jUsageUnitTest.java @@ -1,7 +1,7 @@ package com.baeldung.ratelimiting.bucket4japp; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; import java.util.concurrent.CountDownLatch; @@ -13,7 +13,6 @@ import org.junit.jupiter.api.Test; import io.github.bucket4j.Bandwidth; import io.github.bucket4j.Bucket; -import io.github.bucket4j.Bucket4j; import io.github.bucket4j.Refill; public class Bucket4jUsageUnitTest { @@ -22,7 +21,7 @@ public class Bucket4jUsageUnitTest { public void givenBucketLimit_whenExceedLimit_thenConsumeReturnsFalse() { Refill refill = Refill.intervally(10, Duration.ofMinutes(1)); Bandwidth limit = Bandwidth.classic(10, refill); - Bucket bucket = Bucket4j.builder() + Bucket bucket = Bucket.builder() .addLimit(limit) .build(); @@ -34,7 +33,7 @@ public class Bucket4jUsageUnitTest { @Test public void givenMultipletLimits_whenExceedSmallerLimit_thenConsumeReturnsFalse() { - Bucket bucket = Bucket4j.builder() + Bucket bucket = Bucket.builder() .addLimit(Bandwidth.classic(10, Refill.intervally(10, Duration.ofMinutes(1)))) .addLimit(Bandwidth.classic(5, Refill.intervally(5, Duration.ofSeconds(20)))) .build(); @@ -49,7 +48,7 @@ public class Bucket4jUsageUnitTest { public void givenBucketLimit_whenThrottleRequests_thenConsumeReturnsTrue() throws InterruptedException { Refill refill = Refill.intervally(1, Duration.ofSeconds(2)); Bandwidth limit = Bandwidth.classic(1, refill); - Bucket bucket = Bucket4j.builder() + Bucket bucket = Bucket.builder() .addLimit(limit) .build(); @@ -65,8 +64,8 @@ public class Bucket4jUsageUnitTest { static class AssertTryConsume implements Runnable { - private Bucket bucket; - private CountDownLatch latch; + private final Bucket bucket; + private final CountDownLatch latch; AssertTryConsume(Bucket bucket, CountDownLatch latch) { this.bucket = bucket; diff --git a/spring-boot-modules/spring-boot-logging-log4j2/README.md b/spring-boot-modules/spring-boot-logging-log4j2/README.md index 9688f8f83c..45d6c0a2f5 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/README.md +++ b/spring-boot-modules/spring-boot-logging-log4j2/README.md @@ -7,3 +7,4 @@ This module contains articles about logging in Spring Boot projects with Log4j 2 - [Logging to Graylog with Spring Boot](https://www.baeldung.com/graylog-with-spring-boot) - [Log Groups in Spring Boot 2.1](https://www.baeldung.com/spring-boot-log-groups) - [Writing Log Data to Syslog Using Log4j2](https://www.baeldung.com/log4j-to-syslog) +- [Spring Boot Logback and Log4j2 Extensions](https://www.baeldung.com/spring-boot-logback-log4j2) diff --git a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml index 81a28725a7..b429339417 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml @@ -8,34 +8,13 @@ jar Demo project for Spring Boot Logging with Log4J2 - - org.springframework.boot - spring-boot-starter-parent - 2.2.2.RELEASE - + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 - - - - - - - junit - junit - ${junit.version} - - - org.junit - junit-bom - ${junit-jupiter.version} - pom - import - - - - org.springframework.boot @@ -55,19 +34,15 @@ org.springframework.boot spring-boot-starter-log4j2 + + org.apache.logging.log4j + log4j-spring-boot + org.projectlombok lombok - ${lombok.version} provided - - - - org.springframework.boot - spring-boot-starter-log4j - ${spring-boot-starter-log4j.version} - org.graylog2 gelfj @@ -99,10 +74,6 @@ com.baeldung.springbootlogging.SpringBootLoggingApplication 1.3.8.RELEASE 1.1.16 - 1.18.24 - - 4.13.2 - 5.8.1 2.17.1 diff --git a/spring-boot-modules/spring-boot-logging-log4j2/src/main/java/com/baeldung/extensions/SpringBootLog4j2ExtensionsApplication.java b/spring-boot-modules/spring-boot-logging-log4j2/src/main/java/com/baeldung/extensions/SpringBootLog4j2ExtensionsApplication.java new file mode 100644 index 0000000000..7802653c1c --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-log4j2/src/main/java/com/baeldung/extensions/SpringBootLog4j2ExtensionsApplication.java @@ -0,0 +1,25 @@ +package com.baeldung.extensions; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:application-log4j2-extensions.properties") +public class SpringBootLog4j2ExtensionsApplication { + + private static final Logger logger = LogManager.getLogger(SpringBootLog4j2ExtensionsApplication.class); + + public static void main(String[] args) { + SpringApplication.run(SpringBootLog4j2ExtensionsApplication.class, args); + + logger.trace("Trace log message"); + logger.debug("Debug log message"); + logger.info("Info log message"); + logger.error("Error log message"); + logger.warn("Warn log message"); + logger.fatal("Fatal log message"); + } +} diff --git a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/application-log4j2-extensions.properties b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/application-log4j2-extensions.properties new file mode 100644 index 0000000000..8db25c3ff5 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/application-log4j2-extensions.properties @@ -0,0 +1,2 @@ +logging.config=classpath:log4j2-spring.xml +spring.application.name=log4j2-extension \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j.xml b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j.xml index 61c1b7b229..524628b855 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j.xml @@ -7,7 +7,7 @@ - + diff --git a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2-spring.xml b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2-spring.xml index 77a2074b30..c6906e1698 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2-spring.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2-spring.xml @@ -7,6 +7,11 @@ pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" /> + + + + @@ -37,7 +42,20 @@ - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2.system.properties b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2.system.properties new file mode 100644 index 0000000000..ba79a90a64 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-log4j2/src/main/resources/log4j2.system.properties @@ -0,0 +1 @@ +log4j2.debug=true \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-logback/.gitignore b/spring-boot-modules/spring-boot-logging-logback/.gitignore new file mode 100644 index 0000000000..d129c74ec9 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/.gitignore @@ -0,0 +1,29 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/logs/ +/bin/ +/mvnw +/mvnw.cmd diff --git a/spring-boot-modules/spring-boot-logging-logback/README.md b/spring-boot-modules/spring-boot-logging-logback/README.md new file mode 100644 index 0000000000..0a9d6d8bba --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/README.md @@ -0,0 +1,6 @@ +## Spring Boot Logging with Logback + +This module contains articles about logging in Spring Boot projects with Logback. + +### Relevant Articles: + diff --git a/spring-boot-modules/spring-boot-logging-logback/pom.xml b/spring-boot-modules/spring-boot-logging-logback/pom.xml new file mode 100644 index 0000000000..deb591c9f0 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + spring-boot-logging-logback + spring-boot-logging-logback + jar + Demo project for Spring Boot Logging with Logback + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-logback/src/main/java/com/baeldung/extensions/SpringBootLogbackExtensionsApplication.java b/spring-boot-modules/spring-boot-logging-logback/src/main/java/com/baeldung/extensions/SpringBootLogbackExtensionsApplication.java new file mode 100644 index 0000000000..28e455a7ea --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/src/main/java/com/baeldung/extensions/SpringBootLogbackExtensionsApplication.java @@ -0,0 +1,22 @@ +package com.baeldung.extensions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootLogbackExtensionsApplication { + + private static final Logger logger = LoggerFactory.getLogger(SpringBootLogbackExtensionsApplication.class); + + public static void main(String[] args) { + SpringApplication.run(SpringBootLogbackExtensionsApplication.class, args); + + logger.debug("Debug log message"); + logger.info("Info log message"); + logger.error("Error log message"); + logger.warn("Warn log message"); + logger.trace("Trace log message"); + } +} diff --git a/spring-boot-modules/spring-boot-logging-logback/src/main/resources/application.properties b/spring-boot-modules/spring-boot-logging-logback/src/main/resources/application.properties new file mode 100644 index 0000000000..d4860d5765 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=logback-extension \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-logback/src/main/resources/logback-spring.xml b/spring-boot-modules/spring-boot-logging-logback/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..b2bf8bcd07 --- /dev/null +++ b/spring-boot-modules/spring-boot-logging-logback/src/main/resources/logback-spring.xml @@ -0,0 +1,33 @@ + + + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + ${LOGS}/${application.name}.log + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + ${LOGS}/archived/${application.name}-%d{yyyy-MM-dd}.log + + + + + + + + diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/PostmanUploadDemo.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/PostmanUploadDemo.java new file mode 100644 index 0000000000..b3721fefe4 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/PostmanUploadDemo.java @@ -0,0 +1,15 @@ +package com.baeldung.postman; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@EnableWebMvc +public class PostmanUploadDemo { + + public static void main(String[] args) { + SpringApplication.run(PostmanUploadDemo.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java new file mode 100644 index 0000000000..ac19110318 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java @@ -0,0 +1,26 @@ +package com.baeldung.postman.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import com.baeldung.postman.model.JsonRequest; + +@Controller +public class PostmanUploadController { + + @PostMapping("/uploadFile") + public ResponseEntity handleFileUpload(@RequestParam("file") MultipartFile file) { + return ResponseEntity.ok() + .body("file received successfully"); + } + + @PostMapping("/uploadJson") + public ResponseEntity handleJsonInput(@RequestBody JsonRequest json) { + return ResponseEntity.ok() + .body(json.getId() + json.getName()); + } +} diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/model/JsonRequest.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/model/JsonRequest.java new file mode 100644 index 0000000000..326f32c30b --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/model/JsonRequest.java @@ -0,0 +1,30 @@ +package com.baeldung.postman.model; + +public class JsonRequest { + int id; + String name; + + public JsonRequest() { + } + + public JsonRequest(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/postman/controller/PostmanUploadControllerUnitTest.java b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/postman/controller/PostmanUploadControllerUnitTest.java new file mode 100644 index 0000000000..1049d2ec0d --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/postman/controller/PostmanUploadControllerUnitTest.java @@ -0,0 +1,43 @@ +package com.baeldung.postman.controller; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import com.baeldung.postman.PostmanUploadDemo; +import com.baeldung.postman.model.JsonRequest; +import com.fasterxml.jackson.databind.ObjectMapper; + +@SpringBootTest(classes = PostmanUploadDemo.class) +@AutoConfigureMockMvc +public class PostmanUploadControllerUnitTest { + @Autowired + private MockMvc mockMvc; + + @Test + public void givenJson_whenUploaded_thenSuccessReturned() throws Exception { + JsonRequest request = new JsonRequest(1, "John Doe"); + this.mockMvc.perform(MockMvcRequestBuilders.post("/uploadJson") + .contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(content().string("1John Doe")); + } + + @Test + public void givenFile_whenUploaded_thenSuccessReturned() throws Exception { + MockMultipartFile request = new MockMultipartFile("dummy", "{\"key\": \"value\"}".getBytes()); + this.mockMvc.perform(MockMvcRequestBuilders.multipart("/uploadFile") + .file("file", request.getBytes())) + .andExpect(status().isOk()) + .andExpect(content().string("file received successfully")); + } +} diff --git a/spring-boot-modules/spring-boot-mvc-5/README.md b/spring-boot-modules/spring-boot-mvc-5/README.md index 7cc3f8a1fe..782adb7b34 100644 --- a/spring-boot-modules/spring-boot-mvc-5/README.md +++ b/spring-boot-modules/spring-boot-mvc-5/README.md @@ -2,4 +2,6 @@ This module contains articles about Spring Web MVC in Spring Boot projects. -### Relevant Articles: \ No newline at end of file +### Relevant Articles: +- [Enable and Disable Endpoints at Runtime With Spring Boot](https://www.baeldung.com/spring-boot-enable-disable-endpoints-at-runtime) +- [Extracting a Custom Header From the Request](https://www.baeldung.com/spring-extract-custom-header-request) diff --git a/spring-boot-modules/spring-boot-mvc-5/pom.xml b/spring-boot-modules/spring-boot-mvc-5/pom.xml index 61b27ea8f1..5a4f8a6cce 100644 --- a/spring-boot-modules/spring-boot-mvc-5/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-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 spring-boot-mvc-5 spring-boot-mvc-5 @@ -14,6 +14,18 @@ 1.0.0-SNAPSHOT + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + org.springframework.boot @@ -39,18 +51,6 @@ - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/BuzzController.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/BuzzController.java new file mode 100644 index 0000000000..09bf16f008 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/BuzzController.java @@ -0,0 +1,21 @@ +package com.baeldung.requestheader; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.requestheader.interceptor.OperatorHolder; + +@RestController +public class BuzzController { + private final OperatorHolder operatorHolder; + + public BuzzController(OperatorHolder operatorHolder) { + this.operatorHolder = operatorHolder; + } + + @GetMapping("buzz") + public String buzz() { + return "hello, " + operatorHolder.getOperator(); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/FooBarController.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/FooBarController.java new file mode 100644 index 0000000000..e0fd5f2f64 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/FooBarController.java @@ -0,0 +1,22 @@ +package com.baeldung.requestheader; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class FooBarController { + + @GetMapping("foo") + public String foo(HttpServletRequest request) { + String operator = request.getHeader("operator"); + return "hello, " + operator; + } + + @GetMapping("bar") + public String bar(@RequestHeader("operator") String operator) { + return "hello, " + operator; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/HeaderInterceptorApplication.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/HeaderInterceptorApplication.java new file mode 100644 index 0000000000..f2e9aaca12 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/HeaderInterceptorApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.requestheader; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@EnableWebMvc +public class HeaderInterceptorApplication { + + public static void main(String[] args) { + SpringApplication.run(HeaderInterceptorApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/config/HeaderInterceptorConfig.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/config/HeaderInterceptorConfig.java new file mode 100644 index 0000000000..07fb5b5184 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/config/HeaderInterceptorConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.requestheader.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.baeldung.requestheader.interceptor.OperatorHolder; +import com.baeldung.requestheader.interceptor.OperatorInterceptor; + +@Configuration +public class HeaderInterceptorConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + registry.addInterceptor(operatorInterceptor()); + } + + @Bean + public OperatorInterceptor operatorInterceptor() { + return new OperatorInterceptor(operatorHolder()); + } + + @Bean + @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) + public OperatorHolder operatorHolder() { + return new OperatorHolder(); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorHolder.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorHolder.java new file mode 100644 index 0000000000..31d36c0b59 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorHolder.java @@ -0,0 +1,13 @@ +package com.baeldung.requestheader.interceptor; + +public class OperatorHolder { + private String operator; + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorInterceptor.java b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorInterceptor.java new file mode 100644 index 0000000000..0d0a0c7405 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/main/java/com/baeldung/requestheader/interceptor/OperatorInterceptor.java @@ -0,0 +1,22 @@ +package com.baeldung.requestheader.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerInterceptor; + +public class OperatorInterceptor implements HandlerInterceptor { + + private final OperatorHolder operatorHolder; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String operator = request.getHeader("operator"); + operatorHolder.setOperator(operator); + return true; + } + + public OperatorInterceptor(OperatorHolder operatorHolder) { + this.operatorHolder = operatorHolder; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-5/src/test/java/com/baeldung/requestheader/HeaderInterceptorIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-5/src/test/java/com/baeldung/requestheader/HeaderInterceptorIntegrationTest.java new file mode 100644 index 0000000000..ee053a4c36 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-5/src/test/java/com/baeldung/requestheader/HeaderInterceptorIntegrationTest.java @@ -0,0 +1,65 @@ +package com.baeldung.requestheader; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +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.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { HeaderInterceptorApplication.class }) +@WebAppConfiguration +public class HeaderInterceptorIntegrationTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + private MockMvc mockMvc; + + @BeforeEach + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) + .build(); + } + + @Test + public void givenARequestWithOperatorHeader_whenWeCallFooEndpoint_thenOperatorIsExtracted() throws Exception { + MockHttpServletResponse response = this.mockMvc.perform(get("/foo").header("operator", "John.Doe")) + .andDo(print()) + .andReturn() + .getResponse(); + + assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe"); + } + + @Test + public void givenARequestWithOperatorHeader_whenWeCallBarEndpoint_thenOperatorIsExtracted() throws Exception { + MockHttpServletResponse response = this.mockMvc.perform(get("/bar").header("operator", "John.Doe")) + .andDo(print()) + .andReturn() + .getResponse(); + + assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe"); + } + + @Test + public void givenARequestWithOperatorHeader_whenWeCallBuzzEndpoint_thenOperatorIsIntercepted() throws Exception { + MockHttpServletResponse response = this.mockMvc.perform(get("/buzz").header("operator", "John.Doe")) + .andDo(print()) + .andReturn() + .getResponse(); + + assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe"); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-birt/pom.xml b/spring-boot-modules/spring-boot-mvc-birt/pom.xml index badf77735f..274932f06c 100644 --- a/spring-boot-modules/spring-boot-mvc-birt/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-birt/pom.xml @@ -9,13 +9,11 @@ jar Module For Spring Boot Integration with BIRT - - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 diff --git a/spring-boot-modules/spring-boot-mvc/pom.xml b/spring-boot-modules/spring-boot-mvc/pom.xml index 6d3f722146..d5ec7742c9 100644 --- a/spring-boot-modules/spring-boot-mvc/pom.xml +++ b/spring-boot-modules/spring-boot-mvc/pom.xml @@ -41,8 +41,8 @@ spring-boot-starter-data-rest - mysql - mysql-connector-java + com.mysql + mysql-connector-j org.hsqldb diff --git a/javaxval2/.gitignore b/spring-boot-modules/spring-boot-process-automation/.gitignore similarity index 71% rename from javaxval2/.gitignore rename to spring-boot-modules/spring-boot-process-automation/.gitignore index 8027134ae9..da7c2c5c0a 100644 --- a/javaxval2/.gitignore +++ b/spring-boot-modules/spring-boot-process-automation/.gitignore @@ -1,6 +1,5 @@ +/target/ +.settings/ .classpath .project -.settings/ -target/ -bin/ diff --git a/spring-boot-modules/spring-boot-process-automation/README.md b/spring-boot-modules/spring-boot-process-automation/README.md new file mode 100644 index 0000000000..a623302a9f --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/README.md @@ -0,0 +1,3 @@ +## Relevant Articles + +- [Running Spring Boot Applications with the Embedded Camunda Engine](https://www.baeldung.com/spring-boot-embedded-camunda) diff --git a/spring-boot-modules/spring-boot-process-automation/pom.xml b/spring-boot-modules/spring-boot-process-automation/pom.xml new file mode 100644 index 0000000000..a68fc95ea5 --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + spring-boot-process-automation + + + spring-boot-modules + com.baeldung.spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + org.camunda.bpm.springboot + camunda-bpm-spring-boot-starter-webapp + ${camunda.version} + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 7.18.0 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/CamundaApplication.java b/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/CamundaApplication.java new file mode 100644 index 0000000000..2862bc9ebc --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/CamundaApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.camunda; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CamundaApplication { + + public static void main(String[] args) { + SpringApplication.run(CamundaApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/task/CalculateInterestService.java b/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/task/CalculateInterestService.java new file mode 100644 index 0000000000..ceef72ef79 --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/src/main/java/com/baeldung/camunda/task/CalculateInterestService.java @@ -0,0 +1,19 @@ +package com.baeldung.camunda.task; + +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.JavaDelegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class CalculateInterestService implements JavaDelegate { + + private static final Logger LOGGER = LoggerFactory.getLogger(CalculateInterestService.class); + + @Override + public void execute(DelegateExecution execution) { + LOGGER.info("calculating interest of the loan"); + } + +} diff --git a/spring-boot-modules/spring-boot-process-automation/src/main/resources/application.yaml b/spring-boot-modules/spring-boot-process-automation/src/main/resources/application.yaml new file mode 100644 index 0000000000..102790e1ed --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/src/main/resources/application.yaml @@ -0,0 +1,5 @@ +spring.datasource.url: jdbc:h2:file:./camunda-h2-database + +camunda.bpm.admin-user: + id: demo + password: demo \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-process-automation/src/main/resources/loanProcess.bpmn b/spring-boot-modules/spring-boot-process-automation/src/main/resources/loanProcess.bpmn new file mode 100644 index 0000000000..c3245e5bfd --- /dev/null +++ b/spring-boot-modules/spring-boot-process-automation/src/main/resources/loanProcess.bpmn @@ -0,0 +1,67 @@ + + + + + SequenceFlow_14bdz4q + + + + SequenceFlow_1s49wir + + + + + SequenceFlow_0d726xt + SequenceFlow_1s49wir + + + SequenceFlow_14bdz4q + SequenceFlow_0d726xt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-modules/spring-boot-request-params/README.md b/spring-boot-modules/spring-boot-request-params/README.md new file mode 100644 index 0000000000..2824083d8a --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/README.md @@ -0,0 +1,6 @@ +## Spring Boot Request Params + +This module contains articles about Spring Boot Request Params + +### Relevant Articles: +- [Enum Mapping in Spring Boot](https://www.baeldung.com/spring-boot-enum-mapping) diff --git a/spring-boot-modules/spring-boot-request-params/pom.xml b/spring-boot-modules/spring-boot-request-params/pom.xml new file mode 100644 index 0000000000..526938860a --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + spring-boot-request-params + spring-boot-request-params + jar + Module For Spring Boot Request Params + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java new file mode 100644 index 0000000000..43145f13ad --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.enummapping; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EnumMappingMainApplication { + + public static void main(String[] args) { + SpringApplication.run(EnumMappingMainApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java new file mode 100644 index 0000000000..8078a3cb47 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.enummapping.config; + +import org.springframework.boot.convert.ApplicationConversionService; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.baeldung.enummapping.converters.StringToLevelConverter; + +@Configuration +public class EnumMappingConfig implements WebMvcConfigurer { + @Override + public void addFormatters(FormatterRegistry registry) { + ApplicationConversionService.configure(registry); + registry.addConverter(new StringToLevelConverter()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java new file mode 100644 index 0000000000..d006b8f149 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java @@ -0,0 +1,30 @@ +package com.baeldung.enummapping.controllers; + +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.enummapping.editors.LevelEditor; +import com.baeldung.enummapping.enums.Level; + +@RestController +@RequestMapping("enummapping") +public class EnumMappingController { + + @InitBinder + public void initBinder(WebDataBinder dataBinder) { + dataBinder.registerCustomEditor(Level.class, new LevelEditor()); + } + + @GetMapping("/get") + public String getByLevel(@RequestParam(required = false) Level level) { + if (level != null) { + return level.name(); + } + return "undefined"; + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java new file mode 100644 index 0000000000..8adee1c4e5 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java @@ -0,0 +1,19 @@ +package com.baeldung.enummapping.converters; + +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.convert.converter.Converter; + +import com.baeldung.enummapping.enums.Level; + +public class StringToLevelConverter implements Converter { + + @Override + public Level convert(String source) { + if (StringUtils.isBlank(source)) { + return null; + } + return EnumUtils.getEnum(Level.class, source.toUpperCase()); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java new file mode 100644 index 0000000000..d4f8e96ad8 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java @@ -0,0 +1,22 @@ +package com.baeldung.enummapping.editors; + +import java.beans.PropertyEditorSupport; + +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; + +import com.baeldung.enummapping.enums.Level; + +public class LevelEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) { + if (StringUtils.isBlank(text)) { + setValue(null); + } else { + setValue(EnumUtils.getEnum(Level.class, text.toUpperCase())); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java new file mode 100644 index 0000000000..471e9c2f5c --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java @@ -0,0 +1,7 @@ +package com.baeldung.enummapping.enums; + +public enum Level { + + LOW, MEDIUM, HIGH + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java new file mode 100644 index 0000000000..0fd1ce72d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.enummapping; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.enummapping.controllers.EnumMappingController; +import com.baeldung.enummapping.enums.Level; + +@RunWith(SpringRunner.class) +@WebMvcTest(EnumMappingController.class) +public class EnumMappingIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenPassingLowerCaseEnumConstant_thenConvert() throws Exception { + mockMvc.perform(get("/enummapping/get?level=medium")) + .andExpect(status().isOk()) + .andExpect(content().string(Level.MEDIUM.name())); + } + + @Test + public void whenPassingUnknownEnumConstant_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get?level=unknown")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + + @Test + public void whenPassingEmptyParameter_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get?level=")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + + @Test + public void whenPassingNoParameter_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java new file mode 100644 index 0000000000..100f742f40 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java @@ -0,0 +1,37 @@ +package com.baeldung.enummapping.converters; + +import static org.assertj.core.api.Assertions.assertThat; + +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.convert.ConversionService; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.enummapping.EnumMappingMainApplication; +import com.baeldung.enummapping.enums.Level; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = EnumMappingMainApplication.class) +public class StringToLevelConverterIntegrationTest { + + @Autowired + ConversionService conversionService; + + @Test + public void whenConvertStringToLevelEnumUsingCustomConverter_thenSuccess() { + assertThat(conversionService.convert("low", Level.class)).isEqualTo(Level.LOW); + } + + @Test + public void whenStringIsEmpty_thenReturnNull() { + assertThat(conversionService.convert("", Level.class)).isNull(); + } + + @Test + public void whenStringIsNull_thenReturnNull() { + assertThat(conversionService.convert(null, Level.class)).isNull(); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java new file mode 100644 index 0000000000..ab01cbc1ed --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java @@ -0,0 +1,34 @@ +package com.baeldung.enummapping.editors; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +import com.baeldung.enummapping.enums.Level; + +public class LevelEditorIntegrationTest { + + private final LevelEditor levelEditor = new LevelEditor(); + + @Test + public void whenConvertStringToLevelEnumUsingCustomPropertyEditor_thenSuccess() { + levelEditor.setAsText("lOw"); + + assertThat(levelEditor.getValue()).isEqualTo(Level.LOW); + } + + @Test + public void whenStringIsEmpty_thenReturnNull() { + levelEditor.setAsText(""); + + assertThat(levelEditor.getValue()).isNull(); + } + + @Test + public void whenStringIsNull_thenReturnNull() { + levelEditor.setAsText(null); + + assertThat(levelEditor.getValue()).isNull(); + } + +} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java index 40f5341e29..24174815fa 100644 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/Application.java @@ -1,19 +1,18 @@ package com.baeldung.web.log.app; -import javax.servlet.ServletRegistration; - import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.PropertySource; -import com.baeldung.web.log.config.CustomeRequestLoggingFilter; - -@EnableAutoConfiguration @ComponentScan("com.baeldung.web.log") @PropertySource("application-log.properties") -@SpringBootApplication +@SpringBootApplication(exclude = { + SecurityAutoConfiguration.class, + ManagementWebSecurityAutoConfiguration.class +}) public class Application { public static void main(final String[] args) { diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedHttpServletRequest.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedHttpServletRequest.java new file mode 100644 index 0000000000..51bbd51ea8 --- /dev/null +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedHttpServletRequest.java @@ -0,0 +1,30 @@ +package com.baeldung.web.log.app; + +import org.springframework.util.StreamUtils; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.*; + +public class CachedHttpServletRequest extends HttpServletRequestWrapper { + + private byte[] cachedPayload; + + public CachedHttpServletRequest(HttpServletRequest request) throws IOException { + super(request); + InputStream requestInputStream = request.getInputStream(); + this.cachedPayload = StreamUtils.copyToByteArray(requestInputStream); + } + + @Override + public ServletInputStream getInputStream() { + return new CachedServletInputStream(this.cachedPayload); + } + + @Override + public BufferedReader getReader() { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedPayload); + return new BufferedReader(new InputStreamReader(byteArrayInputStream)); + } +} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedServletInputStream.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedServletInputStream.java new file mode 100644 index 0000000000..673d04876b --- /dev/null +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/CachedServletInputStream.java @@ -0,0 +1,45 @@ +package com.baeldung.web.log.app; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class CachedServletInputStream extends ServletInputStream { + + private final static Logger LOGGER = LoggerFactory.getLogger(CachedServletInputStream.class); + private InputStream cachedInputStream; + + public CachedServletInputStream(byte[] cachedBody) { + this.cachedInputStream = new ByteArrayInputStream(cachedBody); + } + + @Override + public boolean isFinished() { + try { + return cachedInputStream.available() == 0; + } catch (IOException exp) { + LOGGER.error(exp.getMessage()); + } + return false; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + throw new UnsupportedOperationException(); + } + + @Override + public int read() throws IOException { + return cachedInputStream.read(); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/RequestCachingFilter.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/RequestCachingFilter.java new file mode 100644 index 0000000000..e0928550fc --- /dev/null +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/RequestCachingFilter.java @@ -0,0 +1,33 @@ +package com.baeldung.web.log.app; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Order(value = Ordered.HIGHEST_PRECEDENCE) +@Component +@WebFilter(filterName = "RequestCachingFilter", urlPatterns = "/*") +public class RequestCachingFilter extends OncePerRequestFilter { + + private final static Logger LOGGER = LoggerFactory.getLogger(RequestCachingFilter.class); + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + CachedHttpServletRequest cachedHttpServletRequest = new CachedHttpServletRequest(request); + LOGGER.info("REQUEST DATA: " + IOUtils.toString(cachedHttpServletRequest.getInputStream(), StandardCharsets.UTF_8)); + filterChain.doFilter(cachedHttpServletRequest, response); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java deleted file mode 100644 index 2ea0204dc3..0000000000 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/app/TaxiFareRequestInterceptor.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.baeldung.web.log.app; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; -import org.springframework.web.util.ContentCachingRequestWrapper; - -import com.baeldung.web.log.util.RequestLoggingUtil; - -@Component -public class TaxiFareRequestInterceptor extends HandlerInterceptorAdapter { - - private final static Logger LOGGER = LoggerFactory.getLogger(TaxiFareRequestInterceptor.class); - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - String postData; - HttpServletRequest requestCacheWrapperObject = null; - try { - // Uncomment to produce the stream closed issue - // postData = RequestLoggingUtil.getStringFromInputStream(request.getInputStream()); - - // To overcome request stream closed issue - requestCacheWrapperObject = new ContentCachingRequestWrapper(request); - requestCacheWrapperObject.getParameterMap(); - } catch (Exception exception) { - exception.printStackTrace(); - } finally { - postData = RequestLoggingUtil.readPayload(requestCacheWrapperObject); - LOGGER.info("REQUEST DATA: " + postData); - } - return true; - } - - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { - LOGGER.info("RESPONSE: " + response.getStatus()); - } - -} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomWebAppInitializer.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomWebAppInitializer.java deleted file mode 100644 index 0f19c6dc48..0000000000 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomWebAppInitializer.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.web.log.config; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; -import org.springframework.web.WebApplicationInitializer; - -public class CustomWebAppInitializer implements WebApplicationInitializer { - - @Override - public void onStartup(ServletContext container) throws ServletException { - - AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); - context.setConfigLocation("com.baeldung.web.log"); - container.addListener(new ContextLoaderListener(context)); - - ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(context)); - dispatcher.setLoadOnStartup(1); - dispatcher.addMapping("/"); - - container.addFilter("customRequestLoggingFilter", CustomeRequestLoggingFilter.class).addMappingForServletNames(null, false, "dispatcher"); - } -} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java deleted file mode 100644 index 3accb0a06e..0000000000 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/CustomeRequestLoggingFilter.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.web.log.config; - -import org.springframework.web.filter.CommonsRequestLoggingFilter; - -public class CustomeRequestLoggingFilter extends CommonsRequestLoggingFilter { - - public CustomeRequestLoggingFilter() { - super.setIncludeQueryString(true); - super.setIncludePayload(true); - super.setMaxPayloadLength(10000); - } -} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java index 85728729d5..a0622d45d2 100644 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/RequestLoggingFilterConfig.java @@ -14,7 +14,7 @@ public class RequestLoggingFilterConfig { filter.setIncludePayload(true); filter.setMaxPayloadLength(10000); filter.setIncludeHeaders(false); - filter.setAfterMessagePrefix("REQUEST DATA : "); + filter.setAfterMessagePrefix("REQUEST DATA: "); return filter; } } diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java deleted file mode 100644 index fda8a845e9..0000000000 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/config/TaxiFareMVCConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.baeldung.web.log.config; - -import com.baeldung.web.log.app.TaxiFareRequestInterceptor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class TaxiFareMVCConfig implements WebMvcConfigurer { - - @Autowired - private TaxiFareRequestInterceptor taxiFareRequestInterceptor; - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(taxiFareRequestInterceptor).addPathPatterns("/taxifare/*/"); - } -} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java deleted file mode 100644 index 70c4eaee90..0000000000 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/web/log/util/RequestLoggingUtil.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.baeldung.web.log.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.io.IOUtils; -import org.springframework.web.util.ContentCachingRequestWrapper; -import org.springframework.web.util.WebUtils; - -public class RequestLoggingUtil { - - public static String getStringFromInputStream(InputStream is) { - StringWriter writer = new StringWriter(); - String encoding = "UTF-8"; - try { - IOUtils.copy(is, writer, encoding); - } catch (IOException e) { - e.printStackTrace(); - } - return writer.toString(); - } - - public static String readPayload(final HttpServletRequest request) throws IOException { - String payloadData = null; - ContentCachingRequestWrapper contentCachingRequestWrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class); - if (null != contentCachingRequestWrapper) { - byte[] buf = contentCachingRequestWrapper.getContentAsByteArray(); - if (buf.length > 0) { - payloadData = new String(buf, 0, buf.length, contentCachingRequestWrapper.getCharacterEncoding()); - } - } - return payloadData; - } - -} diff --git a/spring-boot-modules/spring-boot-runtime/src/main/resources/logback.xml b/spring-boot-modules/spring-boot-runtime/src/main/resources/logback.xml index 7d900d8ea8..4552282d23 100644 --- a/spring-boot-modules/spring-boot-runtime/src/main/resources/logback.xml +++ b/spring-boot-modules/spring-boot-runtime/src/main/resources/logback.xml @@ -7,6 +7,10 @@ + + + + diff --git a/spring-boot-modules/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java b/spring-boot-modules/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java index 97d669d3fa..b98c77ad2b 100644 --- a/spring-boot-modules/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-runtime/src/test/java/com/baeldung/web/controller/TaxiFareControllerIntegrationTest.java @@ -1,23 +1,19 @@ package com.baeldung.web.controller; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - +import com.baeldung.web.log.app.Application; +import com.baeldung.web.log.data.TaxiRide; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.context.annotation.Configuration; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import com.baeldung.web.log.app.Application; -import com.baeldung.web.log.data.TaxiRide; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; @RunWith(SpringRunner.class) -@SpringBootTest(classes = { Application.class, TaxiFareControllerIntegrationTest.SecurityConfig.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@SpringBootTest(classes = { Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class TaxiFareControllerIntegrationTest { @LocalServerPort @@ -25,8 +21,6 @@ public class TaxiFareControllerIntegrationTest { @Test public void givenRequest_whenFetchTaxiFareRateCard_thanOK() { - - System.out.println(port); String URL = "http://localhost:" + port + "/spring-rest"; TestRestTemplate testRestTemplate = new TestRestTemplate(); TaxiRide taxiRide = new TaxiRide(true, 10l); @@ -37,16 +31,4 @@ public class TaxiFareControllerIntegrationTest { assertThat(fare, equalTo("200")); } - @Configuration - static class SecurityConfig extends WebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - System.out.println("security being set"); - http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .csrf().disable(); - } - } } \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/README.md b/spring-boot-modules/spring-boot-swagger-2/README.md index 242f3d3385..e5ec236801 100644 --- a/spring-boot-modules/spring-boot-swagger-2/README.md +++ b/spring-boot-modules/spring-boot-swagger-2/README.md @@ -2,4 +2,5 @@ - [Swagger: Specify Two Responses with the Same Response Code](https://www.baeldung.com/swagger-two-responses-one-response-code) - [Specify an Array of Strings as Body Parameters in Swagger](https://www.baeldung.com/swagger-body-array-of-strings) -- [Swagger @ApiParam vs @ApiModelProperty](https://www.baeldung.com/swagger-apiparam-vs-apimodelproperty) \ No newline at end of file +- [Swagger @ApiParam vs @ApiModelProperty](https://www.baeldung.com/swagger-apiparam-vs-apimodelproperty) +- [Map Date Types With OpenAPI Generator](https://www.baeldung.com/openapi-map-date-types) diff --git a/spring-boot-modules/spring-boot-swagger-2/pom.xml b/spring-boot-modules/spring-boot-swagger-2/pom.xml index 1cd8e5b850..d2d1d10ad9 100644 --- a/spring-boot-modules/spring-boot-swagger-2/pom.xml +++ b/spring-boot-modules/spring-boot-swagger-2/pom.xml @@ -20,6 +20,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-validation + org.springdoc springdoc-openapi-ui @@ -59,6 +63,7 @@ ${swagger-codegen-maven-plugin.version} + two-responses generate @@ -71,6 +76,59 @@ + + dates + + generate + + + ${project.basedir}/src/main/resources/static/event.yaml + spring + + true + custom + + + DateTime=Instant + Date=Date + + + Instant=java.time.Instant + Date=java.util.Date + + + + + + + org.openapitools + openapi-generator-maven-plugin + ${openapi-generator.version} + + + + generate + + + true + ${project.basedir}/src/main/resources/static/event.yaml + spring + + true + custom + false + true + + + DateTime=Instant + Date=Date + + + Instant=java.time.Instant + Date=java.util.Date + + + @@ -84,6 +142,7 @@ + 6.2.1 3.0.0 3.0.34 1.6.10 diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/resources/static/event.yaml b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/static/event.yaml new file mode 100644 index 0000000000..f8a7b01b43 --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/static/event.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.0 +info: + title: an example api with dates + version: 0.1.0 +paths: +components: + schemas: + Event: + type: object + properties: + organizer: + type: string + startDate: + type: string + format: date + endDate: + type: string + format: date-time + ticketSales: + type: string + description: Beginning of the ticket sales + example: "01-01-2023" + pattern: "[0-9]{2}-[0-9]{2}-[0-9]{4}" \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/src/test/java/com/baeldung/dates/EventUnitTest.java b/spring-boot-modules/spring-boot-swagger-2/src/test/java/com/baeldung/dates/EventUnitTest.java new file mode 100644 index 0000000000..378882c964 --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/test/java/com/baeldung/dates/EventUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.dates; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; + +import org.junit.jupiter.api.Test; + +import io.swagger.model.Event; + +class EventUnitTest { + + private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory() + .getValidator(); + + @Test + void givenACorrectlyFormattedTicketSales_WhenBuildingEvent_ThenSuccess() { + Set> violations = VALIDATOR.validate(new Event().ticketSales("01-01-2024")); + assertTrue(violations.isEmpty()); + } + + @Test + void givenAWronglyFormattedTicketSales_WhenBuildingEvent_ThenSuccess() { + Set> violations = VALIDATOR.validate(new Event().ticketSales("2024-01-01")); + assertEquals(1, violations.size()); + } + +} diff --git a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/resources/application.yml b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/resources/application.yml index e4bcdb5888..5d3c8b3af5 100644 --- a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/resources/application.yml +++ b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/resources/application.yml @@ -2,7 +2,6 @@ keycloak: auth-server-url: https://api.example.com/auth # Keycloak server url realm: todos-service-realm # Keycloak Realm resource: todos-service-clients # Keycloak Client - public-client: true principal-attribute: preferred_username ssl-required: external credentials: diff --git a/spring-caching-2/README.md b/spring-boot-modules/spring-caching-2/README.md similarity index 100% rename from spring-caching-2/README.md rename to spring-boot-modules/spring-caching-2/README.md diff --git a/spring-caching-2/pom.xml b/spring-boot-modules/spring-caching-2/pom.xml similarity index 91% rename from spring-caching-2/pom.xml rename to spring-boot-modules/spring-caching-2/pom.xml index 0a07820fc4..6e33e42d2b 100644 --- a/spring-caching-2/pom.xml +++ b/spring-boot-modules/spring-caching-2/pom.xml @@ -9,10 +9,9 @@ jar - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../parent-boot-2/pom.xml + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/CachingTTLApplication.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/CachingTTLApplication.java old mode 100755 new mode 100644 similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/CachingTTLApplication.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/CachingTTLApplication.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/config/SpringCachingConfig.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/config/SpringCachingConfig.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/config/SpringCachingConfig.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/config/SpringCachingConfig.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/controller/HotelController.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/controller/HotelController.java old mode 100755 new mode 100644 similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/controller/HotelController.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/controller/HotelController.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ControllerAdvisor.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ControllerAdvisor.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ControllerAdvisor.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ControllerAdvisor.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ElementNotFoundException.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ElementNotFoundException.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ElementNotFoundException.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/exception/ElementNotFoundException.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/City.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/City.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/City.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/City.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/Hotel.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/Hotel.java old mode 100755 new mode 100644 similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/Hotel.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/model/Hotel.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/CityRepository.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/CityRepository.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/CityRepository.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/CityRepository.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/HotelRepository.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/HotelRepository.java old mode 100755 new mode 100644 similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/HotelRepository.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/repository/HotelRepository.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/HotelService.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/HotelService.java old mode 100755 new mode 100644 similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/HotelService.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/HotelService.java diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/SpringCacheCustomizer.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/SpringCacheCustomizer.java similarity index 100% rename from spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/SpringCacheCustomizer.java rename to spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/ttl/service/SpringCacheCustomizer.java diff --git a/spring-caching-2/src/main/resources/application.properties b/spring-boot-modules/spring-caching-2/src/main/resources/application.properties similarity index 100% rename from spring-caching-2/src/main/resources/application.properties rename to spring-boot-modules/spring-caching-2/src/main/resources/application.properties diff --git a/spring-caching-2/src/main/resources/data.sql b/spring-boot-modules/spring-caching-2/src/main/resources/data.sql similarity index 100% rename from spring-caching-2/src/main/resources/data.sql rename to spring-boot-modules/spring-caching-2/src/main/resources/data.sql diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java similarity index 100% rename from spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java rename to spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/ttl/HotelControllerIntegrationTest.java b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/ttl/HotelControllerIntegrationTest.java similarity index 100% rename from spring-caching-2/src/test/java/com/baeldung/caching/ttl/HotelControllerIntegrationTest.java rename to spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/ttl/HotelControllerIntegrationTest.java diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/ttl/SlowTest.java b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/ttl/SlowTest.java similarity index 100% rename from spring-caching-2/src/test/java/com/baeldung/caching/ttl/SlowTest.java rename to spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/ttl/SlowTest.java diff --git a/spring-caching-2/src/test/resources/application.properties b/spring-boot-modules/spring-caching-2/src/test/resources/application.properties similarity index 100% rename from spring-caching-2/src/test/resources/application.properties rename to spring-boot-modules/spring-caching-2/src/test/resources/application.properties diff --git a/spring-caching/README.md b/spring-boot-modules/spring-caching/README.md similarity index 100% rename from spring-caching/README.md rename to spring-boot-modules/spring-caching/README.md diff --git a/spring-caching/pom.xml b/spring-boot-modules/spring-caching/pom.xml similarity index 93% rename from spring-caching/pom.xml rename to spring-boot-modules/spring-caching/pom.xml index 34c035a8ec..c0318729af 100644 --- a/spring-caching/pom.xml +++ b/spring-boot-modules/spring-caching/pom.xml @@ -8,11 +8,10 @@ spring-caching war - - 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-caching/src/main/java/com/baeldung/cachetest/Application.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/Application.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/cachetest/Application.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/Application.java diff --git a/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheConfig.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheConfig.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/cachetest/config/CacheConfig.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheConfig.java diff --git a/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java diff --git a/spring-caching/src/main/java/com/baeldung/cachetest/rest/NumberController.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/rest/NumberController.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/cachetest/rest/NumberController.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/rest/NumberController.java diff --git a/spring-caching/src/main/java/com/baeldung/cachetest/service/NumberService.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/service/NumberService.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/cachetest/service/NumberService.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/cachetest/service/NumberService.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/config/ApplicationCacheConfig.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/ApplicationCacheConfig.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/config/ApplicationCacheConfig.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/ApplicationCacheConfig.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/config/CachingConfig.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/CachingConfig.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/config/CachingConfig.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/CachingConfig.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/config/CustomKeyGenerator.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/CustomKeyGenerator.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/config/CustomKeyGenerator.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/config/CustomKeyGenerator.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/eviction/controllers/CachingController.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/eviction/controllers/CachingController.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/eviction/controllers/CachingController.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/eviction/controllers/CachingController.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/eviction/service/CachingService.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/eviction/service/CachingService.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/eviction/service/CachingService.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/eviction/service/CachingService.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/example/AbstractService.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/AbstractService.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/example/AbstractService.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/AbstractService.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/example/BookService.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/BookService.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/example/BookService.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/BookService.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/example/Customer.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/Customer.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/example/Customer.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/Customer.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/example/CustomerDataService.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/CustomerDataService.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/example/CustomerDataService.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/CustomerDataService.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/example/CustomerServiceWithParent.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/CustomerServiceWithParent.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/example/CustomerServiceWithParent.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/example/CustomerServiceWithParent.java diff --git a/spring-caching/src/main/java/com/baeldung/caching/model/Book.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/model/Book.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/caching/model/Book.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/caching/model/Book.java diff --git a/spring-caching/src/main/java/com/baeldung/ehcache/calculator/SquaredCalculator.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/ehcache/calculator/SquaredCalculator.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/ehcache/calculator/SquaredCalculator.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/ehcache/calculator/SquaredCalculator.java diff --git a/spring-caching/src/main/java/com/baeldung/ehcache/config/CacheHelper.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/ehcache/config/CacheHelper.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/ehcache/config/CacheHelper.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/ehcache/config/CacheHelper.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/CustomerDetailBO.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/CustomerDetailBO.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/CustomerDetailBO.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/CustomerDetailBO.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/OrderDetailBO.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/OrderDetailBO.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/OrderDetailBO.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/bo/OrderDetailBO.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheManagerConfig.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheManagerConfig.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheManagerConfig.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheManagerConfig.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheResolver.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheResolver.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheResolver.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/config/MultipleCacheResolver.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/controller/MultipleCacheManagerController.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/controller/MultipleCacheManagerController.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/controller/MultipleCacheManagerController.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/controller/MultipleCacheManagerController.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Customer.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Customer.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Customer.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Customer.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Item.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Item.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Item.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Item.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Order.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Order.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Order.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/entity/Order.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/CustomerDetailRepository.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/CustomerDetailRepository.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/CustomerDetailRepository.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/CustomerDetailRepository.java diff --git a/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/OrderDetailRepository.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/OrderDetailRepository.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/OrderDetailRepository.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/multiplecachemanager/repository/OrderDetailRepository.java diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java b/spring-boot-modules/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java similarity index 100% rename from spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java rename to spring-boot-modules/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java diff --git a/spring-caching/src/main/resources/application.properties b/spring-boot-modules/spring-caching/src/main/resources/application.properties similarity index 100% rename from spring-caching/src/main/resources/application.properties rename to spring-boot-modules/spring-caching/src/main/resources/application.properties diff --git a/spring-caching/src/main/resources/config.xml b/spring-boot-modules/spring-caching/src/main/resources/config.xml similarity index 100% rename from spring-caching/src/main/resources/config.xml rename to spring-boot-modules/spring-caching/src/main/resources/config.xml diff --git a/spring-caching/src/main/resources/data.sql b/spring-boot-modules/spring-caching/src/main/resources/data.sql similarity index 100% rename from spring-caching/src/main/resources/data.sql rename to spring-boot-modules/spring-caching/src/main/resources/data.sql diff --git a/spring-caching/src/main/resources/ehcache.xml b/spring-boot-modules/spring-caching/src/main/resources/ehcache.xml similarity index 100% rename from spring-caching/src/main/resources/ehcache.xml rename to spring-boot-modules/spring-caching/src/main/resources/ehcache.xml diff --git a/twitter4j/src/main/resources/logback.xml b/spring-boot-modules/spring-caching/src/main/resources/logback.xml similarity index 100% rename from twitter4j/src/main/resources/logback.xml rename to spring-boot-modules/spring-caching/src/main/resources/logback.xml diff --git a/spring-caching/src/main/resources/schema.sql b/spring-boot-modules/spring-caching/src/main/resources/schema.sql similarity index 100% rename from spring-caching/src/main/resources/schema.sql rename to spring-boot-modules/spring-caching/src/main/resources/schema.sql diff --git a/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/caching/test/CacheEvictAnnotationIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/CacheEvictAnnotationIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/caching/test/CacheEvictAnnotationIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/CacheEvictAnnotationIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/caching/test/CacheManagerEvictIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/CacheManagerEvictIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/caching/test/CacheManagerEvictIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/CacheManagerEvictIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/caching/test/SpringCachingIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/SpringCachingIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/caching/test/SpringCachingIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/caching/test/SpringCachingIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/ehcache/SquareCalculatorUnitTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/ehcache/SquareCalculatorUnitTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/ehcache/SquareCalculatorUnitTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/ehcache/SquareCalculatorUnitTest.java diff --git a/spring-caching/src/test/java/com/baeldung/multiplecachemanager/MultipleCacheManagerIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/multiplecachemanager/MultipleCacheManagerIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/multiplecachemanager/MultipleCacheManagerIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/multiplecachemanager/MultipleCacheManagerIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java b/spring-boot-modules/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java similarity index 100% rename from spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java rename to spring-boot-modules/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index cbd59ef78e..f81286adb6 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -87,7 +87,7 @@ com.baeldung.SpringBootRestApplication 1.4.11.1 - 2.4.5 + 3.1.0 \ No newline at end of file diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 7a4eec679e..68c7d45b7c 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -25,6 +25,7 @@ spring-cloud-ribbon-client spring-cloud-zookeeper spring-cloud-gateway + spring-cloud-gateway-2 spring-cloud-stream spring-cloud-stream-starters spring-cloud-connectors-heroku @@ -53,7 +54,7 @@ spring-cloud-bus spring-cloud-data-flow spring-cloud-sleuth - spring-cloud-openfeign-2 + spring-cloud-open-telemetry diff --git a/spring-cloud-modules/spring-cloud-archaius/pom.xml b/spring-cloud-modules/spring-cloud-archaius/pom.xml index 66b7bb9b19..4d7ca3943d 100644 --- a/spring-cloud-modules/spring-cloud-archaius/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/pom.xml @@ -16,12 +16,12 @@ - additional-sources-simple - basic-config - dynamodb-config - extra-configs - jdbc-config - zookeeper-config + spring-cloud-archaius-additionalsources + spring-cloud-archaius-basic-config + spring-cloud-archaius-dynamodb-config + spring-cloud-archaius-extra-configs + spring-cloud-archaius-jdbc-config + spring-cloud-archaius-zookeeper-config diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/pom.xml similarity index 84% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/pom.xml index 5e2eb47928..eee751b6a4 100644 --- a/spring-cloud-modules/spring-cloud-archaius/basic-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/pom.xml @@ -3,9 +3,9 @@ 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 - basic-config + spring-cloud-archaius-additionalsources 1.0.0-SNAPSHOT - basic-config + spring-cloud-archaius-additionalsources jar diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/AdditionalSourcesSimpleApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/AdditionalSourcesSimpleApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/AdditionalSourcesSimpleApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/AdditionalSourcesSimpleApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/controller/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/controller/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/controller/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/controller/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/config.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/config.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/config.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/config.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/other-config.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/other-config.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/main/resources/other-config.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/main/resources/other-config.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/ArchaiusAdditionalSourcesLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/ArchaiusAdditionalSourcesLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/ArchaiusAdditionalSourcesLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/ArchaiusAdditionalSourcesLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/resources/logback-test.xml similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/src/test/resources/logback-test.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-additionalsources/src/test/resources/logback-test.xml diff --git a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/pom.xml similarity index 85% rename from spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/pom.xml index 6c8ed96003..8b35ee845b 100644 --- a/spring-cloud-modules/spring-cloud-archaius/additional-sources-simple/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/pom.xml @@ -3,9 +3,9 @@ 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 - additional-sources-simple + spring-cloud-archaius-basic-config 1.0.0-SNAPSHOT - additional-sources-simple + spring-cloud-archaius-basic-config jar diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/BasicArchaiusApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/BasicArchaiusApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/BasicArchaiusApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/BasicArchaiusApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/controller/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/controller/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/controller/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/java/com/baeldung/spring/cloud/archaius/basic/controller/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/config.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/config.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/config.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/config.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/other.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/other.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/main/resources/other.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/main/resources/other.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/SpringContextTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/SpringContextTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/SpringContextTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/SpringContextTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/SpringContextTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/resources/config.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/resources/config.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/resources/config.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/resources/config.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/resources/logback-test.xml similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/basic-config/src/test/resources/logback-test.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-basic-config/src/test/resources/logback-test.xml diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml similarity index 92% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml index 08c96fb1f6..6e25ace6a8 100644 --- a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml @@ -3,8 +3,8 @@ 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 - dynamodb-config - dynamodb-config + spring-cloud-archaius-dynamodb-config + spring-cloud-archaius-dynamodb-config jar diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/DynamoSourcesApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/DynamoSourcesApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/DynamoSourcesApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/DynamoSourcesApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/ApplicationPropertiesConfigurations.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/ApplicationPropertiesConfigurations.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/ApplicationPropertiesConfigurations.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/ApplicationPropertiesConfigurations.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/DynamoDbConfiguration.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/DynamoDbConfiguration.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/DynamoDbConfiguration.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/config/DynamoDbConfiguration.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/controller/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/controller/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/controller/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/controller/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusProperties.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusProperties.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusProperties.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusProperties.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusPropertiesRepository.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusPropertiesRepository.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusPropertiesRepository.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/java/com/baeldung/spring/cloud/archaius/dynamosources/dynamodb/ArchaiusPropertiesRepository.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/ArchaiusDynamoDbLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/ArchaiusDynamoDbLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/ArchaiusDynamoDbLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/ArchaiusDynamoDbLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml similarity index 91% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml index 4113bf5bca..f90570abc2 100644 --- a/spring-cloud-modules/spring-cloud-archaius/extra-configs/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml @@ -3,9 +3,9 @@ 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 - extra-configs + spring-cloud-archaius-extra-configs 1.0.0-SNAPSHOT - extra-configs + spring-cloud-archaius-extra-configs jar diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/ExtraConfigsApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/ExtraConfigsApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/ExtraConfigsApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/ExtraConfigsApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/controllers/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/controllers/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/controllers/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/java/com/baeldung/spring/cloud/archaius/extraconfigs/controllers/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/other-config-dir/extra.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/other-config-dir/extra.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/other-config-dir/extra.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/other-config-dir/extra.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/other.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/other.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/main/resources/other.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/main/resources/other.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/java/com/baeldung/SpringContextTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/java/com/baeldung/SpringContextTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/java/com/baeldung/spring/cloud/archaius/extraconfigs/ArchaiusExtraConfigsLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/java/com/baeldung/spring/cloud/archaius/extraconfigs/ArchaiusExtraConfigsLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/java/com/baeldung/spring/cloud/archaius/extraconfigs/ArchaiusExtraConfigsLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/java/com/baeldung/spring/cloud/archaius/extraconfigs/ArchaiusExtraConfigsLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/resources/logback-test.xml similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/extra-configs/src/test/resources/logback-test.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/src/test/resources/logback-test.xml diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml similarity index 89% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml index dcaf934849..7fb5747739 100644 --- a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml @@ -3,8 +3,8 @@ 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 - jdbc-config - jdbc-config + spring-cloud-archaius-jdbc-config + spring-cloud-archaius-jdbc-config jar diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/JdbcSourcesApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/JdbcSourcesApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/JdbcSourcesApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/JdbcSourcesApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/config/ApplicationPropertiesConfigurations.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/config/ApplicationPropertiesConfigurations.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/config/ApplicationPropertiesConfigurations.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/config/ApplicationPropertiesConfigurations.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/controller/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/controller/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/controller/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/controller/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/jdbc/Properties.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/jdbc/Properties.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/jdbc/Properties.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/java/com/baeldung/spring/cloud/archaius/jdbconfig/jdbc/Properties.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/resources/data.sql b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/resources/data.sql similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/main/resources/data.sql rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/main/resources/data.sql diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/ArchaiusJDBCSourceLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/ArchaiusJDBCSourceLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/ArchaiusJDBCSourceLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/ArchaiusJDBCSourceLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/resources/logback-test.xml similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/jdbc-config/src/test/resources/logback-test.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/src/test/resources/logback-test.xml diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/pom.xml similarity index 92% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/pom.xml rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/pom.xml index 7700a2219d..f7c93fd9bf 100644 --- a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/pom.xml @@ -3,8 +3,8 @@ 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 - zookeeper-config - zookeeper-config + spring-cloud-archaius-zookeeper-config + spring-cloud-archaius-zookeeper-config jar diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ZookeeperConfigApplication.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ZookeeperConfigApplication.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ZookeeperConfigApplication.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ZookeeperConfigApplication.java diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/config/ZookeeperConfigsInitializer.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/config/ZookeeperConfigsInitializer.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/config/ZookeeperConfigsInitializer.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/config/ZookeeperConfigsInitializer.java diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/controller/ConfigPropertiesController.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/controller/ConfigPropertiesController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/controller/ConfigPropertiesController.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/controller/ConfigPropertiesController.java diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/resources/application.properties similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/main/resources/application.properties rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/main/resources/application.properties diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ArchaiusZookeeperLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ArchaiusZookeeperLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ArchaiusZookeeperLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/ArchaiusZookeeperLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java similarity index 100% rename from spring-cloud-modules/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java rename to spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java index 79785a3f20..8fc75e1ff6 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java @@ -1,7 +1,5 @@ package com.baeldung.spring.cloud.bootstrap.gateway; -import com.baeldung.spring.cloud.bootstrap.gateway.client.book.BooksClient; -import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.RatingsClient; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.EurekaClient; import org.springframework.beans.factory.annotation.Autowired; @@ -19,8 +17,6 @@ import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; import org.springframework.web.client.RestTemplate; import zipkin.Span; @@ -69,11 +65,10 @@ public class GatewayApplication { @Override public void report(Span span) { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); } + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } }; diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index 91fd23e32d..d787b5e407 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -42,11 +42,11 @@ public class BookServiceApplication { @Override public void report(Span span) { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); } + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); + if (!span.name.matches(skipPattern)) delegate.report(span); } }; } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java index 8dacbaa79d..5a94f19472 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java @@ -51,11 +51,10 @@ public class RatingServiceApplication { @Override public void report(Span span) { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); } + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } }; diff --git a/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-client/pom.xml b/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-client/pom.xml index 0c6212c877..c6dfa3189d 100644 --- a/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-client/pom.xml +++ b/spring-cloud-modules/spring-cloud-bus/spring-cloud-bus-client/pom.xml @@ -14,7 +14,6 @@ 1.0.0-SNAPSHOT - org.springframework.cloud diff --git a/spring-cloud-modules/spring-cloud-config/README.md b/spring-cloud-modules/spring-cloud-config/README.md index 788889c8d6..f80b4b508c 100644 --- a/spring-cloud-modules/spring-cloud-config/README.md +++ b/spring-cloud-modules/spring-cloud-config/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Quick Intro to Spring Cloud Configuration](http://www.baeldung.com/spring-cloud-configuration) +- [Overriding the Values of Remote Properties in Spring Cloud Config](https://www.baeldung.com/spring-cloud-config-remote-properties-override) diff --git a/spring-cloud-modules/spring-cloud-config/pom.xml b/spring-cloud-modules/spring-cloud-config/pom.xml index efbf30d0b2..c256e82d1b 100644 --- a/spring-cloud-modules/spring-cloud-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-config/pom.xml @@ -38,4 +38,4 @@ 2021.0.3 - + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-client/pom.xml b/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-client/pom.xml index d297e5b44d..06c6385928 100644 --- a/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-client/pom.xml +++ b/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-client/pom.xml @@ -37,4 +37,4 @@ - + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-server/pom.xml b/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-server/pom.xml index bcaa64e0d1..7eef867eeb 100644 --- a/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-config/spring-cloud-config-overriding-properties-server/pom.xml @@ -28,4 +28,4 @@ - + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-dapr/pom.xml b/spring-cloud-modules/spring-cloud-dapr/pom.xml index 24b6c989bd..2bac0e8eaf 100644 --- a/spring-cloud-modules/spring-cloud-dapr/pom.xml +++ b/spring-cloud-modules/spring-cloud-dapr/pom.xml @@ -13,8 +13,8 @@ - gateway - greeting + spring-cloud-dapr-gateway + spring-cloud-dapr-greeting \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-dapr/gateway/pom.xml b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/pom.xml similarity index 95% rename from spring-cloud-modules/spring-cloud-dapr/gateway/pom.xml rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/pom.xml index 6545c61002..7874edda4a 100644 --- a/spring-cloud-modules/spring-cloud-dapr/gateway/pom.xml +++ b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/pom.xml @@ -4,7 +4,7 @@ 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-dapr - gateway + spring-cloud-dapr-gateway 1.0-SNAPSHOT diff --git a/spring-cloud-modules/spring-cloud-dapr/gateway/src/main/java/com/baeldung/gateway/GatewayApp.java b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/java/com/baeldung/gateway/GatewayApp.java similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/gateway/src/main/java/com/baeldung/gateway/GatewayApp.java rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/java/com/baeldung/gateway/GatewayApp.java diff --git a/spring-cloud-modules/spring-cloud-dapr/gateway/src/main/resources/application-no-dapr.yml b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/resources/application-no-dapr.yml similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/gateway/src/main/resources/application-no-dapr.yml rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/resources/application-no-dapr.yml diff --git a/spring-cloud-modules/spring-cloud-dapr/gateway/src/main/resources/application-with-dapr.yml b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/resources/application-with-dapr.yml similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/gateway/src/main/resources/application-with-dapr.yml rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-gateway/src/main/resources/application-with-dapr.yml diff --git a/spring-cloud-modules/spring-cloud-dapr/greeting/pom.xml b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/pom.xml similarity index 93% rename from spring-cloud-modules/spring-cloud-dapr/greeting/pom.xml rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/pom.xml index 22b4004cbf..24aa2f4dcf 100644 --- a/spring-cloud-modules/spring-cloud-dapr/greeting/pom.xml +++ b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/pom.xml @@ -4,7 +4,7 @@ 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-dapr - greeting + spring-cloud-dapr-greeting 1.0-SNAPSHOT diff --git a/spring-cloud-modules/spring-cloud-dapr/greeting/src/main/java/com/baeldung/hello/GreetingApp.java b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/java/com/baeldung/hello/GreetingApp.java similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/greeting/src/main/java/com/baeldung/hello/GreetingApp.java rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/java/com/baeldung/hello/GreetingApp.java diff --git a/spring-cloud-modules/spring-cloud-dapr/greeting/src/main/java/com/baeldung/hello/GreetingController.java b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/java/com/baeldung/hello/GreetingController.java similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/greeting/src/main/java/com/baeldung/hello/GreetingController.java rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/java/com/baeldung/hello/GreetingController.java diff --git a/spring-cloud-modules/spring-cloud-dapr/greeting/src/main/resources/application.yml b/spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/resources/application.yml similarity index 100% rename from spring-cloud-modules/spring-cloud-dapr/greeting/src/main/resources/application.yml rename to spring-cloud-modules/spring-cloud-dapr/spring-cloud-dapr-greeting/src/main/resources/application.yml diff --git a/spring-cloud-modules/spring-cloud-gateway-2/README.md b/spring-cloud-modules/spring-cloud-gateway-2/README.md new file mode 100644 index 0000000000..578bfc623e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/README.md @@ -0,0 +1,7 @@ +## Spring Cloud Gateway 2 + +This module contains additional articles about Spring Cloud Gateway. + +### Relevant Articles: + +- [Rate Limiting With Client IP in Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-rate-limit-by-client-ip) diff --git a/spring-cloud-modules/spring-cloud-gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-gateway-2/pom.xml new file mode 100644 index 0000000000..22182e8c78 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + spring-cloud-gateway-2 + spring-cloud-gateway-2 + jar + + + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + it.ozimov + embedded-redis + ${redis.version} + test + + + org.hibernate + hibernate-validator-cdi + ${hibernate-validator.version} + + + javax.validation + validation-api + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-devtools + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + 6.0.2.Final + 0.7.2 + 9.19 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/GatewayApplication b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/GatewayApplication new file mode 100644 index 0000000000..53b2629dd0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/GatewayApplication @@ -0,0 +1,14 @@ +package com.baeldung.springcloudgateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/IpAddressApplication.java b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/IpAddressApplication.java new file mode 100644 index 0000000000..472c331404 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/IpAddressApplication.java @@ -0,0 +1,38 @@ +package com.baeldung.springcloudgateway.ipaddress; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +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.PropertySource; + +@SpringBootApplication() +@PropertySource("classpath:ipaddress-application.properties") +public class IpAddressApplication { + public static void main(String[] args) { + SpringApplication.run(IpAddressApplication.class, args); + } + + @Bean + public RouteLocator myRoutes(RouteLocatorBuilder builder) { + return builder.routes() + .route("requestratelimiter_route", p -> p + .path("/example") + .filters(f -> f.requestRateLimiter(r -> r.setRateLimiter(redisRateLimiter()))) + .uri("http://example.org")) + .route("ipaddress_route", p -> p + .path("/example2") + .filters(f -> f.requestRateLimiter(r -> r.setRateLimiter(redisRateLimiter()) + .setDenyEmptyKey(false) + .setKeyResolver(new SimpleClientAddressResolver()))) + .uri("http://example.org")) + .build(); + } + + @Bean + public RedisRateLimiter redisRateLimiter() { + return new RedisRateLimiter(1, 1, 1); + } +} diff --git a/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/ProxiedClientAddressResolver.java b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/ProxiedClientAddressResolver.java new file mode 100644 index 0000000000..25b1fbcf1f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/ProxiedClientAddressResolver.java @@ -0,0 +1,21 @@ +package com.baeldung.springcloudgateway.ipaddress; + +import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; +import org.springframework.cloud.gateway.support.ipresolver.XForwardedRemoteAddressResolver; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.net.InetSocketAddress; + +@Primary +@Component +public class ProxiedClientAddressResolver implements KeyResolver { + @Override + public Mono resolve(ServerWebExchange exchange) { + XForwardedRemoteAddressResolver resolver = XForwardedRemoteAddressResolver.maxTrustedIndex(1); + InetSocketAddress inetSocketAddress = resolver.resolve(exchange); + return Mono.just(inetSocketAddress.getAddress().getHostAddress()); + } +} diff --git a/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/SimpleClientAddressResolver.java b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/SimpleClientAddressResolver.java new file mode 100644 index 0000000000..904fd4c193 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/src/main/java/com/baeldung/springcloudgateway/ipaddress/SimpleClientAddressResolver.java @@ -0,0 +1,23 @@ +package com.baeldung.springcloudgateway.ipaddress; + +import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Optional; + +@Component +public class SimpleClientAddressResolver implements KeyResolver { + @Override + public Mono resolve(ServerWebExchange exchange) { + return Optional.ofNullable(exchange.getRequest().getRemoteAddress()) + .map(InetSocketAddress::getAddress) + .map(InetAddress::getHostAddress) + .map(Mono::just) + .orElse(Mono.empty()); + } +} + diff --git a/spring-cloud-modules/spring-cloud-gateway-2/src/main/resources/ipaddress-application.properties b/spring-cloud-modules/spring-cloud-gateway-2/src/main/resources/ipaddress-application.properties new file mode 100644 index 0000000000..ebec52403a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-gateway-2/src/main/resources/ipaddress-application.properties @@ -0,0 +1,6 @@ +server.port=8081 +spring.redis.database=0 +spring.redis.host=localhost +spring.redis.port=16379 +spring.redis.password=mypass +spring.redis.timeout=60000 diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/README.md b/spring-cloud-modules/spring-cloud-open-telemetry/README.md new file mode 100644 index 0000000000..4a24159982 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [OpenTelemetry Setup in Spring Boot Application](https://www.baeldung.com/spring-boot-opentelemetry-setup) diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/docker-compose.yml b/spring-cloud-modules/spring-cloud-open-telemetry/docker-compose.yml new file mode 100644 index 0000000000..7ee2f67c0f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/docker-compose.yml @@ -0,0 +1,30 @@ +version: "4.0" + +services: + product-service: + platform: linux/x86_64 + build: spring-cloud-open-telemetry1/ + ports: + - "8080:8080" + + price-service: + platform: linux/x86_64 + build: spring-cloud-open-telemetry2/ + ports: + - "8081" + + jaeger-service: + image: jaegertracing/all-in-one:latest + ports: + - "16686:16686" + - "14250" + + collector: + image: otel/opentelemetry-collector:0.72.0 + command: [ "--config=/etc/otel-collector-config.yml" ] + volumes: + - ./otel-config.yml:/etc/otel-collector-config.yml + ports: + - "4317:4317" + depends_on: + - jaeger-service \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/otel-config.yml b/spring-cloud-modules/spring-cloud-open-telemetry/otel-config.yml new file mode 100644 index 0000000000..4402603a85 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/otel-config.yml @@ -0,0 +1,23 @@ +receivers: + otlp: + protocols: + grpc: + http: + +processors: + batch: + +exporters: + logging: + loglevel: debug + jaeger: + endpoint: jaeger-service:14250 + tls: + insecure: true + +service: + pipelines: + traces: + receivers: [ otlp ] + processors: [ batch ] + exporters: [ logging, jaeger ] diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/pom.xml b/spring-cloud-modules/spring-cloud-open-telemetry/pom.xml new file mode 100644 index 0000000000..69b3a1a478 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + com.baeldung.spring.cloud + spring-cloud-open-telemetry + 1.0.0-SNAPSHOT + spring-cloud-open-telemetry + pom + + + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT + + + + spring-cloud-open-telemetry1 + spring-cloud-open-telemetry2 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/Dockerfile b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/Dockerfile new file mode 100644 index 0000000000..50cd35ed84 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/Dockerfile @@ -0,0 +1,7 @@ +FROM adoptopenjdk/openjdk11:alpine + +COPY target/spring-cloud-open-telemetry1-1.0.0-SNAPSHOT.jar spring-cloud-open-telemetry.jar + +EXPOSE 8080 + +ENTRYPOINT ["java","-jar","/spring-cloud-open-telemetry.jar"] \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/pom.xml b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/pom.xml new file mode 100644 index 0000000000..3003113085 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + spring-cloud-open-telemetry1 + com.baeldung.spring.cloud + 1.0.0-SNAPSHOT + spring-cloud-open-telemetry1 + jar + + + com.baeldung.spring.cloud + spring-cloud-open-telemetry + 1.0.0-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-dependencies.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${release.train.version} + pom + import + + + org.springframework.cloud + spring-cloud-sleuth-otel-dependencies + ${spring-cloud-sleuth-otel.version} + import + pom + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-sleuth + + + org.springframework.cloud + spring-cloud-sleuth-brave + + + + + org.springframework.cloud + spring-cloud-sleuth-otel-autoconfigure + + + io.opentelemetry + opentelemetry-exporter-otlp + ${otel-exporter-otlp.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + 2.7.9 + 2021.0.5 + 1.1.2 + 1.23.1 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/ProductApplication.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/ProductApplication.java new file mode 100644 index 0000000000..8427603340 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/ProductApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.opentelemetry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ProductApplication { + + public static void main(String[] args) { + SpringApplication.run(ProductApplication.class, args); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/api/client/PriceClient.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/api/client/PriceClient.java new file mode 100644 index 0000000000..d8b43b61a5 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/api/client/PriceClient.java @@ -0,0 +1,34 @@ +package com.baeldung.opentelemetry.api.client; + +import com.baeldung.opentelemetry.model.Price; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.client.RestTemplate; + +@Component +public class PriceClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(PriceClient.class); + + private final RestTemplate restTemplate; + + @Autowired + public PriceClient(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Value("${priceClient.baseUrl}") + private String baseUrl; + + public Price getPrice(@PathVariable("id") long productId){ + LOGGER.info("Fetching Price Details With Product Id {}", productId); + String url = String.format("%s/price/%d", baseUrl, productId); + ResponseEntity price = restTemplate.getForEntity(url, Price.class); + return price.getBody(); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/configuration/RestConfiguration.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/configuration/RestConfiguration.java new file mode 100644 index 0000000000..5d8ba4beac --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/configuration/RestConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.opentelemetry.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestConfiguration { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/controller/ProductController.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/controller/ProductController.java new file mode 100644 index 0000000000..5586f5e9d0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/controller/ProductController.java @@ -0,0 +1,36 @@ +package com.baeldung.opentelemetry.controller; + +import com.baeldung.opentelemetry.api.client.PriceClient; +import com.baeldung.opentelemetry.model.Product; +import com.baeldung.opentelemetry.repository.ProductRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.RestController; + +@RestController +public class ProductController { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProductController.class); + + private final PriceClient priceClient; + + private final ProductRepository productRepository; + + @Autowired + public ProductController(PriceClient priceClient, ProductRepository productRepository) { + this.priceClient = priceClient; + this.productRepository = productRepository; + } + + @GetMapping(path = "/product/{id}") + public Product getProductDetails(@PathVariable("id") long productId){ + LOGGER.info("Getting Product and Price Details With Product Id {}", productId); + Product product = productRepository.getProduct(productId); + product.setPrice(priceClient.getPrice(productId)); + + return product; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java new file mode 100644 index 0000000000..0ab031f517 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java @@ -0,0 +1,22 @@ +package com.baeldung.opentelemetry.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.client.HttpServerErrorException; + + +@RestControllerAdvice +public class ProductControllerAdvice { + + @ExceptionHandler(ProductNotFoundException.class) + public ResponseEntity handleProductNotFoundException(ProductNotFoundException exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(HttpServerErrorException.ServiceUnavailable.class) + public ResponseEntity handleException(HttpServerErrorException.ServiceUnavailable exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductNotFoundException.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductNotFoundException.java new file mode 100644 index 0000000000..9b698d5416 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/exception/ProductNotFoundException.java @@ -0,0 +1,7 @@ +package com.baeldung.opentelemetry.exception; + +public class ProductNotFoundException extends RuntimeException { + public ProductNotFoundException(String productNotFound) { + super(productNotFound); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Price.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Price.java new file mode 100644 index 0000000000..dccaf978fd --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Price.java @@ -0,0 +1,39 @@ +package com.baeldung.opentelemetry.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Price { + + @JsonProperty("productId") + private long productId; + + @JsonProperty("price_amount") + private double priceAmount; + + @JsonProperty("discount") + private double discount; + + public long getProductId() { + return productId; + } + + public void setProductId(long productId) { + this.productId = productId; + } + + public double getPriceAmount() { + return priceAmount; + } + + public void setPriceAmount(double priceAmount) { + this.priceAmount = priceAmount; + } + + public double getDiscount() { + return discount; + } + + public void setDiscount(double discount) { + this.discount = discount; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Product.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Product.java new file mode 100644 index 0000000000..2a3a279dd8 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/model/Product.java @@ -0,0 +1,27 @@ +package com.baeldung.opentelemetry.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Product { + + @JsonProperty("id") + private long id; + + @JsonProperty("name") + private String name; + + @JsonProperty("price") + private Price price; + + public void setId(long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setPrice(Price price) { + this.price = price; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/repository/ProductRepository.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/repository/ProductRepository.java new file mode 100644 index 0000000000..07f94f626e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/java/com/baeldung/opentelemetry/repository/ProductRepository.java @@ -0,0 +1,55 @@ +package com.baeldung.opentelemetry.repository; + +import com.baeldung.opentelemetry.exception.ProductNotFoundException; +import com.baeldung.opentelemetry.model.Product; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Component +public class ProductRepository { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProductRepository.class); + + private final Map productMap = new HashMap<>(); + + public Product getProduct(Long productId){ + LOGGER.info("Getting Product from Product Repo With Product Id {}", productId); + + if(!productMap.containsKey(productId)){ + LOGGER.error("Product Not Found for Product Id {}", productId); + throw new ProductNotFoundException("Product Not Found"); + } + + return productMap.get(productId); + } + + @PostConstruct + private void setupRepo() { + Product product1 = getProduct(100001, "apple"); + productMap.put(100001L, product1); + + Product product2 = getProduct(100002, "pears"); + productMap.put(100002L, product2); + + Product product3 = getProduct(100003, "banana"); + productMap.put(100003L, product3); + + Product product4 = getProduct(100004, "mango"); + productMap.put(100004L, product4); + + Product product5 = getProduct(100005, "test"); + productMap.put(100005L, product5); + } + + private static Product getProduct(int id, String name) { + Product product = new Product(); + product.setId(id); + product.setName(name); + return product; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/resources/application.properties new file mode 100644 index 0000000000..1645b6144d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/main/resources/application.properties @@ -0,0 +1,5 @@ +server.port= 8080 +spring.application.name=product-service +priceClient.baseUrl=http://price-service:8081 +spring.sleuth.otel.config.trace-id-ratio-based=1.0 +spring.sleuth.otel.exporter.otlp.endpoint=http://collector:4317 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java new file mode 100644 index 0000000000..4f4a918cb4 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java @@ -0,0 +1,16 @@ +package com.baeldung.opentelemetry; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = ProductApplication.class) +class SpringContextTest { + + @Test + void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/controller/ProductControllerUnitTest.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/controller/ProductControllerUnitTest.java new file mode 100644 index 0000000000..fcb3e23752 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry1/src/test/java/com/baeldung/opentelemetry/controller/ProductControllerUnitTest.java @@ -0,0 +1,92 @@ +package com.baeldung.opentelemetry.controller; + +import com.baeldung.opentelemetry.api.client.PriceClient; +import com.baeldung.opentelemetry.exception.ProductNotFoundException; +import com.baeldung.opentelemetry.model.Price; +import com.baeldung.opentelemetry.model.Product; +import com.baeldung.opentelemetry.repository.ProductRepository; +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.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.HttpServerErrorException; + + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@ExtendWith(SpringExtension.class) +@WebMvcTest(ProductController.class) +class ProductControllerUnitTest { + + @MockBean + private PriceClient priceCLient; + + @MockBean + private ProductRepository productRepository; + + @Autowired + private MockMvc mockMvc; + + + @Test + void givenProductandPriceDataAvailable_whenGetProductCalled_thenReturnProductDetails() throws Exception { + long productId = 100000L; + + Price price = createPrice(productId); + Product product = createProduct(productId); + product.setPrice(price); + + when(productRepository.getProduct(productId)).thenReturn(product); + when(priceCLient.getPrice(productId)).thenReturn(price); + + mockMvc.perform(get("/product/" + productId)) + .andExpect(status().is(HttpStatus.OK.value())); + } + + @Test + void givenProductNotFound_whenGetProductCalled_thenReturnInternalServerError() throws Exception { + long productId = 100000L; + Price price = createPrice(productId); + + when(productRepository.getProduct(productId)).thenThrow(ProductNotFoundException.class); + when(priceCLient.getPrice(productId)).thenReturn(price); + + mockMvc.perform(get("/product/" + productId)) + .andExpect(status().is(HttpStatus.NOT_FOUND.value())); + } + + @Test + void givenPriceServiceNotAvailable_whenGetProductCalled_thenReturnInternalServerError() throws Exception { + long productId = 100000L; + Product product = createProduct(productId); + + when(productRepository.getProduct(productId)).thenReturn(product); + when(priceCLient.getPrice(productId)).thenThrow(HttpServerErrorException.ServiceUnavailable.class); + + mockMvc.perform(get("/product/" + productId)) + .andExpect(status().is(HttpStatus.INTERNAL_SERVER_ERROR.value())); + } + + private static Product createProduct(long productId) { + Product product = new Product(); + product.setId(productId); + product.setName("test"); + return product; + } + + private static Price createPrice(long productId) { + Price price = new Price(); + price.setProductId(productId); + price.setPriceAmount(12.00); + price.setDiscount(2.5); + return price; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/Dockerfile b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/Dockerfile new file mode 100644 index 0000000000..fb0e3b3263 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/Dockerfile @@ -0,0 +1,7 @@ +FROM adoptopenjdk/openjdk11:alpine + +COPY target/spring-cloud-open-telemetry2-1.0.0-SNAPSHOT.jar spring-cloud-open-telemetry.jar + +EXPOSE 8081 + +ENTRYPOINT ["java","-jar","/spring-cloud-open-telemetry.jar"] \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/pom.xml b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/pom.xml new file mode 100644 index 0000000000..4f56cc717e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + spring-cloud-open-telemetry2 + com.baeldung.spring.cloud + 1.0.0-SNAPSHOT + spring-cloud-open-telemetry2 + jar + + + com.baeldung.spring.cloud + spring-cloud-open-telemetry + 1.0.0-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-dependencies.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${release.train.version} + pom + import + + + org.springframework.cloud + spring-cloud-sleuth-otel-dependencies + ${spring-cloud-sleuth-otel.version} + import + pom + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-sleuth + + + org.springframework.cloud + spring-cloud-sleuth-brave + + + + + org.springframework.cloud + spring-cloud-sleuth-otel-autoconfigure + + + io.opentelemetry + opentelemetry-exporter-otlp + ${otel-exporter-otlp.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + 2.7.9 + 2021.0.5 + 1.1.2 + 1.23.1 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/PriceApplication.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/PriceApplication.java new file mode 100644 index 0000000000..75db68c624 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/PriceApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.opentelemetry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PriceApplication { + + public static void main(String[] args) { + SpringApplication.run(PriceApplication.class, args); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/controller/PriceController.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/controller/PriceController.java new file mode 100644 index 0000000000..6142d4da10 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/controller/PriceController.java @@ -0,0 +1,29 @@ +package com.baeldung.opentelemetry.controller; + +import com.baeldung.opentelemetry.model.Price; +import com.baeldung.opentelemetry.repository.PriceRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.RestController; + +@RestController +public class PriceController { + + private static final Logger LOGGER = LoggerFactory.getLogger(PriceController.class); + + private final PriceRepository priceRepository; + + @Autowired + public PriceController(PriceRepository priceRepository) { + this.priceRepository = priceRepository; + } + + @GetMapping(path = "/price/{id}") + public Price getPrice(@PathVariable("id") long productId) { + LOGGER.info("Getting Price details for Product Id {}", productId); + return priceRepository.getPrice(productId); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/PriceNotFoundException.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/PriceNotFoundException.java new file mode 100644 index 0000000000..6e1c5e0b5e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/PriceNotFoundException.java @@ -0,0 +1,7 @@ +package com.baeldung.opentelemetry.exception; + +public class PriceNotFoundException extends RuntimeException { + public PriceNotFoundException(String priceNotFound) { + super(priceNotFound); + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java new file mode 100644 index 0000000000..fe7789ecf5 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/exception/ProductControllerAdvice.java @@ -0,0 +1,16 @@ +package com.baeldung.opentelemetry.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ProductControllerAdvice { + + @ExceptionHandler(PriceNotFoundException.class) + public ResponseEntity handlePriceNotFoundException(PriceNotFoundException exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND); + } + +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/model/Price.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/model/Price.java new file mode 100644 index 0000000000..0e30c4e25b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/model/Price.java @@ -0,0 +1,27 @@ +package com.baeldung.opentelemetry.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Price { + + @JsonProperty("productId") + private long productId; + + @JsonProperty("price_amount") + private double priceAmount; + + @JsonProperty("discount") + private double discount; + + public void setDiscount(double discount) { + this.discount = discount; + } + + public void setProductId(long productId) { + this.productId = productId; + } + + public void setPriceAmount(double priceAmount) { + this.priceAmount = priceAmount; + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/repository/PriceRepository.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/repository/PriceRepository.java new file mode 100644 index 0000000000..63af7548d9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/java/com/baeldung/opentelemetry/repository/PriceRepository.java @@ -0,0 +1,53 @@ +package com.baeldung.opentelemetry.repository; + +import com.baeldung.opentelemetry.model.Price; +import com.baeldung.opentelemetry.exception.PriceNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Component +public class PriceRepository { + + private static final Logger LOGGER = LoggerFactory.getLogger(PriceRepository.class); + + private final Map priceMap = new HashMap<>(); + + public Price getPrice(Long productId){ + LOGGER.info("Getting Price from Price Repo With Product Id {}", productId); + + if(!priceMap.containsKey(productId)){ + LOGGER.error("Price Not Found for Product Id {}", productId); + throw new PriceNotFoundException("Product Not Found"); + } + + return priceMap.get(productId); + } + + @PostConstruct + private void setupRepo(){ + Price price1 = getPrice(100001L, 12.5, 2.5); + priceMap.put(100001L, price1); + + Price price2 = getPrice(100002L, 10.5, 2.1); + priceMap.put(100002L, price2); + + Price price3 = getPrice(100003L, 18.5, 2.0); + priceMap.put(100003L, price3); + + Price price4 = getPrice(100004L, 18.5, 2.0); + priceMap.put(100004L, price4); + } + + private static Price getPrice(long productId, double priceAmount, double discount) { + Price price = new Price(); + price.setProductId(productId); + price.setPriceAmount(priceAmount); + price.setDiscount(discount); + return price; + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/resources/application.properties new file mode 100644 index 0000000000..03b80ae271 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/main/resources/application.properties @@ -0,0 +1,4 @@ +server.port= 8081 +spring.application.name=price-service +spring.sleuth.otel.config.trace-id-ratio-based=1.0 +spring.sleuth.otel.exporter.otlp.endpoint=http://collector:4317 diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java new file mode 100644 index 0000000000..524cc30567 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/SpringContextTest.java @@ -0,0 +1,16 @@ +package com.baeldung.opentelemetry; + +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = PriceApplication.class) +class SpringContextTest { + + @Test + void whenSpringContextIsBootstrapped_thenNoException() { + } +} diff --git a/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/controller/PriceControllerUnitTest.java b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/controller/PriceControllerUnitTest.java new file mode 100644 index 0000000000..7fd87c99d1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-open-telemetry/spring-cloud-open-telemetry2/src/test/java/com/baeldung/opentelemetry/controller/PriceControllerUnitTest.java @@ -0,0 +1,57 @@ +package com.baeldung.opentelemetry.controller; + + +import com.baeldung.opentelemetry.exception.PriceNotFoundException; +import com.baeldung.opentelemetry.model.Price; +import com.baeldung.opentelemetry.repository.PriceRepository; +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.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@ExtendWith(SpringExtension.class) +@WebMvcTest(PriceController.class) +class PriceControllerUnitTest { + + @MockBean + private PriceRepository priceRepository; + + @Autowired + private MockMvc mockMvc; + + @Test + void givenProductandPriceAvailable_whenGetProductCalled_thenReturnProductDetails() throws Exception { + long productId = 100000L; + Price price = new Price(); + price.setProductId(productId); + price.setPriceAmount(12.00); + price.setDiscount(2.5); + + when(priceRepository.getPrice(productId)).thenReturn(price); + + mockMvc.perform(get("/price/" + productId)) + .andExpect(status().is(HttpStatus.OK.value())); + } + + + @Test + void givenProductNotFound_whenGetProductCalled_thenReturnInternalServerError() throws Exception { + long productId = 100000L; + + when(priceRepository.getPrice(productId)).thenThrow(PriceNotFoundException.class); + + mockMvc.perform(get("/price/" + productId)) + .andExpect(status().is(HttpStatus.NOT_FOUND.value())); + } + +} diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/README.md b/spring-cloud-modules/spring-cloud-openfeign-2/README.md deleted file mode 100644 index bc306e2302..0000000000 --- a/spring-cloud-modules/spring-cloud-openfeign-2/README.md +++ /dev/null @@ -1,4 +0,0 @@ - -### Relevant Articles: - -- [Feign Client Exception Handling](https://www.baeldung.com/java-feign-client-exception-handling) diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml b/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml deleted file mode 100644 index 43cc7c6c50..0000000000 --- a/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - 4.0.0 - com.baeldung.cloud - spring-cloud-openfeign-2 - spring-cloud-openfeign-2 - OpenFeign project for Spring Boot - - - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - - io.github.openfeign - feign-okhttp - - - org.springframework.boot - spring-boot-starter-web - - - io.github.openfeign.form - feign-form - ${feign-form.version} - - - io.github.openfeign.form - feign-form-spring - - - org.springframework.boot - spring-boot-starter-test - test - - - - - 2021.0.3 - 3.8.0 - - - \ No newline at end of file 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 deleted file mode 100644 index 7188b74c9b..0000000000 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties +++ /dev/null @@ -1,10 +0,0 @@ -server.port=8085 -spring.main.allow-bean-definition-overriding=true -spring.application.name= openfeign -logging.level.com.baeldung.cloud.openfeign.client: DEBUG -feign.hystrix.enabled=true - -spring.security.oauth2.client.registration.keycloak.authorization-grant-type=client_credentials -spring.security.oauth2.client.registration.keycloak.client-id=payment-app -spring.security.oauth2.client.registration.keycloak.client-secret=863e9de4-33d4-4471-b35e-f8d2434385bb -spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8083/auth/realms/master/protocol/openid-connect/token diff --git a/spring-cloud-modules/spring-cloud-openfeign/README.md b/spring-cloud-modules/spring-cloud-openfeign/README.md index 421fa0284f..62434b35b8 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/README.md +++ b/spring-cloud-modules/spring-cloud-openfeign/README.md @@ -2,9 +2,6 @@ - [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign) - [Differences Between Netflix Feign and OpenFeign](https://www.baeldung.com/netflix-feign-vs-openfeign) -- [File Upload With Open Feign](https://www.baeldung.com/java-feign-file-upload) -- [Feign Logging Configuration](https://www.baeldung.com/java-feign-logging) - [Provide an OAuth2 Token to a Feign Client](https://www.baeldung.com/spring-cloud-feign-oauth-token) -- [Retrieve Original Message From Feign ErrorDecoder](https://www.baeldung.com/feign-retrieve-original-message) -- [RequestLine with Feign Client](https://www.baeldung.com/feign-requestline) - [Propagating Exceptions With OpenFeign and Spring](https://www.baeldung.com/spring-openfeign-propagate-exception) +- [Feign Client Exception Handling](https://www.baeldung.com/java-feign-client-exception-handling) diff --git a/spring-cloud-modules/spring-cloud-openfeign/pom.xml b/spring-cloud-modules/spring-cloud-openfeign/pom.xml index 570cb6a082..88ad38517b 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/pom.xml +++ b/spring-cloud-modules/spring-cloud-openfeign/pom.xml @@ -61,12 +61,6 @@ spring-boot-starter-test test - - com.github.tomakehurst - wiremock-jre8 - 2.33.2 - test - diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/UserClient.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/UserClient.java deleted file mode 100644 index 9416bd30f0..0000000000 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/UserClient.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.cloud.openfeign.client; - -import com.baeldung.cloud.openfeign.config.FeignConfig; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -@FeignClient(name = "user-client", url="https://jsonplaceholder.typicode.com", configuration = FeignConfig.class) -public interface UserClient { - - @RequestMapping(value = "/users", method = RequestMethod.GET) - String getUsers(); -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java index 09bf8bf54b..5ebd7b6887 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/RetreiveMessageErrorDecoder.java @@ -12,7 +12,6 @@ import feign.codec.ErrorDecoder; public class RetreiveMessageErrorDecoder implements ErrorDecoder { private final ErrorDecoder errorDecoder = new Default(); - @Override public Exception decode(String methodKey, Response response) { ExceptionMessage message = null; diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientFallbackFactory.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientFallbackFactory.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientFallbackFactory.java rename to spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientFallbackFactory.java diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallBack.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallBack.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallBack.java rename to spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallBack.java diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackFactory.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackFactory.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackFactory.java rename to spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackFactory.java diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackImpl.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackImpl.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackImpl.java rename to spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/FileUploadClientWithFallbackImpl.java diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java index 26e658a7f0..2d5090897d 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java @@ -9,7 +9,7 @@ import feign.Response; public interface UploadResource { - @RequestLine("POST /upload-file") + @RequestLine("POST /upload-error") @Headers("Content-Type: multipart/form-data") Response uploadFile(@Param("file") MultipartFile file); diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java index c0d1962a71..244a5a2168 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java @@ -13,20 +13,22 @@ public class UploadService { private static final String HTTP_FILE_UPLOAD_URL = "http://localhost:8081"; @Autowired - private UploadClient client; - + private FileUploadClientWithFallbackFactory fileUploadClient; + @Autowired + private FileUploadClientWithFallBack fileUploadClientWithFallback; + public boolean uploadFileWithManualClient(MultipartFile file) { UploadResource fileUploadResource = Feign.builder().encoder(new SpringFormEncoder()) .target(UploadResource.class, HTTP_FILE_UPLOAD_URL); Response response = fileUploadResource.uploadFile(file); return response.status() == 200; } - - public String uploadFile(MultipartFile file) { - return client.fileUpload(file); + + public String uploadFileWithFallbackFactory(MultipartFile file) { + return fileUploadClient.fileUpload(file); } - - public String uploadFileError(MultipartFile file) { - return client.fileUpload(file); + + public String uploadFileWithFallback(MultipartFile file) { + return fileUploadClientWithFallback.fileUpload(file); } } \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java index f558e07491..6396be2453 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java @@ -14,6 +14,7 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.multipart.MultipartFile; +import com.baeldung.cloud.openfeign.exception.NotFoundException; import com.baeldung.cloud.openfeign.fileupload.service.UploadService; @RunWith(SpringRunner.class) @@ -25,26 +26,36 @@ public class OpenFeignFileUploadLiveTest { private static String FILE_NAME = "fileupload.txt"; - @Test - public void whenFeignBuilder_thenFileUploadSuccess() throws IOException { + @Test(expected = NotFoundException.class) + public void whenFileUploadClientFallbackFactory_thenFileUploadError() throws IOException { ClassLoader classloader = Thread.currentThread().getContextClassLoader(); File file = new File(classloader.getResource(FILE_NAME).getFile()); Assert.assertTrue(file.exists()); FileInputStream input = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input)); - Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile)); + uploadService.uploadFileWithFallbackFactory(multipartFile); + } + + @Test(expected = NotFoundException.class) + public void whenFileUploadClientFallback_thenFileUploadError() throws IOException { + ClassLoader classloader = Thread.currentThread().getContextClassLoader(); + File file = new File(classloader.getResource(FILE_NAME).getFile()); + Assert.assertTrue(file.exists()); + FileInputStream input = new FileInputStream(file); + MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", + IOUtils.toByteArray(input)); + uploadService.uploadFileWithFallback(multipartFile); } - @Test - public void whenAnnotatedFeignClient_thenFileUploadSuccess() throws IOException { + @Test(expected = NotFoundException.class) + public void whenFileUploadWithMannualClient_thenFileUploadError() throws IOException { ClassLoader classloader = Thread.currentThread().getContextClassLoader(); File file = new File(classloader.getResource(FILE_NAME).getFile()); Assert.assertTrue(file.exists()); FileInputStream input = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input)); - String uploadFile = uploadService.uploadFile(multipartFile); - Assert.assertNotNull(uploadFile); + uploadService.uploadFileWithManualClient(multipartFile); } } diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/pom.xml b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/pom.xml index c7d3f5d12c..9d0d91b2c0 100644 --- a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/pom.xml @@ -1,44 +1,54 @@ - 4.0.0 - spring-cloud-stream-kinesis - spring-cloud-stream-kinesis + 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-cloud-stream-kinesis + spring-cloud-stream-kinesis - - com.baeldung - spring-cloud-stream - 1.0.0-SNAPSHOT - + + com.baeldung + spring-cloud-stream + 1.0.0-SNAPSHOT + - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.cloud - spring-cloud-stream-binder-kinesis - ${spring-cloud-stream-kinesis-binder.version} - - - com.amazonaws - aws-java-sdk-kinesis - ${aws-sdk.version} - - - org.springframework.cloud - spring-cloud-stream-test-support - ${spring-cloud-stream-test.version} - test - - + + + org.springframework.boot + spring-boot-starter-web + + + com.amazonaws + aws-java-sdk-kinesis + ${aws-sdk.version} + + + org.springframework.cloud + spring-cloud-stream-test-support + ${spring-cloud-stream-test.version} + test + + + com.amazonaws + amazon-kinesis-producer + 0.13.1 + + + com.amazonaws + amazon-kinesis-client + 1.14.9 + + + org.springframework.cloud + spring-cloud-stream-binder-kinesis + ${spring-cloud-stream-kinesis-binder.version} + + - - 1.11.632 - 2.0.2.RELEASE - 2.2.1.RELEASE - + + 1.12.380 + 2.2.0 + 4.0.0 + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/KinesisApplication.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/KinesisApplication.java deleted file mode 100644 index c863cd8fe2..0000000000 --- a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/KinesisApplication.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.baeldung; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.messaging.support.MessageBuilder; - -@SpringBootApplication -@EnableBinding(Processor.class) -public class KinesisApplication { - - public static void main(String[] args) { - SpringApplication.run(KinesisApplication.class, args); - } - - @Autowired - private Processor processor; - - @StreamListener(Processor.INPUT) - public void consume(String val) { - System.out.println(val); - } - - public void produce(String val) { - processor.output().send(MessageBuilder.withPayload(val).build()); - } -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ConsumerBinder.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ConsumerBinder.java new file mode 100644 index 0000000000..1fedec83ad --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ConsumerBinder.java @@ -0,0 +1,16 @@ +package com.baeldung.binder; + +import java.util.function.Consumer; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ConsumerBinder { + @Bean + Consumer input() { + return str -> { + System.out.println(str); + }; + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/KinesisBinderApplication.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/KinesisBinderApplication.java new file mode 100644 index 0000000000..1cf31f9928 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/KinesisBinderApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.binder; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class KinesisBinderApplication { + + public static void main(String[] args) { + SpringApplication.run(KinesisBinderApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ProducerBinder.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ProducerBinder.java new file mode 100644 index 0000000000..1486459a1e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/binder/ProducerBinder.java @@ -0,0 +1,20 @@ +package com.baeldung.binder; + +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.support.MessageBuilder; + +@Configuration +class ProducerBinder { + + @Bean + public Supplier output() { + return () -> IntStream.range(1, 200) + .mapToObj(ipSuffix -> "192.168.0." + ipSuffix) + .map(entry -> MessageBuilder.withPayload(entry) + .build()); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessor.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessor.java new file mode 100644 index 0000000000..c028f530dc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessor.java @@ -0,0 +1,20 @@ +package com.baeldung.kclkpl; + +import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor; +import com.amazonaws.services.kinesis.clientlibrary.types.InitializationInput; +import com.amazonaws.services.kinesis.clientlibrary.types.ProcessRecordsInput; +import com.amazonaws.services.kinesis.clientlibrary.types.ShutdownInput; + +public class IpProcessor implements IRecordProcessor { + @Override + public void initialize(InitializationInput initializationInput) { } + + @Override + public void processRecords(ProcessRecordsInput processRecordsInput) { + processRecordsInput.getRecords() + .forEach(record -> System.out.println(new String(record.getData().array()))); + } + + @Override + public void shutdown(ShutdownInput shutdownInput) { } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessorFactory.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessorFactory.java new file mode 100644 index 0000000000..7515e65eff --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProcessorFactory.java @@ -0,0 +1,11 @@ +package com.baeldung.kclkpl; + +import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor; +import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory; + +public class IpProcessorFactory implements IRecordProcessorFactory { + @Override + public IRecordProcessor createProcessor() { + return new IpProcessor(); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProducer.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProducer.java new file mode 100644 index 0000000000..76111cfe57 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/IpProducer.java @@ -0,0 +1,30 @@ +package com.baeldung.kclkpl; + +import java.nio.ByteBuffer; +import java.util.stream.IntStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.amazonaws.services.kinesis.producer.KinesisProducer; + +@Component +public class IpProducer { + + @Value("${ips.stream}") + private String IPS_STREAM; + + @Value("${ips.partition.key}") + private String IPS_PARTITION_KEY; + + @Autowired + private KinesisProducer kinesisProducer; + + @Scheduled(fixedDelay = 3000L) + private void produce() { + IntStream.range(1, 200).mapToObj(ipSuffix -> ByteBuffer.wrap(("192.168.0." + ipSuffix).getBytes())) + .forEach(entry -> kinesisProducer.addUserRecord(IPS_STREAM, IPS_PARTITION_KEY, entry)); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKCLApplication.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKCLApplication.java new file mode 100644 index 0000000000..1ab205d3aa --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKCLApplication.java @@ -0,0 +1,49 @@ +package com.baeldung.kclkpl; + +import static com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration.*; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration; +import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker; + +@SpringBootApplication +public class KinesisKCLApplication implements ApplicationRunner { + + @Value("${aws.access.key}") + private String accessKey; + + @Value("${aws.secret.key}") + private String secretKey; + + @Value("${ips.stream}") + private String IPS_STREAM; + + public static void main(String[] args) { + SpringApplication.run(KinesisKCLApplication.class, args); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + + KinesisClientLibConfiguration consumerConfig = new KinesisClientLibConfiguration("KinesisKCLConsumer", IPS_STREAM, "", "", DEFAULT_INITIAL_POSITION_IN_STREAM, new AWSStaticCredentialsProvider(awsCredentials), + new AWSStaticCredentialsProvider(awsCredentials), new AWSStaticCredentialsProvider(awsCredentials), DEFAULT_FAILOVER_TIME_MILLIS, "KinesisKCLConsumer", DEFAULT_MAX_RECORDS, DEFAULT_IDLETIME_BETWEEN_READS_MILLIS, + DEFAULT_DONT_CALL_PROCESS_RECORDS_FOR_EMPTY_RECORD_LIST, DEFAULT_PARENT_SHARD_POLL_INTERVAL_MILLIS, DEFAULT_SHARD_SYNC_INTERVAL_MILLIS, DEFAULT_CLEANUP_LEASES_UPON_SHARDS_COMPLETION, new ClientConfiguration(), new ClientConfiguration(), + new ClientConfiguration(), DEFAULT_TASK_BACKOFF_TIME_MILLIS, DEFAULT_METRICS_BUFFER_TIME_MILLIS, DEFAULT_METRICS_MAX_QUEUE_SIZE, DEFAULT_VALIDATE_SEQUENCE_NUMBER_BEFORE_CHECKPOINTING, Regions.EU_CENTRAL_1.getName(), DEFAULT_SHUTDOWN_GRACE_MILLIS, + DEFAULT_DDB_BILLING_MODE, null, 0, 0, 0); + + new Worker.Builder().recordProcessorFactory(new IpProcessorFactory()) + .config(consumerConfig) + .build() + .run(); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKPLApplication.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKPLApplication.java new file mode 100644 index 0000000000..1b2d9bed3f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/kclkpl/KinesisKPLApplication.java @@ -0,0 +1,37 @@ +package com.baeldung.kclkpl; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.kinesis.producer.KinesisProducer; +import com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration; + +@SpringBootApplication +public class KinesisKPLApplication { + + @Value("${aws.access.key}") + private String accessKey; + + @Value("${aws.secret.key}") + private String secretKey; + + public static void main(String[] args) { + SpringApplication.run(KinesisKPLApplication.class, args); + } + + @Bean + public KinesisProducer kinesisProducer() { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + KinesisProducerConfiguration producerConfig = new KinesisProducerConfiguration().setCredentialsProvider(new AWSStaticCredentialsProvider(awsCredentials)) + .setVerifyCertificate(false) + .setRegion(Regions.EU_CENTRAL_1.getName()); + + return new KinesisProducer(producerConfig); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ConsumerSDK.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ConsumerSDK.java new file mode 100644 index 0000000000..d95d66b75a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ConsumerSDK.java @@ -0,0 +1,56 @@ +package com.baeldung.sdk; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.amazonaws.services.kinesis.AmazonKinesis; +import com.amazonaws.services.kinesis.model.GetRecordsRequest; +import com.amazonaws.services.kinesis.model.GetRecordsResult; +import com.amazonaws.services.kinesis.model.GetShardIteratorRequest; +import com.amazonaws.services.kinesis.model.GetShardIteratorResult; +import com.amazonaws.services.kinesis.model.ShardIteratorType; + +@Component +public class ConsumerSDK { + + @Value("${ips.stream}") + private String IPS_STREAM; + + @Value("${ips.shard.id}") + private String IPS_SHARD_ID; + + @Autowired + private AmazonKinesis kinesis; + + private GetShardIteratorResult shardIterator; + + public void consumeWithKinesis() { + GetRecordsRequest recordsRequest = new GetRecordsRequest(); + recordsRequest.setShardIterator(shardIterator.getShardIterator()); + recordsRequest.setLimit(25); + + GetRecordsResult recordsResult = kinesis.getRecords(recordsRequest); + while (!recordsResult.getRecords().isEmpty()) { + recordsResult.getRecords() + .stream() + .map(record -> new String(record.getData() + .array())) + .forEach(System.out::println); + + recordsRequest.setShardIterator(recordsResult.getNextShardIterator()); + recordsResult = kinesis.getRecords(recordsRequest); + } + } + + @PostConstruct + private void buildShardIterator() { + GetShardIteratorRequest readShardsRequest = new GetShardIteratorRequest(); + readShardsRequest.setStreamName(IPS_STREAM); + readShardsRequest.setShardIteratorType(ShardIteratorType.LATEST); + readShardsRequest.setShardId(IPS_SHARD_ID); + this.shardIterator = kinesis.getShardIterator(readShardsRequest); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/KinesisSDKApplication.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/KinesisSDKApplication.java new file mode 100644 index 0000000000..28901c0723 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/KinesisSDKApplication.java @@ -0,0 +1,35 @@ +package com.baeldung.sdk; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.kinesis.AmazonKinesis; +import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder; + +@SpringBootApplication +public class KinesisSDKApplication { + + @Value("${aws.access.key}") + private String accessKey; + + @Value("${aws.secret.key}") + private String secretKey; + + public static void main(String[] args) { + SpringApplication.run(KinesisSDKApplication.class, args); + } + + @Bean + public AmazonKinesis buildAmazonKinesis() { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + return AmazonKinesisClientBuilder.standard() + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .withRegion(Regions.EU_CENTRAL_1) + .build(); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ProducerSDK.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ProducerSDK.java new file mode 100644 index 0000000000..76ece8ddb7 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/java/com/baeldung/sdk/ProducerSDK.java @@ -0,0 +1,44 @@ +package com.baeldung.sdk; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.amazonaws.services.kinesis.AmazonKinesis; +import com.amazonaws.services.kinesis.model.PutRecordsRequest; +import com.amazonaws.services.kinesis.model.PutRecordsRequestEntry; + +@Component +public class ProducerSDK { + + @Value("${ips.partition.key}") + private String IPS_PARTITION_KEY; + + @Value("${ips.stream}") + private String IPS_STREAM; + + @Autowired + private AmazonKinesis kinesis; + + @Scheduled(fixedDelay = 3000L) + private void produceWithKinesis() { + List entries = IntStream.range(1, 200).mapToObj(ipSuffix -> { + PutRecordsRequestEntry entry = new PutRecordsRequestEntry(); + entry.setData(ByteBuffer.wrap(("192.168.0." + ipSuffix).getBytes())); + entry.setPartitionKey(IPS_PARTITION_KEY); + return entry; + }).collect(Collectors.toList()); + + PutRecordsRequest createRecordsRequest = new PutRecordsRequest(); + createRecordsRequest.setStreamName(IPS_STREAM); + createRecordsRequest.setRecords(entries); + + kinesis.putRecords(createRecordsRequest); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/resources/application.properties index 1a966c64fb..fddea95d45 100644 --- a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/main/resources/application.properties @@ -1,11 +1,22 @@ -cloud.aws.credentials.access-key=aws-key -cloud.aws.credentials.secret-key=aws-secret +# configurations for AWS SDK consumer and producer +aws.access.key=my-aws-access-key-goes-here +aws.secret.key=my-aws-secret-key-goes-here + +ips.partition.key=ips-partition-key +ips.stream=ips-stream +ips.shard.id=1 + +# configurations for Spring Cloud Stream Kineses Binder consumer and producer +cloud.aws.credentials.access-key=my-aws-access-key +cloud.aws.credentials.secret-key=my-aws-secret-key cloud.aws.region.static=eu-central-1 cloud.aws.stack.auto=false -spring.cloud.stream.bindings.output.destination=myStream -spring.cloud.stream.bindings.output.content-type=text/plain +spring.cloud.stream.bindings.input-in-0.destination=live-ips +spring.cloud.stream.bindings.input-in-0.group=live-ips-group +spring.cloud.stream.bindings.input-in-0.content-type=text/plain +spring.cloud.stream.function.definition = input -spring.cloud.stream.bindings.input.destination=myStream -spring.cloud.stream.bindings.input.group=myStream-group -spring.cloud.stream.bindings.input.content-type=text/plain \ No newline at end of file +spring.cloud.stream.bindings.output-out-0.destination=myStream +spring.cloud.stream.bindings.output-out-0.content-type=text/plain +spring.cloud.stream.poller.fixed-delay = 3000 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationIntegrationTest.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationIntegrationTest.java deleted file mode 100644 index 4e1c281cfb..0000000000 --- a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationIntegrationTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = KinesisApplication.class) -public class KinesisApplicationIntegrationTest { - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - - } -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationManualTest.java b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationManualTest.java new file mode 100644 index 0000000000..bbe871ea11 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/java/com/baeldung/KinesisApplicationManualTest.java @@ -0,0 +1,20 @@ +package com.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.kclkpl.KinesisKPLApplication; + +/** + * Manual Test - this test needs correct AWS Access Key and Secret to build the Amazon Kinesis and complete successfully + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = KinesisKPLApplication.class) +public class KinesisApplicationManualTest { + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/resources/application.properties b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/resources/application.properties index 48005616ec..fddea95d45 100644 --- a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-kinesis/src/test/resources/application.properties @@ -1,2 +1,22 @@ +# configurations for AWS SDK consumer and producer +aws.access.key=my-aws-access-key-goes-here +aws.secret.key=my-aws-secret-key-goes-here + +ips.partition.key=ips-partition-key +ips.stream=ips-stream +ips.shard.id=1 + +# configurations for Spring Cloud Stream Kineses Binder consumer and producer +cloud.aws.credentials.access-key=my-aws-access-key +cloud.aws.credentials.secret-key=my-aws-secret-key cloud.aws.region.static=eu-central-1 -cloud.aws.stack.auto=false \ No newline at end of file +cloud.aws.stack.auto=false + +spring.cloud.stream.bindings.input-in-0.destination=live-ips +spring.cloud.stream.bindings.input-in-0.group=live-ips-group +spring.cloud.stream.bindings.input-in-0.content-type=text/plain +spring.cloud.stream.function.definition = input + +spring.cloud.stream.bindings.output-out-0.destination=myStream +spring.cloud.stream.bindings.output-out-0.content-type=text/plain +spring.cloud.stream.poller.fixed-delay = 3000 \ No newline at end of file diff --git a/spring-core-2/pom.xml b/spring-core-2/pom.xml index 719bf56e0b..3cd9adf451 100644 --- a/spring-core-2/pom.xml +++ b/spring-core-2/pom.xml @@ -92,8 +92,8 @@ ${javassist.version} - mysql - mysql-connector-java + com.mysql + mysql-connector-j runtime diff --git a/spring-core-6/README.md b/spring-core-6/README.md index 9976dbc099..e10db19a54 100644 --- a/spring-core-6/README.md +++ b/spring-core-6/README.md @@ -2,3 +2,6 @@ ### Relevant Articles: - [Instantiating Multiple Beans of the Same Class with Spring Annotations](https://www.baeldung.com/spring-same-class-multiple-beans) - [Using Environment Variables in Spring Boot’s application.properties](https://www.baeldung.com/spring-boot-properties-env-variables) +- [Reinitialize Singleton Bean in Spring Context](https://www.baeldung.com/spring-reinitialize-singleton-bean) +- [HTTP Interface in Spring 6](https://www.baeldung.com/spring-6-http-interface) +- [Getting the Current ApplicationContext in Spring](https://www.baeldung.com/spring-get-current-applicationcontext) diff --git a/spring-core-6/pom.xml b/spring-core-6/pom.xml index 2df7167ca1..a3dda0374f 100644 --- a/spring-core-6/pom.xml +++ b/spring-core-6/pom.xml @@ -10,27 +10,39 @@ http://www.baeldung.com - com.baeldung - parent-modules - 1.0.0-SNAPSHOT + org.springframework.boot + spring-boot-starter-parent + 3.0.1 + org.springframework.boot spring-boot-starter-web - ${spring.boot.version} + + + org.springframework.boot + spring-boot-starter-webflux + + + org.mock-server + mockserver-netty + ${mockserver.version} + + + org.mock-server + mockserver-client-java + ${mockserver.version} org.springframework.boot spring-boot-starter-test - ${spring.boot.version} test - org.junit.jupiter - junit-jupiter-api - ${junit-jupiter.version} + io.projectreactor + reactor-test test @@ -76,13 +88,23 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + UTF-8 - 11 - 11 - 2.7.5 + 17 + 17 + 5.14.0 \ No newline at end of file diff --git a/spring-core-6/src/main/java/com/baeldung/applicationcontext/ApplicationContextProvider.java b/spring-core-6/src/main/java/com/baeldung/applicationcontext/ApplicationContextProvider.java new file mode 100644 index 0000000000..260620ff48 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/applicationcontext/ApplicationContextProvider.java @@ -0,0 +1,20 @@ +package com.baeldung.applicationcontext; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class ApplicationContextProvider implements ApplicationContextAware { + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + ApplicationContextProvider.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } +} \ No newline at end of file diff --git a/spring-core-6/src/main/java/com/baeldung/applicationcontext/ItemService.java b/spring-core-6/src/main/java/com/baeldung/applicationcontext/ItemService.java new file mode 100644 index 0000000000..344ea3af0f --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/applicationcontext/ItemService.java @@ -0,0 +1,11 @@ +package com.baeldung.applicationcontext; + +import org.springframework.stereotype.Service; + +@Service +public class ItemService { + + public String getItem(){ + return "New Item"; + } +} diff --git a/spring-core-6/src/main/java/com/baeldung/applicationcontext/MyBean.java b/spring-core-6/src/main/java/com/baeldung/applicationcontext/MyBean.java new file mode 100644 index 0000000000..95be3375c7 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/applicationcontext/MyBean.java @@ -0,0 +1,17 @@ +package com.baeldung.applicationcontext; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +@Component +public class MyBean { + + @Autowired + private ApplicationContext applicationContext; + + public ApplicationContext getApplicationContext() { + return applicationContext; + } + +} diff --git a/spring-core-6/src/main/java/com/baeldung/httpinterface/Book.java b/spring-core-6/src/main/java/com/baeldung/httpinterface/Book.java new file mode 100644 index 0000000000..a38085852e --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/httpinterface/Book.java @@ -0,0 +1,3 @@ +package com.baeldung.httpinterface; + +public record Book(long id, String title, String author, int year) {} diff --git a/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksClient.java b/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksClient.java new file mode 100644 index 0000000000..3034f4f528 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksClient.java @@ -0,0 +1,23 @@ +package com.baeldung.httpinterface; + +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.support.WebClientAdapter; +import org.springframework.web.service.invoker.HttpServiceProxyFactory; + +@Component +public class BooksClient { + + private final BooksService booksService; + + public BooksClient(WebClient webClient) { + HttpServiceProxyFactory httpServiceProxyFactory = + HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)) + .build(); + booksService = httpServiceProxyFactory.createClient(BooksService.class); + } + + public BooksService getBooksService() { + return booksService; + } +} diff --git a/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksService.java b/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksService.java new file mode 100644 index 0000000000..a9cf6ec58a --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/httpinterface/BooksService.java @@ -0,0 +1,26 @@ +package com.baeldung.httpinterface; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.service.annotation.DeleteExchange; +import org.springframework.web.service.annotation.GetExchange; +import org.springframework.web.service.annotation.PostExchange; + +import java.util.List; + +interface BooksService { + + @GetExchange("/books") + List getBooks(); + + @GetExchange("/books/{id}") + Book getBook(@PathVariable long id); + + @PostExchange("/books") + Book saveBook(@RequestBody Book book); + + @DeleteExchange("/books/{id}") + ResponseEntity deleteBook(@PathVariable long id); + +} diff --git a/spring-core-6/src/main/java/com/baeldung/reinitializebean/ReinitializeBeanApp.java b/spring-core-6/src/main/java/com/baeldung/reinitializebean/ReinitializeBeanApp.java new file mode 100644 index 0000000000..5c3b607579 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/reinitializebean/ReinitializeBeanApp.java @@ -0,0 +1,11 @@ +package com.baeldung.reinitializebean; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ReinitializeBeanApp { + public static void main(String[] args) { + SpringApplication.run(ReinitializeBeanApp.class, args); + } +} diff --git a/spring-core-6/src/main/java/com/baeldung/reinitializebean/cache/ConfigManager.java b/spring-core-6/src/main/java/com/baeldung/reinitializebean/cache/ConfigManager.java new file mode 100644 index 0000000000..240fb350c2 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/reinitializebean/cache/ConfigManager.java @@ -0,0 +1,50 @@ +package com.baeldung.reinitializebean.cache; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +@Service("ConfigManager") +public class ConfigManager { + + private static final Log LOG = LogFactory.getLog(ConfigManager.class); + + private Map config; + + private final String filePath; + + public ConfigManager(@Value("${config.file.path}") String filePath) { + this.filePath = filePath; + initConfigs(); + } + + private void initConfigs() { + Properties properties = new Properties(); + try { + properties.load(Files.newInputStream(Paths.get(filePath))); + } catch (IOException e) { + LOG.error("Error loading configuration:", e); + } + config = new HashMap<>(); + for (Map.Entry entry : properties.entrySet()) { + config.put(String.valueOf(entry.getKey()), entry.getValue()); + } + } + + public Object getConfig(String key) { + return config.get(key); + } + + public void reinitializeConfig() { + initConfigs(); + } + +} diff --git a/spring-core-6/src/main/java/com/baeldung/reinitializebean/controller/ConfigController.java b/spring-core-6/src/main/java/com/baeldung/reinitializebean/controller/ConfigController.java new file mode 100644 index 0000000000..377882a8f0 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/reinitializebean/controller/ConfigController.java @@ -0,0 +1,55 @@ +package com.baeldung.reinitializebean.controller; + +import com.baeldung.reinitializebean.cache.ConfigManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry; +import org.springframework.context.ApplicationContext; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/config") +public class ConfigController { + + @Value("${config.file.path}") + private String filePath; + private final ApplicationContext applicationContext; + private final ConfigManager configManager; + + public ConfigController(ApplicationContext applicationContext, ConfigManager configManager) { + this.applicationContext = applicationContext; + this.configManager = configManager; + } + + @GetMapping("/reinitializeConfig") + public void reinitializeConfig() { + configManager.reinitializeConfig(); + } + + @GetMapping("/reinitializeBean") + public void reinitializeBean() { + DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory(); + registry.destroySingleton("ConfigManager"); + registry.registerSingleton("ConfigManager", new ConfigManager(filePath)); + } + + @GetMapping("/destroyBean") + public void destroyBean() { + DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory(); + registry.destroySingleton("ConfigManager"); + } + + @GetMapping("/{key}") + public Object get(@PathVariable String key) { + return configManager.getConfig(key); + } + + @GetMapping("/context/{key}") + public Object getFromContext(@PathVariable String key) { + ConfigManager dynamicConfigManager = applicationContext.getBean(ConfigManager.class); + return dynamicConfigManager.getConfig(key); + } + +} diff --git a/spring-core-6/src/main/resources/application.properties b/spring-core-6/src/main/resources/application.properties index d0029f363c..28a65dce32 100644 --- a/spring-core-6/src/main/resources/application.properties +++ b/spring-core-6/src/main/resources/application.properties @@ -1,4 +1,5 @@ environment.name=${OS} java.home.and.environment=${JAVA_HOME}+${OS} not.existing.system.property=${thispropertydoesnotexist} -baeldung.presentation=${HELLO_BAELDUNG}. Java is installed in the folder: ${JAVA_HOME} \ No newline at end of file +baeldung.presentation=${HELLO_BAELDUNG}. Java is installed in the folder: ${JAVA_HOME} +config.file.path=./spring-core-6/src/main/resources/config.properties \ No newline at end of file diff --git a/spring-core-6/src/main/resources/config.properties b/spring-core-6/src/main/resources/config.properties new file mode 100644 index 0000000000..591d32f33c --- /dev/null +++ b/spring-core-6/src/main/resources/config.properties @@ -0,0 +1 @@ +property1=value2 diff --git a/spring-core-6/src/test/java/com/baeldung/applicationcontext/ApplicationContextProviderUnitTest.java b/spring-core-6/src/test/java/com/baeldung/applicationcontext/ApplicationContextProviderUnitTest.java new file mode 100644 index 0000000000..3c3053e61c --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/applicationcontext/ApplicationContextProviderUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.applicationcontext; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ContextConfiguration(classes = TestContextConfig.class) +@ExtendWith(SpringExtension.class) +class ApplicationContextProviderUnitTest { + + @Test + void whenGetApplicationContext_thenReturnApplicationContext() { + ApplicationContext context = ApplicationContextProvider.getApplicationContext(); + assertNotNull(context); + System.out.printf("ApplicationContext has %d beans %n", context.getBeanDefinitionCount()); + } + + @Test + void whenGetBean_thenReturnItemServiceReference() { + ApplicationContext context = ApplicationContextProvider.getApplicationContext(); + assertNotNull(context); + + ItemService itemService = context.getBean(ItemService.class); + assertNotNull(context); + + System.out.println(itemService.getItem()); + } +} \ No newline at end of file diff --git a/spring-core-6/src/test/java/com/baeldung/applicationcontext/MyBeanUnitTest.java b/spring-core-6/src/test/java/com/baeldung/applicationcontext/MyBeanUnitTest.java new file mode 100644 index 0000000000..bff04c2d20 --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/applicationcontext/MyBeanUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.applicationcontext; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ContextConfiguration(classes = TestContextConfig.class) +@ExtendWith(SpringExtension.class) +class MyBeanUnitTest { + + @Autowired + MyBean myBean; + + @Test + void whenGetApplicationContext_thenReturnApplicationContext() { + assertNotNull(myBean); + ApplicationContext context = myBean.getApplicationContext(); + assertNotNull(context); + + System.out.printf("ApplicationContext has %d beans %n", context.getBeanDefinitionCount()); + } + +} \ No newline at end of file diff --git a/spring-core-6/src/test/java/com/baeldung/applicationcontext/TestContextConfig.java b/spring-core-6/src/test/java/com/baeldung/applicationcontext/TestContextConfig.java new file mode 100644 index 0000000000..257500a00f --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/applicationcontext/TestContextConfig.java @@ -0,0 +1,11 @@ +package com.baeldung.applicationcontext; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan("com.baeldung.applicationcontext") +public class TestContextConfig { + + +} diff --git a/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockServerTest.java b/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockServerTest.java new file mode 100644 index 0000000000..22e00c16ae --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockServerTest.java @@ -0,0 +1,217 @@ +package com.baeldung.httpinterface; + +import org.apache.http.HttpException; +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockserver.client.MockServerClient; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.configuration.Configuration; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.List; + +import org.mockserver.model.HttpRequest; +import org.mockserver.model.MediaType; +import org.mockserver.verify.VerificationTimes; +import org.slf4j.event.Level; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.integration.ClientAndServer.startClientAndServer; +import static org.mockserver.matchers.Times.exactly; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BooksServiceMockServerTest { + + private static final String SERVER_ADDRESS = "localhost"; + private static final String PATH = "/books"; + + private static int serverPort; + private static ClientAndServer mockServer; + private static String serviceUrl; + + @BeforeAll + static void startServer() throws IOException { + serverPort = getFreePort(); + serviceUrl = "http://" + SERVER_ADDRESS + ":" + serverPort; + + Configuration config = Configuration.configuration().logLevel(Level.WARN); + mockServer = startClientAndServer(config, serverPort); + + mockAllBooksRequest(); + mockBookByIdRequest(); + mockSaveBookRequest(); + mockDeleteBookRequest(); + } + + @AfterAll + static void stopServer() { + mockServer.stop(); + } + + @Test + void givenMockedGetResponse_whenGetBooksServiceMethodIsCalled_thenTwoBooksAreReturned() { + BooksClient booksClient = new BooksClient(WebClient.builder().baseUrl(serviceUrl).build()); + BooksService booksService = booksClient.getBooksService(); + + List books = booksService.getBooks(); + assertEquals(2, books.size()); + + mockServer.verify( + HttpRequest.request() + .withMethod(HttpMethod.GET.name()) + .withPath(PATH), + VerificationTimes.exactly(1) + ); + } + + @Test + void givenMockedGetResponse_whenGetExistingBookServiceMethodIsCalled_thenCorrectBookIsReturned() { + BooksClient booksClient = new BooksClient(WebClient.builder().baseUrl(serviceUrl).build()); + BooksService booksService = booksClient.getBooksService(); + + Book book = booksService.getBook(1); + assertEquals("Book_1", book.title()); + + mockServer.verify( + HttpRequest.request() + .withMethod(HttpMethod.GET.name()) + .withPath(PATH + "/1"), + VerificationTimes.exactly(1) + ); + } + + @Test + void givenMockedGetResponse_whenGetNonExistingBookServiceMethodIsCalled_thenCorrectBookIsReturned() { + BooksClient booksClient = new BooksClient(WebClient.builder().baseUrl(serviceUrl).build()); + BooksService booksService = booksClient.getBooksService(); + + assertThrows(WebClientResponseException.class, () -> booksService.getBook(9)); + } + + @Test + void givenCustomErrorHandlerIsSet_whenGetNonExistingBookServiceMethodIsCalled_thenCustomExceptionIsThrown() { + BooksClient booksClient = new BooksClient(WebClient.builder() + .defaultStatusHandler(HttpStatusCode::isError, resp -> + Mono.just(new MyServiceException("Custom exception"))) + .baseUrl(serviceUrl) + .build()); + + BooksService booksService = booksClient.getBooksService(); + assertThrows(MyServiceException.class, () -> booksService.getBook(9)); + } + + @Test + void givenMockedPostResponse_whenSaveBookServiceMethodIsCalled_thenCorrectBookIsReturned() { + BooksClient booksClient = new BooksClient(WebClient.builder().baseUrl(serviceUrl).build()); + BooksService booksService = booksClient.getBooksService(); + + Book book = booksService.saveBook(new Book(3, "Book_3", "Author_3", 2000)); + assertEquals("Book_3", book.title()); + + mockServer.verify( + HttpRequest.request() + .withMethod(HttpMethod.POST.name()) + .withPath(PATH), + VerificationTimes.exactly(1) + ); + } + + @Test + void givenMockedDeleteResponse_whenDeleteBookServiceMethodIsCalled_thenCorrectCodeIsReturned() { + BooksClient booksClient = new BooksClient(WebClient.builder().baseUrl(serviceUrl).build()); + BooksService booksService = booksClient.getBooksService(); + + ResponseEntity response = booksService.deleteBook(3); + assertEquals(HttpStatusCode.valueOf(200), response.getStatusCode()); + + mockServer.verify( + HttpRequest.request() + .withMethod(HttpMethod.DELETE.name()) + .withPath(PATH + "/3"), + VerificationTimes.exactly(1) + ); + } + + private static int getFreePort () throws IOException { + try (ServerSocket serverSocket = new ServerSocket(0)) { + return serverSocket.getLocalPort(); + } + } + + private static void mockAllBooksRequest() { + new MockServerClient(SERVER_ADDRESS, serverPort) + .when( + request() + .withPath(PATH) + .withMethod(HttpMethod.GET.name()), + exactly(1) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + .withContentType(MediaType.APPLICATION_JSON) + .withBody("[{\"id\":1,\"title\":\"Book_1\",\"author\":\"Author_1\",\"year\":1998},{\"id\":2,\"title\":\"Book_2\",\"author\":\"Author_2\",\"year\":1999}]") + ); + } + + private static void mockBookByIdRequest() { + new MockServerClient(SERVER_ADDRESS, serverPort) + .when( + request() + .withPath(PATH + "/1") + .withMethod(HttpMethod.GET.name()), + exactly(1) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + .withContentType(MediaType.APPLICATION_JSON) + .withBody("{\"id\":1,\"title\":\"Book_1\",\"author\":\"Author_1\",\"year\":1998}") + ); + } + + private static void mockSaveBookRequest() { + new MockServerClient(SERVER_ADDRESS, serverPort) + .when( + request() + .withPath(PATH) + .withMethod(HttpMethod.POST.name()) + .withContentType(MediaType.APPLICATION_JSON) + .withBody("{\"id\":3,\"title\":\"Book_3\",\"author\":\"Author_3\",\"year\":2000}"), + exactly(1) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + .withContentType(MediaType.APPLICATION_JSON) + .withBody("{\"id\":3,\"title\":\"Book_3\",\"author\":\"Author_3\",\"year\":2000}") + ); + } + + private static void mockDeleteBookRequest() { + new MockServerClient(SERVER_ADDRESS, serverPort) + .when( + request() + .withPath(PATH + "/3") + .withMethod(HttpMethod.DELETE.name()), + exactly(1) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + ); + } + +} diff --git a/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockitoTest.java b/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockitoTest.java new file mode 100644 index 0000000000..7a82835ef3 --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/httpinterface/BooksServiceMockitoTest.java @@ -0,0 +1,88 @@ +package com.baeldung.httpinterface; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import static org.mockito.BDDMockito.*; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MockitoExtension.class) +class BooksServiceMockitoTest { + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private WebClient webClient; + + @InjectMocks + private BooksClient booksClient; + + @Test + void givenMockedWebClientReturnsTwoBooks_whenGetBooksServiceMethodIsCalled_thenListOfTwoBooksIsReturned() { + given(webClient.method(HttpMethod.GET) + .uri(anyString(), anyMap()) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>(){})) + .willReturn(Mono.just(List.of( + new Book(1,"Book_1", "Author_1", 1998), + new Book(2, "Book_2", "Author_2", 1999) + ))); + + BooksService booksService = booksClient.getBooksService(); + List books = booksService.getBooks(); + assertEquals(2, books.size()); + } + + @Test + void givenMockedWebClientReturnsBook_whenGetBookServiceMethodIsCalled_thenBookIsReturned() { + given(webClient.method(HttpMethod.GET) + .uri(anyString(), anyMap()) + .retrieve() + .bodyToMono(new ParameterizedTypeReference(){})) + .willReturn(Mono.just(new Book(1,"Book_1", "Author_1", 1998))); + + BooksService booksService = booksClient.getBooksService(); + Book book = booksService.getBook(1); + assertEquals("Book_1", book.title()); + } + + @Test + void givenMockedWebClientReturnsBook_whenSaveBookServiceMethodIsCalled_thenBookIsReturned() { + given(webClient.method(HttpMethod.POST) + .uri(anyString(), anyMap()) + .retrieve() + .bodyToMono(new ParameterizedTypeReference(){})) + .willReturn(Mono.just(new Book(3, "Book_3", "Author_3", 2000))); + + BooksService booksService = booksClient.getBooksService(); + Book book = booksService.saveBook(new Book(3, "Book_3", "Author_3", 2000)); + assertEquals("Book_3", book.title()); + } + + @Test + void givenMockedWebClientReturnsOk_whenDeleteBookServiceMethodIsCalled_thenOkCodeIsReturned() { + given(webClient.method(HttpMethod.DELETE) + .uri(anyString(), anyMap()) + .retrieve() + .toBodilessEntity() + .block(any()) + .getStatusCode()) + .willReturn(HttpStatusCode.valueOf(200)); + + BooksService booksService = booksClient.getBooksService(); + ResponseEntity response = booksService.deleteBook(3); + assertEquals(HttpStatusCode.valueOf(200), response.getStatusCode()); + } + +} diff --git a/spring-core-6/src/test/java/com/baeldung/httpinterface/MyServiceException.java b/spring-core-6/src/test/java/com/baeldung/httpinterface/MyServiceException.java new file mode 100644 index 0000000000..e09335a211 --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/httpinterface/MyServiceException.java @@ -0,0 +1,9 @@ +package com.baeldung.httpinterface; + +public class MyServiceException extends RuntimeException { + + MyServiceException(String msg) { + super(msg); + } + +} diff --git a/spring-credhub/README.md b/spring-credhub/README.md new file mode 100644 index 0000000000..7eb82aed28 --- /dev/null +++ b/spring-credhub/README.md @@ -0,0 +1,3 @@ +## Relevant Articles + +- [A Guide to Spring CredHub](https://www.baeldung.com/spring-credhub) diff --git a/spring-di-2/src/test/java/com/baeldung/circulardependency/CircularDependencyIntegrationTest.java b/spring-di-2/src/test/java/com/baeldung/circulardependency/CircularDependencyIntegrationTest.java index 42847f4dd1..5ddd47bc28 100644 --- a/spring-di-2/src/test/java/com/baeldung/circulardependency/CircularDependencyIntegrationTest.java +++ b/spring-di-2/src/test/java/com/baeldung/circulardependency/CircularDependencyIntegrationTest.java @@ -32,4 +32,9 @@ public class CircularDependencyIntegrationTest { Assert.assertEquals("Hi!", circA.getCircB().getMessage()); } + + @Test + public void givenCircularDependency_whenConstructorInjection_thenItFails() { + // Empty test; we just want the context to load + } } diff --git a/spring-di/src/main/java/com/baeldung/sample/Config.java b/spring-di/src/main/java/com/baeldung/sample/Config.java new file mode 100644 index 0000000000..9d13573c8e --- /dev/null +++ b/spring-di/src/main/java/com/baeldung/sample/Config.java @@ -0,0 +1,22 @@ +package com.baeldung.sample; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@Configuration +@ComponentScan(basePackages="com.baeldung.primary") +public class Config { + + @Bean + public Employee johnEmployee(){ + return new Employee("John"); + } + + @Bean + @Primary + public Employee tonyEmployee(){ + return new Employee("Tony"); + } +} diff --git a/spring-di/src/main/java/com/baeldung/sample/Employee.java b/spring-di/src/main/java/com/baeldung/sample/Employee.java new file mode 100644 index 0000000000..a150aeb813 --- /dev/null +++ b/spring-di/src/main/java/com/baeldung/sample/Employee.java @@ -0,0 +1,20 @@ +package com.baeldung.sample; + +/** + * Created by Gebruiker on 7/17/2018. + */ +public class Employee { + + private String name; + + public Employee(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/spring-ejb-modules/README.md b/spring-ejb-modules/README.md index 84e01f95e9..dbef052791 100644 --- a/spring-ejb-modules/README.md +++ b/spring-ejb-modules/README.md @@ -5,7 +5,7 @@ This module contains articles about Spring with EJB ### Relevant Articles - [Java EE Session Beans](https://www.baeldung.com/ejb-session-beans) -- [A Guide to Message Driven Beans in EJB](https://www.baeldung.com/ejb-message-driven-beans) - [Integration Guide for Spring and EJB](https://www.baeldung.com/spring-ejb) - [Singleton Session Bean in Jakarta EE](https://www.baeldung.com/java-ee-singleton-session-bean) +- [Guide to EJB Set-up](https://www.baeldung.com/ejb-intro) diff --git a/spring-kafka-2/README.md b/spring-kafka-2/README.md new file mode 100644 index 0000000000..1f5e015f9e --- /dev/null +++ b/spring-kafka-2/README.md @@ -0,0 +1,7 @@ +## Spring Kafka 2 + +This module contains articles about Spring with Kafka + +### Relevant articles + +- [Implementing Retry In Kafka Consumer](https://www.baeldung.com/spring-retry-kafka-consumer) diff --git a/spring-kafka-2/pom.xml b/spring-kafka-2/pom.xml new file mode 100644 index 0000000000..76a82f6000 --- /dev/null +++ b/spring-kafka-2/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + spring-kafka-2 + spring-kafka-2 + Intro to Kafka with Spring + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.kafka + spring-kafka + + + org.apache.kafka + kafka-streams + + + com.fasterxml.jackson.core + jackson-databind + + + org.projectlombok + lombok + + + org.springframework.kafka + spring-kafka-test + test + + + org.testcontainers + kafka + ${testcontainers-kafka.version} + test + + + org.testcontainers + junit-jupiter + ${testcontainers-kafka.version} + test + + + org.awaitility + awaitility + test + + + + + 1.16.2 + + + \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java new file mode 100644 index 0000000000..bbff315ad2 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.kafka; + +public class Farewell { + + private String message; + private Integer remainingMinutes; + + public Farewell() { + } + + public Farewell(String message, Integer remainingMinutes) { + this.message = message; + this.remainingMinutes = remainingMinutes; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getRemainingMinutes() { + return remainingMinutes; + } + + public void setRemainingMinutes(Integer remainingMinutes) { + this.remainingMinutes = remainingMinutes; + } + + @Override + public String toString() { + return message + ". In " + remainingMinutes + "!"; + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java new file mode 100644 index 0000000000..b4633e802a --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.kafka; + +public class Greeting { + + private String msg; + private String name; + + public Greeting() { + + } + + public Greeting(String msg, String name) { + this.msg = msg; + this.name = name; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return msg + ", " + name + "!"; + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java new file mode 100644 index 0000000000..463d3209ea --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java @@ -0,0 +1,152 @@ +package com.baeldung.spring.kafka; + +import java.net.SocketTimeoutException; +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.context.annotation.Primary; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.DefaultErrorHandler; +import org.springframework.kafka.support.converter.RecordMessageConverter; +import org.springframework.kafka.support.converter.StringJsonMessageConverter; +import org.springframework.kafka.support.mapping.DefaultJackson2JavaTypeMapper; +import org.springframework.kafka.support.mapping.Jackson2JavaTypeMapper; +import org.springframework.kafka.support.serializer.JsonDeserializer; +import org.springframework.util.backoff.BackOff; +import org.springframework.util.backoff.FixedBackOff; + +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Value(value = "${kafka.backoff.interval}") + private Long interval; + + @Value(value = "${kafka.backoff.max_failure}") + private Long maxAttempts; + + public ConsumerFactory consumerFactory(String groupId) { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, "20971520"); + props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, "20971520"); + return new DefaultKafkaConsumerFactory<>(props); + } + + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory(String groupId) { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory(groupId)); + return factory; + } + + @Bean + public ConcurrentKafkaListenerContainerFactory fooKafkaListenerContainerFactory() { + return kafkaListenerContainerFactory("foo"); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory barKafkaListenerContainerFactory() { + return kafkaListenerContainerFactory("bar"); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory headersKafkaListenerContainerFactory() { + return kafkaListenerContainerFactory("headers"); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory partitionsKafkaListenerContainerFactory() { + return kafkaListenerContainerFactory("partitions"); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory longMessageKafkaListenerContainerFactory() { + return kafkaListenerContainerFactory("longMessage"); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory filterKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = kafkaListenerContainerFactory("filter"); + factory.setRecordFilterStrategy(record -> record.value() + .contains("World")); + return factory; + } + + public ConsumerFactory greetingConsumerFactory() { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.GROUP_ID_CONFIG, "greeting"); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(Greeting.class)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(greetingConsumerFactory()); + return factory; + } + + @Bean + public RecordMessageConverter multiTypeConverter() { + StringJsonMessageConverter converter = new StringJsonMessageConverter(); + DefaultJackson2JavaTypeMapper typeMapper = new DefaultJackson2JavaTypeMapper(); + typeMapper.setTypePrecedence(Jackson2JavaTypeMapper.TypePrecedence.TYPE_ID); + typeMapper.addTrustedPackages("com.baeldung.spring.kafka"); + Map> mappings = new HashMap<>(); + mappings.put("greeting", Greeting.class); + mappings.put("farewell", Farewell.class); + typeMapper.setIdClassMapping(mappings); + converter.setTypeMapper(typeMapper); + return converter; + } + + @Bean + public ConsumerFactory multiTypeConsumerFactory() { + HashMap props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class); + props.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id_test"); + return new DefaultKafkaConsumerFactory<>(props); + } + + @Bean + @Primary + public ConcurrentKafkaListenerContainerFactory greetingKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(multiTypeConsumerFactory()); + factory.setMessageConverter(multiTypeConverter()); + factory.setCommonErrorHandler(errorHandler()); + factory.getContainerProperties() + .setAckMode(ContainerProperties.AckMode.RECORD); + return factory; + } + + @Bean + public DefaultErrorHandler errorHandler() { + BackOff fixedBackOff = new FixedBackOff(interval, maxAttempts); + DefaultErrorHandler errorHandler = new DefaultErrorHandler((consumerRecord, e) -> { + System.out.println(String.format("consumed record %s because this exception was thrown",consumerRecord.toString(),e.getClass().getName())); + }, fixedBackOff); + //Commented because of the test + //errorHandler.addRetryableExceptions(SocketTimeoutException.class,RuntimeException.class); + errorHandler.addNotRetryableExceptions(NullPointerException.class); + return errorHandler; + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java new file mode 100644 index 0000000000..da8b2bd1a6 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java @@ -0,0 +1,67 @@ +package com.baeldung.spring.kafka; + +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 bootstrapAddress; + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, "20971520"); + + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + @Bean + public ProducerFactory greetingProducerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate greetingKafkaTemplate() { + return new KafkaTemplate<>(greetingProducerFactory()); + } + + @Bean + public ProducerFactory multiTypeProducerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + configProps.put(JsonSerializer.TYPE_MAPPINGS, "greeting:com.baeldung.spring.kafka.Greeting, farewell:com.baeldung.spring.kafka.Farewell"); + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate multiTypeKafkaTemplate() { + return new KafkaTemplate<>(multiTypeProducerFactory()); + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java new file mode 100644 index 0000000000..6a20915699 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java @@ -0,0 +1,77 @@ +package com.baeldung.spring.kafka; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaAdmin; + +@Configuration +public class KafkaTopicConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Value(value = "${message.topic.name}") + private String topicName; + + @Value(value = "${long.message.topic.name}") + private String longMsgTopicName; + + @Value(value = "${partitioned.topic.name}") + private String partitionedTopicName; + + @Value(value = "${filtered.topic.name}") + private String filteredTopicName; + + @Value(value = "${greeting.topic.name}") + private String greetingTopicName; + + @Value(value = "${multi.type.topic.name}") + private String multiTypeTopicName; + + @Bean + public KafkaAdmin kafkaAdmin() { + Map configs = new HashMap<>(); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + return new KafkaAdmin(configs); + } + + @Bean + public NewTopic topic1() { + return new NewTopic(topicName, 1, (short) 1); + } + + @Bean + public NewTopic topic2() { + return new NewTopic(partitionedTopicName, 6, (short) 1); + } + + @Bean + public NewTopic topic3() { + return new NewTopic(filteredTopicName, 1, (short) 1); + } + + @Bean + public NewTopic topic4() { + return new NewTopic(greetingTopicName, 1, (short) 1); + } + + @Bean + public NewTopic topic5() { + NewTopic newTopic = new NewTopic(longMsgTopicName, 1, (short) 1); + Map configs = new HashMap<>(); + configs.put("max.message.bytes", "20971520"); + newTopic.configs(configs); + return newTopic; + } + + @Bean + public NewTopic multiTypeTopic() { + return new NewTopic(multiTypeTopicName, 1, (short) 1); + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java new file mode 100644 index 0000000000..6c4d78171b --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.kafka; + +import org.springframework.kafka.annotation.KafkaHandler; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.messaging.MessagingException; +import org.springframework.stereotype.Component; + +@Component +@KafkaListener(id = "multiGroup", topics = "multitype") +public class MultiTypeKafkaListener { + + @KafkaHandler + //@RetryableTopic(backoff = @Backoff(value = 3000L), attempts = "5", autoCreateTopics = "false",include = SocketTimeoutException.class, exclude = NullPointerException.class) + public void handleGreeting(Greeting greeting) { + if (greeting.getName() + .equalsIgnoreCase("test")) { + throw new MessagingException("test not allowed"); + } + System.out.println("Greeting received: " + greeting); + } + + @KafkaHandler + public void handleF(Farewell farewell) { + System.out.println("Farewell received: " + farewell); + } + + @KafkaHandler(isDefault = true) + public void unknown(Object object) { + System.out.println("Unkown type received: " + object); + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java new file mode 100644 index 0000000000..e43207829a --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.kafka; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@Import(value = { KafkaTopicConfig.class, KafkaConsumerConfig.class, KafkaProducerConfig.class }) +public class RetryableApplicationKafkaApp { + + public static void main(String[] args) { + SpringApplication.run(RetryableApplicationKafkaApp.class, args); + } +} diff --git a/spring-kafka-2/src/main/resources/application.properties b/spring-kafka-2/src/main/resources/application.properties new file mode 100644 index 0000000000..691b6f55b7 --- /dev/null +++ b/spring-kafka-2/src/main/resources/application.properties @@ -0,0 +1,20 @@ +spring.kafka.bootstrap-servers=localhost:9092 +message.topic.name=baeldung +long.message.topic.name=longMessage +greeting.topic.name=greeting +filtered.topic.name=filtered +partitioned.topic.name=partitioned +multi.type.topic.name=multitype +# monitoring - lag analysis +monitor.kafka.bootstrap.config=localhost:9092 +monitor.kafka.consumer.groupid=baeldungGrp +monitor.topic.name=baeldung +# monitoring - simulation +monitor.producer.simulate=true +monitor.consumer.simulate=true +monitor.kafka.consumer.groupid.simulate=baeldungGrpSimulate +test.topic=testtopic1 +kafka.backoff.interval=9000 +kafka.backoff.max_failure=5 + + diff --git a/undertow/src/main/resources/logback.xml b/spring-kafka-2/src/main/resources/logback.xml similarity index 100% rename from undertow/src/main/resources/logback.xml rename to spring-kafka-2/src/main/resources/logback.xml diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java new file mode 100644 index 0000000000..5417fee1ac --- /dev/null +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java @@ -0,0 +1,84 @@ +package com.baeldung.spring.kafka; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.AcknowledgingConsumerAwareMessageListener; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.test.EmbeddedKafkaBroker; +import org.springframework.kafka.test.context.EmbeddedKafka; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@SpringBootTest(classes = RetryableApplicationKafkaApp.class) +@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +public class KafkaRetryableIntegrationTest { + @ClassRule + public static EmbeddedKafkaBroker embeddedKafka = new EmbeddedKafkaBroker(1, true, "multitype"); + + @Autowired + private KafkaListenerEndpointRegistry registry; + + @Autowired + private KafkaTemplate template; + + private ObjectMapper objectMapper = new ObjectMapper(); + + private static final String CONTAINER_GROUP = "multiGroup"; + + private static final String TOPIC = "topic"; + + @Before + public void setup() { + System.setProperty("spring.kafka.bootstrap-servers", embeddedKafka.getBrokersAsString()); + } + + @Test + public void givenEmbeddedKafkaBroker_whenSendingAWellFormedMessage_thenMessageIsConsumed() throws Exception { + ConcurrentMessageListenerContainer container = (ConcurrentMessageListenerContainer) registry.getListenerContainer(CONTAINER_GROUP); + container.stop(); + @SuppressWarnings("unchecked") AcknowledgingConsumerAwareMessageListener messageListener = (AcknowledgingConsumerAwareMessageListener) container.getContainerProperties() + .getMessageListener(); + CountDownLatch latch = new CountDownLatch(1); + container.getContainerProperties() + .setMessageListener((AcknowledgingConsumerAwareMessageListener) (data, acknowledgment, consumer) -> { + messageListener.onMessage(data, acknowledgment, consumer); + latch.countDown(); + }); + Greeting greeting = new Greeting("test1", "test2"); + container.start(); + template.send(TOPIC, objectMapper.writeValueAsString(greeting)); + assertThat(latch.await(10, TimeUnit.SECONDS)).isFalse(); + } + + @Test + public void givenEmbeddedKafkaBroker_whenSendingAMalFormedMessage_thenMessageIsConsumedAfterRetry() throws Exception { + ConcurrentMessageListenerContainer container = (ConcurrentMessageListenerContainer) registry.getListenerContainer(CONTAINER_GROUP); + container.stop(); + @SuppressWarnings("unchecked") AcknowledgingConsumerAwareMessageListener messageListener = (AcknowledgingConsumerAwareMessageListener) container.getContainerProperties() + .getMessageListener(); + CountDownLatch latch = new CountDownLatch(1); + container.getContainerProperties() + .setMessageListener((AcknowledgingConsumerAwareMessageListener) (data, acknowledgment, consumer) -> { + messageListener.onMessage(data, acknowledgment, consumer); + latch.countDown(); + }); + container.start(); + Greeting greeting = new Greeting("test", "test"); + template.send(TOPIC, objectMapper.writeValueAsString(greeting)); + //this message will go on error + Greeting greeting2 = new Greeting("test2", "test2"); + template.send(TOPIC, objectMapper.writeValueAsString(greeting2)); + assertThat(latch.getCount()).isEqualTo(1); + } + +} diff --git a/spring-kafka-2/src/test/resources/application.yml b/spring-kafka-2/src/test/resources/application.yml new file mode 100644 index 0000000000..8b245f08b1 --- /dev/null +++ b/spring-kafka-2/src/test/resources/application.yml @@ -0,0 +1,14 @@ +spring: + kafka: + consumer: + auto-offset-reset: earliest + group-id: baeldung +test: + topic: embedded-test-topic + +monitor: + kafka: + bootstrap: + config: "PLAINTEXT://localhost:9085" + consumer: + groupid: "baeldungGrp" diff --git a/spring-kafka-2/src/test/resources/logback-test.xml b/spring-kafka-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..74f126ebc1 --- /dev/null +++ b/spring-kafka-2/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-kafka/pom.xml b/spring-kafka/pom.xml index d51c2e300f..7b0bb0a8b7 100644 --- a/spring-kafka/pom.xml +++ b/spring-kafka/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../parent-boot-2 + ../parent-boot-3 @@ -61,8 +61,24 @@ awaitility test + + org.apache.commons + commons-lang3 + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.spring.kafka.KafkaApplication + + + + + 1.16.2 diff --git a/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java b/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java index 89cd1c8dac..f76be95c1c 100644 --- a/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java +++ b/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java @@ -6,7 +6,7 @@ import org.apache.kafka.common.serialization.StringDeserializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.Collections; import java.util.HashMap; import java.util.List; diff --git a/spring-kafka/src/main/java/com/baeldung/kafka/ssl/KafkaProducer.java b/spring-kafka/src/main/java/com/baeldung/kafka/ssl/KafkaProducer.java index 895d437c6b..38ce366355 100644 --- a/spring-kafka/src/main/java/com/baeldung/kafka/ssl/KafkaProducer.java +++ b/spring-kafka/src/main/java/com/baeldung/kafka/ssl/KafkaProducer.java @@ -15,9 +15,12 @@ public class KafkaProducer { public void sendMessage(String message, String topic) { log.info("Producing message: {}", message); kafkaTemplate.send(topic, "key", message) - .addCallback( - result -> log.info("Message sent to topic: {}", message), - ex -> log.error("Failed to send message", ex) - ); + .whenComplete((result, ex) -> { + if (ex == null) { + log.info("Message sent to topic: {}", message); + } else { + log.error("Failed to send message", ex); + } + }); } } diff --git a/spring-kafka/src/main/java/com/baeldung/kafka/streams/KafkaProducer.java b/spring-kafka/src/main/java/com/baeldung/kafka/streams/KafkaProducer.java index 2b8e9bbfbd..664758a052 100644 --- a/spring-kafka/src/main/java/com/baeldung/kafka/streams/KafkaProducer.java +++ b/spring-kafka/src/main/java/com/baeldung/kafka/streams/KafkaProducer.java @@ -15,9 +15,12 @@ public class KafkaProducer { public void sendMessage(String message) { kafkaTemplate.send("input-topic", message) - .addCallback( - result -> log.info("Message sent to topic: {}", message), - ex -> log.error("Failed to send message", ex) - ); + .whenComplete((result, ex) -> { + if (ex == null) { + log.info("Message sent to topic: {}", message); + } else { + log.error("Failed to send message", ex); + } + }); } } diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java index 9b79f716e9..ff2d21668f 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java @@ -1,5 +1,6 @@ package com.baeldung.spring.kafka; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -16,8 +17,6 @@ import org.springframework.kafka.support.KafkaHeaders; import org.springframework.kafka.support.SendResult; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; @SpringBootApplication public class KafkaApplication { @@ -102,18 +101,13 @@ public class KafkaApplication { public void sendMessage(String message) { - ListenableFuture> future = kafkaTemplate.send(topicName, message); + CompletableFuture> future = kafkaTemplate.send(topicName, message); + future.whenComplete((result, ex) -> { - future.addCallback(new ListenableFutureCallback>() { - - @Override - public void onSuccess(SendResult result) { + if (ex == null) { System.out.println("Sent message=[" + message + "] with offset=[" + result.getRecordMetadata() .offset() + "]"); - } - - @Override - public void onFailure(Throwable ex) { + } else { System.out.println("Unable to send message=[" + message + "] due to : " + ex.getMessage()); } }); @@ -155,13 +149,13 @@ public class KafkaApplication { } @KafkaListener(topics = "${message.topic.name}", containerFactory = "headersKafkaListenerContainerFactory") - public void listenWithHeaders(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + public void listenWithHeaders(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION) int partition) { System.out.println("Received Message: " + message + " from partition: " + partition); latch.countDown(); } @KafkaListener(topicPartitions = @TopicPartition(topic = "${partitioned.topic.name}", partitions = { "0", "3" }), containerFactory = "partitionsKafkaListenerContainerFactory") - public void listenToPartition(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + public void listenToPartition(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION) int partition) { System.out.println("Received Message: " + message + " from partition: " + partition); this.partitionLatch.countDown(); } diff --git a/spring-kafka/src/test/java/com/baeldung/kafka/embedded/EmbeddedKafkaIntegrationTest.java b/spring-kafka/src/test/java/com/baeldung/kafka/embedded/EmbeddedKafkaIntegrationTest.java index eebcf778be..030d166ca4 100644 --- a/spring-kafka/src/test/java/com/baeldung/kafka/embedded/EmbeddedKafkaIntegrationTest.java +++ b/spring-kafka/src/test/java/com/baeldung/kafka/embedded/EmbeddedKafkaIntegrationTest.java @@ -1,7 +1,6 @@ package com.baeldung.kafka.embedded; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -16,6 +15,8 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.test.context.EmbeddedKafka; import org.springframework.test.annotation.DirtiesContext; +import com.fasterxml.jackson.databind.ObjectMapper; + @SpringBootTest @DirtiesContext @EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) @@ -33,6 +34,8 @@ class EmbeddedKafkaIntegrationTest { @Value("${test.topic}") private String topic; + private ObjectMapper objectMapper = new ObjectMapper(); + @BeforeEach void setup() { consumer.resetLatch(); @@ -44,7 +47,8 @@ class EmbeddedKafkaIntegrationTest { template.send(topic, data); - boolean messageConsumed = consumer.getLatch().await(10, TimeUnit.SECONDS); + boolean messageConsumed = consumer.getLatch() + .await(10, TimeUnit.SECONDS); assertTrue(messageConsumed); assertThat(consumer.getPayload(), containsString(data)); } @@ -55,7 +59,8 @@ class EmbeddedKafkaIntegrationTest { producer.send(topic, data); - boolean messageConsumed = consumer.getLatch().await(10, TimeUnit.SECONDS); + boolean messageConsumed = consumer.getLatch() + .await(10, TimeUnit.SECONDS); assertTrue(messageConsumed); assertThat(consumer.getPayload(), containsString(data)); } diff --git a/spring-kafka/src/test/java/com/baeldung/kafka/streams/KafkaStreamsApplicationLiveTest.java b/spring-kafka/src/test/java/com/baeldung/kafka/streams/KafkaStreamsApplicationLiveTest.java index 85df8485d2..aee3c2c0dc 100644 --- a/spring-kafka/src/test/java/com/baeldung/kafka/streams/KafkaStreamsApplicationLiveTest.java +++ b/spring-kafka/src/test/java/com/baeldung/kafka/streams/KafkaStreamsApplicationLiveTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.io.TempDir; 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.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-native/README.md b/spring-native/README.md index 0f193252d0..72308cb9d5 100644 --- a/spring-native/README.md +++ b/spring-native/README.md @@ -1,3 +1,4 @@ ## Relevant Articles: - [Introduction to Spring Native](https://www.baeldung.com/spring-native-intro) +- [Ahead of Time Optimizations in Spring 6](https://www.baeldung.com/aot-optimization-spring) \ No newline at end of file diff --git a/spring-native/pom.xml b/spring-native/pom.xml index 0cd502fbc1..55f17c833f 100644 --- a/spring-native/pom.xml +++ b/spring-native/pom.xml @@ -72,10 +72,7 @@ paketobuildpacks/builder:tiny 2.7.1 0.12.1 - 1.8 - 1.8 - 1.8 2.17.1 - + \ No newline at end of file diff --git a/spring-reactive-modules/README.md b/spring-reactive-modules/README.md index 3522efec17..57c3eebbff 100644 --- a/spring-reactive-modules/README.md +++ b/spring-reactive-modules/README.md @@ -1,4 +1,3 @@ ## Spring Reactive This module contains modules about Spring Reactive -- [How to Resolve Spring Webflux DataBufferLimitException](https://www.baeldung.com/spring-webflux-databufferlimitexception) diff --git a/spring-reactive-modules/pom.xml b/spring-reactive-modules/pom.xml index 9822642a11..c8c9c84394 100644 --- a/spring-reactive-modules/pom.xml +++ b/spring-reactive-modules/pom.xml @@ -23,10 +23,13 @@ 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 spring-reactive-exceptions + spring-reactor + spring-webflux-amqp diff --git a/spring-reactive-modules/spring-5-reactive-3/README.md b/spring-reactive-modules/spring-5-reactive-3/README.md index 044b3db5f4..24a7c43ad3 100644 --- a/spring-reactive-modules/spring-5-reactive-3/README.md +++ b/spring-reactive-modules/spring-5-reactive-3/README.md @@ -4,4 +4,5 @@ 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) - More articles: [[<-- prev]](../spring-5-reactive-2) diff --git a/spring-reactive-modules/spring-5-reactive-3/pom.xml b/spring-reactive-modules/spring-5-reactive-3/pom.xml index 5d5bfbdc5b..d33b63e921 100644 --- a/spring-reactive-modules/spring-5-reactive-3/pom.xml +++ b/spring-reactive-modules/spring-5-reactive-3/pom.xml @@ -20,6 +20,14 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-openfeign + org.projectreactor reactor-spring @@ -35,10 +43,27 @@ reactor-test test + + org.projectlombok + lombok + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + 1.0.1.RELEASE + 2021.0.4 \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/Product.java b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/Product.java new file mode 100644 index 0000000000..f915792a31 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/Product.java @@ -0,0 +1,13 @@ +package com.baeldung.webclient; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Product { + private String title; + private String description; +} diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsFeignClient.java b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsFeignClient.java new file mode 100644 index 0000000000..d3f7f8118f --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsFeignClient.java @@ -0,0 +1,15 @@ +package com.baeldung.webclient; + +import java.net.URI; +import java.util.List; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@FeignClient(value = "productsBlocking", url = "http://localhost:8080") +public interface ProductsFeignClient { + + @RequestMapping(method = RequestMethod.GET, value = "/slow-service-products", produces = "application/json") + List getProductsBlocking(URI baseUrl); +} diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java new file mode 100644 index 0000000000..8f70c3b228 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/ProductsSlowServiceController.java @@ -0,0 +1,21 @@ +package com.baeldung.webclient; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ProductsSlowServiceController { + + @GetMapping("/slow-service-products") + private List getAllProducts() throws InterruptedException { + Thread.sleep(2000L); // delay + return Arrays.asList( + new Product("Fancy Smartphone", "A stylish phone you need"), + new Product("Cool Watch", "The only device you need"), + new Product("Smart TV", "Cristal clean images") + ); + } +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebClientApplication.java b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebClientApplication.java new file mode 100644 index 0000000000..9e55211b24 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebClientApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.webclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableFeignClients +public class WebClientApplication { + + public static void main(String[] args) { + SpringApplication.run(WebClientApplication.class, args); + } +} + diff --git a/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebController.java b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebController.java new file mode 100644 index 0000000000..7ab6754d44 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/main/java/com/baeldung/webclient/WebController.java @@ -0,0 +1,59 @@ +package com.baeldung.webclient; + +import java.net.URI; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Flux; + +@Slf4j +@RestController +public class WebController { + + private static final int DEFAULT_PORT = 8080; + + public static final String SLOW_SERVICE_PRODUCTS_ENDPOINT_NAME = "/slow-service-products"; + + @Setter + private int serverPort = DEFAULT_PORT; + + @Autowired + private ProductsFeignClient productsFeignClient; + + @GetMapping("/products-blocking") + public List getProductsBlocking() { + log.info("Starting BLOCKING Controller!"); + final URI uri = URI.create(getSlowServiceBaseUri()); + + List result = productsFeignClient.getProductsBlocking(uri); + result.forEach(product -> log.info(product.toString())); + log.info("Exiting BLOCKING Controller!"); + return result; + } + + @GetMapping(value = "/products-non-blocking", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux getProductsNonBlocking() { + log.info("Starting NON-BLOCKING Controller!"); + Flux productFlux = WebClient.create() + .get() + .uri(getSlowServiceBaseUri() + SLOW_SERVICE_PRODUCTS_ENDPOINT_NAME) + .retrieve() + .bodyToFlux(Product.class); + + productFlux.subscribe(product -> log.info(product.toString())); + log.info("Exiting NON-BLOCKING Controller!"); + return productFlux; + } + + private String getSlowServiceBaseUri() { + return "http://localhost:" + serverPort; + } + +} diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java b/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java similarity index 98% rename from spring-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java rename to spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java index b885919bbb..f30b4a8a3b 100644 --- a/spring-reactive-modules/spring-5-reactive-3/src/test/java/databuffer/DataBufferToInputStreamUnitTest.java +++ b/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/databuffer/DataBufferToInputStreamUnitTest.java @@ -1,4 +1,4 @@ -package databuffer; +package com.baeldung.databuffer; import com.baeldung.databuffer.DataBufferToInputStream; diff --git a/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java b/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java new file mode 100644 index 0000000000..e401fb649d --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-3/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java @@ -0,0 +1,49 @@ +package com.baeldung.webclient; + +import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_CLASS; + +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.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.reactive.server.WebTestClient; + +@DirtiesContext(classMode = BEFORE_CLASS) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = WebClientApplication.class) +class WebControllerIntegrationTest { + + @LocalServerPort + private int randomServerPort; + + @Autowired + private WebTestClient testClient; + + @Autowired + private WebController webController; + + @BeforeEach + void setup() { + webController.setServerPort(randomServerPort); + } + + @Test + void whenEndpointWithBlockingClientIsCalled_thenThreeProductsAreReceived() { + testClient.get() + .uri("/products-blocking") + .exchange() + .expectStatus().isOk() + .expectBodyList(Product.class).hasSize(3); + } + + @Test + void whenEndpointWithNonBlockingClientIsCalled_thenThreeProductsAreReceived() { + testClient.get() + .uri("/products-non-blocking") + .exchange() + .expectStatus().isOk() + .expectBodyList(Product.class).hasSize(3); + } +} \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-client-2/README.md b/spring-reactive-modules/spring-5-reactive-client-2/README.md index 067a87a9d5..04fe3c8f42 100644 --- a/spring-reactive-modules/spring-5-reactive-client-2/README.md +++ b/spring-reactive-modules/spring-5-reactive-client-2/README.md @@ -7,4 +7,5 @@ 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) diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java b/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java new file mode 100644 index 0000000000..d664ac58e0 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/StreamLargeFileApp.java @@ -0,0 +1,12 @@ +package com.baeldung.streamlargefile; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StreamLargeFileApp { + + public static void main(String... args) { + SpringApplication.run(StreamLargeFileApp.class, args); + } +} 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-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java new file mode 100644 index 0000000000..3288aa7787 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LargeFileDownloadWebClient.java @@ -0,0 +1,41 @@ +package com.baeldung.streamlargefile.client; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Flux; + +public class LargeFileDownloadWebClient { + + private LargeFileDownloadWebClient() { + } + + public static long fetch(WebClient client, String destination) throws IOException { + Flux flux = client.get() + .retrieve() + .bodyToFlux(DataBuffer.class); + + Path path = Paths.get(destination); + + DataBufferUtils.write(flux, path) + .block(); + + return Files.size(path); + } + + public static void main(String... args) throws IOException { + String baseUrl = args[0]; + String destination = args[1]; + + WebClient client = WebClient.create(baseUrl); + + long bytes = fetch(client, destination); + System.out.printf("downloaded %d bytes to %s", bytes, destination); + } +} 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-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java new file mode 100644 index 0000000000..9b02a0d47b --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/client/LimitedFileDownloadWebClient.java @@ -0,0 +1,55 @@ +package com.baeldung.streamlargefile.client; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +public class LimitedFileDownloadWebClient { + + private LimitedFileDownloadWebClient() { + } + + public static long fetch(WebClient client, String destination) throws IOException { + Mono mono = client.get() + .retrieve() + .bodyToMono(byte[].class) + .onErrorMap(RuntimeException::new); + + byte[] bytes = mono.block(); + + Path path = Paths.get(destination); + Files.write(path, bytes); + + return bytes.length; + } + + public static void main(String... args) throws IOException { + String baseUrl = args[0]; + String destination = args[1]; + + WebClient client = WebClient.builder() + .baseUrl(baseUrl) + .exchangeStrategies(useMaxMemory()) + .build(); + + long bytes = fetch(client, destination); + System.out.printf("downloaded %d bytes to %s", bytes, destination); + } + + public static ExchangeStrategies useMaxMemory() { + long totalMemory = Runtime.getRuntime() + .maxMemory(); + + return ExchangeStrategies.builder() + .codecs(configurer -> + configurer.defaultCodecs() + .maxInMemorySize((int) totalMemory)) + .build(); + } +} 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-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java new file mode 100644 index 0000000000..7fa27cced6 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/java/com/baeldung/streamlargefile/server/LargeFileController.java @@ -0,0 +1,31 @@ +package com.baeldung.streamlargefile.server; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/large-file") +public class LargeFileController { + + public static final Path downloadPath = Paths.get("/tmp/large.dat"); + + @GetMapping("size") + Long getSize() throws IOException { + return Files.size(downloadPath); + } + + @GetMapping + ResponseEntity get() { + return ResponseEntity.ok() + .body(new FileSystemResource(downloadPath)); + } +} diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh b/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh new file mode 100755 index 0000000000..bca9e35796 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/generate-sample-files.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +generate() { + file="$1" + size="$2" + + fallocate -l "$size" "$file" + ls -lah "$file" +} + +generate /tmp/small.dat 128K +generate /tmp/large.dat 128M diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/run.sh b/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/run.sh new file mode 100755 index 0000000000..72727643af --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/main/resources/streamlargefile/run.sh @@ -0,0 +1,21 @@ +#!/bin/bash +MYSELF="$(readlink -f "$0")" +MYDIR="${MYSELF%/*}" + +client="${1:-Large}" +url="${2:-http://localhost:8081/large-file}" +download_destination="${3:-/tmp/download.dat}" +xmx="${4:-32m}" + +module_dir="$(readlink -f "$MYDIR/../../../..")" + +echo "module: $module_dir" +cd $module_dir || exit + +echo "packaging..." +mvn clean package dependency:copy-dependencies + +echo "GET $url with $client client..." +java -Xmx$xmx -cp target/dependency/*:target/* \ +"com.baeldung.streamlargefile.client.${client}FileDownloadWebClient" \ +"$url" "$download_destination" diff --git a/spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java b/spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java new file mode 100644 index 0000000000..65ba97e283 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-client-2/src/test/java/com/baeldung/streamlargefile/LargeFileControllerLiveTest.java @@ -0,0 +1,59 @@ +package com.baeldung.streamlargefile; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.web.reactive.function.client.WebClient; + +import com.baeldung.streamlargefile.client.LargeFileDownloadWebClient; +import com.baeldung.streamlargefile.client.LimitedFileDownloadWebClient; +import com.baeldung.streamlargefile.server.LargeFileController; + +class LargeFileControllerLiveTest { + + private static final String BASE_URL = "http://localhost:8081/large-file"; + private static final String DOWNLOAD_DESTINATION = LargeFileController.downloadPath.resolveSibling("download.dat") + .toString(); + private static final Path downloadFile = LargeFileController.downloadPath; + private static final Runtime runtime = Runtime.getRuntime(); + private static final Long xmx = runtime.maxMemory(); + + private WebClient client = WebClient.create(BASE_URL); + + @BeforeAll + static void init() throws IOException { + if (!Files.exists(downloadFile)) { + ClassPathResource res = new ClassPathResource("streamlargefile/generate-sample-files.sh"); + + runtime.exec(res.getFile() + .getAbsolutePath()); + } + } + + @Test + void givenMemorySafeClient_whenFileLargerThanXmx_thenFileDownloaded() throws IOException { + if (xmx < Files.size(downloadFile)) { + long size = LargeFileDownloadWebClient.fetch(client, DOWNLOAD_DESTINATION); + assertTrue(size > xmx); + } + } + + @Test + void givenLimitedClient_whenXmxLargerThanFile_thenFileDownloaded() throws IOException { + WebClient client = WebClient.builder() + .baseUrl(BASE_URL) + .exchangeStrategies(LimitedFileDownloadWebClient.useMaxMemory()) + .build(); + + if (xmx > Files.size(downloadFile)) { + long size = LimitedFileDownloadWebClient.fetch(client, DOWNLOAD_DESTINATION); + assertTrue(size < xmx); + } + } +} diff --git a/spring-reactive-modules/spring-5-reactive-client/pom.xml b/spring-reactive-modules/spring-5-reactive-client/pom.xml index 16581d53af..a0e5f7794e 100644 --- a/spring-reactive-modules/spring-5-reactive-client/pom.xml +++ b/spring-reactive-modules/spring-5-reactive-client/pom.xml @@ -136,14 +136,6 @@ JAR - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - @@ -189,7 +181,7 @@ 1.0 1.1.6 4.0.1 - 3.2.10.RELEASE + 3.5.3 2.26.0 diff --git a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java b/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java index dabfd22056..e1eefe4d61 100644 --- a/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java +++ b/spring-reactive-modules/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java @@ -49,7 +49,7 @@ public class WebClientLoggingIntegrationTest { private String sampleResponseBody; @BeforeEach - private void setup() throws Exception { + void setup() throws Exception { post = new Post("Learn WebClient logging with Baeldung!", "", 1); sampleResponseBody = new ObjectMapper().writeValueAsString(post); diff --git a/spring-reactive-modules/spring-5-reactive-filters/.gitignore b/spring-reactive-modules/spring-5-reactive-filters/.gitignore new file mode 100644 index 0000000000..dec013dfa4 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-filters/.gitignore @@ -0,0 +1,12 @@ +#folders# +.idea +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive-filters/README.md b/spring-reactive-modules/spring-5-reactive-filters/README.md new file mode 100644 index 0000000000..815ca35442 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-filters/README.md @@ -0,0 +1,10 @@ +## 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 + +- [Spring WebFlux Filters](https://www.baeldung.com/spring-webflux-filters) diff --git a/spring-reactive-modules/spring-5-reactive-filters/pom.xml b/spring-reactive-modules/spring-5-reactive-filters/pom.xml new file mode 100644 index 0000000000..c9503d631a --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-filters/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + spring-5-reactive-filters + 0.0.1-SNAPSHOT + spring-5-reactive-filters + 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-webflux + + + + + org.springframework.boot + spring-boot-devtools + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + io.projectreactor + reactor-test + test + + + + + io.netty + netty-all + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.reactive.Spring5ReactiveFiltersApplication + JAR + + + + + + \ 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-5-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java new file mode 100644 index 0000000000..41f95a274c --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/Spring5ReactiveFiltersApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.reactive; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Spring5ReactiveFiltersApplication{ + + public static void main(String[] args) { + SpringApplication.run(Spring5ReactiveFiltersApplication.class, args); + } + +} diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java rename to spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleHandlerFilterFunction.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java rename to spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/ExampleWebFilter.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java rename to spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerHandler.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java rename to spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/PlayerRouter.java diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/UserController.java b/spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/filters/UserController.java rename to spring-reactive-modules/spring-5-reactive-filters/src/main/java/com/baeldung/reactive/filters/UserController.java diff --git a/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/application.properties b/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/application.properties new file mode 100644 index 0000000000..4b49e8e8a2 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/application.properties @@ -0,0 +1 @@ +logging.level.root=INFO \ No newline at end of file diff --git a/feign/src/main/resources/logback.xml b/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/logback.xml similarity index 77% rename from feign/src/main/resources/logback.xml rename to spring-reactive-modules/spring-5-reactive-filters/src/main/resources/logback.xml index e5e962c8e0..7d900d8ea8 100644 --- a/feign/src/main/resources/logback.xml +++ b/spring-reactive-modules/spring-5-reactive-filters/src/main/resources/logback.xml @@ -5,10 +5,9 @@ %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-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java b/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java similarity index 68% rename from spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java rename to spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java index 4bf35f74f4..3e026ef45f 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java +++ b/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/SpringContextTest.java @@ -1,15 +1,16 @@ -package com.baeldung.cloud.openfeign; - +package com.baeldung; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.reactive.Spring5ReactiveFiltersApplication; + @RunWith(SpringRunner.class) -@SpringBootTest(classes = ExampleApplication.class) +@SpringBootTest(classes = Spring5ReactiveFiltersApplication.class) public class SpringContextTest { - + @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java b/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java rename to spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/PlayerHandlerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java b/spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java rename to spring-reactive-modules/spring-5-reactive-filters/src/test/java/com/baeldung/reactive/filters/UserControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-5-reactive/pom.xml b/spring-reactive-modules/spring-5-reactive/pom.xml index 5eb98eb106..212281b6f9 100644 --- a/spring-reactive-modules/spring-5-reactive/pom.xml +++ b/spring-reactive-modules/spring-5-reactive/pom.xml @@ -26,7 +26,11 @@ org.springframework.boot - spring-boot-starter-webflux + spring-boot-starter-integration + + + org.springframework.boot + spring-boot-starter-websocket javax.json.bind @@ -111,6 +115,10 @@ org.apache.httpcomponents httpclient + + io.netty + netty-all + diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java index a8cd18c470..ef862dd957 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java @@ -2,8 +2,9 @@ package com.baeldung.reactive; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -@SpringBootApplication +@SpringBootApplication(exclude = { RedisAutoConfiguration.class }) public class Spring5ReactiveApplication{ public static void main(String[] args) { diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java index 0e71673df6..148dd07510 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java @@ -2,8 +2,22 @@ package com.baeldung.websocket; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -@SpringBootApplication +@SpringBootApplication(exclude = { + SecurityAutoConfiguration.class, + UserDetailsServiceAutoConfiguration.class, + ReactiveSecurityAutoConfiguration.class, + ReactiveUserDetailsServiceAutoConfiguration.class, + ReactiveOAuth2ClientAutoConfiguration.class, + WebMvcAutoConfiguration.class, + RedisAutoConfiguration.class}) public class ReactiveWebSocketApplication { public static void main(String[] args) { SpringApplication.run(ReactiveWebSocketApplication.class, args); diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java index 43a98d068d..8ebd6118b2 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java @@ -10,19 +10,25 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; import org.springframework.web.reactive.socket.WebSocketHandler; +import org.springframework.web.reactive.socket.server.WebSocketService; +import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService; +import org.springframework.web.reactive.socket.server.upgrade.TomcatRequestUpgradeStrategy; +import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration +@EnableWebSocket public class ReactiveWebSocketConfiguration { @Autowired @Qualifier("ReactiveWebSocketHandler") - private WebSocketHandler webSocketHandler; + private ReactiveWebSocketHandler reactiveWebSocketHandler; @Bean - public HandlerMapping webSocketHandlerMapping() { + public HandlerMapping reactiveWebSocketHandlerMapping() { Map map = new HashMap<>(); - map.put("/event-emitter", webSocketHandler); + map.put("/event-emitter", reactiveWebSocketHandler); SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); handlerMapping.setOrder(1); @@ -32,6 +38,26 @@ public class ReactiveWebSocketConfiguration { @Bean public WebSocketHandlerAdapter handlerAdapter() { - return new WebSocketHandlerAdapter(); + return new WebSocketHandlerAdapter(webSocketService()); + } + + @Bean + public WebSocketService webSocketService() { + TomcatRequestUpgradeStrategy tomcatRequestUpgradeStrategy = new TomcatRequestUpgradeStrategy(); + tomcatRequestUpgradeStrategy.setMaxSessionIdleTimeout(10000L); + tomcatRequestUpgradeStrategy.setAsyncSendTimeout(10000L); + return new HandshakeWebSocketService(tomcatRequestUpgradeStrategy); + } + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter(); + + /** + * Add one or more classes annotated with `@ServerEndpoint`. + */ + serverEndpointExporter.setAnnotatedEndpointClasses(WebSocketController.class); + + return serverEndpointExporter; } } \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java new file mode 100644 index 0000000000..bf4a463ae6 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java @@ -0,0 +1,40 @@ +package com.baeldung.websocket; + +import org.slf4j.Logger; +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 { + + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketController.class); + @OnOpen + public void onOpen(Session session, EndpointConfig endpointConfig) throws IOException { + // Get session and WebSocket connection + session.setMaxIdleTimeout(0); + LOGGER.info("Get session and WebSocket connection"); + } + + @OnMessage + public void onMessage(String message, Session session) throws IOException { + // Handle new messages + LOGGER.info("Handle new messages -> {}", message ); + } + + @OnClose + public void onClose(Session session) throws IOException { + // WebSocket connection closes + LOGGER.info("WebSocket connection closes"); + } + + @OnError + public void onError(Session session, Throwable throwable) { + // Do error handling here + LOGGER.info("Do error handling here"); + } +} 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 index 4b49e8e8a2..dfe4a4d994 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties +++ b/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties @@ -1 +1,2 @@ -logging.level.root=INFO \ No newline at end of file +logging.level.root=INFO +server.tomcat.max-keep-alive-requests=1 \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive-exceptions/README.md b/spring-reactive-modules/spring-reactive-exceptions/README.md new file mode 100644 index 0000000000..8c5bc4f537 --- /dev/null +++ b/spring-reactive-modules/spring-reactive-exceptions/README.md @@ -0,0 +1,2 @@ + +- [How to Resolve Spring Webflux DataBufferLimitException](https://www.baeldung.com/spring-webflux-databufferlimitexception) diff --git a/spring-reactive-modules/spring-reactive/README.md b/spring-reactive-modules/spring-reactive/README.md index 9f1852d912..7dfc7b2952 100644 --- a/spring-reactive-modules/spring-reactive/README.md +++ b/spring-reactive-modules/spring-reactive/README.md @@ -1,3 +1,7 @@ +### 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. + ## Spring Reactive This module contains articles describing reactive processing in Spring. @@ -13,4 +17,8 @@ This module contains articles describing reactive processing in Spring. - [Spring WebClient Requests with Parameters](https://www.baeldung.com/webflux-webclient-parameters) - [Handling Errors in Spring WebFlux](https://www.baeldung.com/spring-webflux-errors) - [Spring Security 5 for Reactive Applications](https://www.baeldung.com/spring-security-5-reactive) -- [Concurrency in Spring WebFlux](https://www.baeldung.com/spring-webflux-concurrency) \ No newline at end of file +- [Concurrency in Spring WebFlux](https://www.baeldung.com/spring-webflux-concurrency) + +### 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. diff --git a/spring-reactor/README.md b/spring-reactive-modules/spring-reactor/README.md similarity index 100% rename from spring-reactor/README.md rename to spring-reactive-modules/spring-reactor/README.md diff --git a/spring-reactor/pom.xml b/spring-reactive-modules/spring-reactor/pom.xml similarity index 100% rename from spring-reactor/pom.xml rename to spring-reactive-modules/spring-reactor/pom.xml diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/Config.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/Config.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/Config.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/Config.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/NotificationApplication.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/NotificationApplication.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/NotificationApplication.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/NotificationApplication.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/consumer/NotificationConsumer.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/consumer/NotificationConsumer.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/consumer/NotificationConsumer.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/consumer/NotificationConsumer.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/controller/NotificationController.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/controller/NotificationController.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/controller/NotificationController.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/controller/NotificationController.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/domain/NotificationData.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/domain/NotificationData.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/domain/NotificationData.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/domain/NotificationData.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/service/NotificationService.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/service/NotificationService.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/service/NotificationService.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/service/NotificationService.java diff --git a/spring-reactor/src/main/java/com/baeldung/reactorbus/service/impl/NotificationServiceimpl.java b/spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/service/impl/NotificationServiceimpl.java similarity index 100% rename from spring-reactor/src/main/java/com/baeldung/reactorbus/service/impl/NotificationServiceimpl.java rename to spring-reactive-modules/spring-reactor/src/main/java/com/baeldung/reactorbus/service/impl/NotificationServiceimpl.java diff --git a/spring-reactive-modules/spring-reactor/src/main/resources/logback.xml b/spring-reactive-modules/spring-reactor/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-reactive-modules/spring-reactor/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-reactor/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-reactor/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-reactor/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-reactor/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-reactor/src/test/java/com/baeldung/reactorbus/NotificationApplicationIntegrationTest.java b/spring-reactive-modules/spring-reactor/src/test/java/com/baeldung/reactorbus/NotificationApplicationIntegrationTest.java similarity index 100% rename from spring-reactor/src/test/java/com/baeldung/reactorbus/NotificationApplicationIntegrationTest.java rename to spring-reactive-modules/spring-reactor/src/test/java/com/baeldung/reactorbus/NotificationApplicationIntegrationTest.java diff --git a/spring-webflux-amqp/.gitignore b/spring-reactive-modules/spring-webflux-amqp/.gitignore similarity index 100% rename from spring-webflux-amqp/.gitignore rename to spring-reactive-modules/spring-webflux-amqp/.gitignore diff --git a/spring-webflux-amqp/README.md b/spring-reactive-modules/spring-webflux-amqp/README.md similarity index 100% rename from spring-webflux-amqp/README.md rename to spring-reactive-modules/spring-webflux-amqp/README.md diff --git a/spring-webflux-amqp/pom.xml b/spring-reactive-modules/spring-webflux-amqp/pom.xml similarity index 100% rename from spring-webflux-amqp/pom.xml rename to spring-reactive-modules/spring-webflux-amqp/pom.xml diff --git a/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/AmqpReactiveController.java b/spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/AmqpReactiveController.java similarity index 100% rename from spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/AmqpReactiveController.java rename to spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/AmqpReactiveController.java diff --git a/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/DestinationsConfig.java b/spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/DestinationsConfig.java similarity index 100% rename from spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/DestinationsConfig.java rename to spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/DestinationsConfig.java diff --git a/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/MessageListenerContainerFactory.java b/spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/MessageListenerContainerFactory.java similarity index 100% rename from spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/MessageListenerContainerFactory.java rename to spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/MessageListenerContainerFactory.java diff --git a/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/SpringWebfluxAmqpApplication.java b/spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/SpringWebfluxAmqpApplication.java similarity index 100% rename from spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/SpringWebfluxAmqpApplication.java rename to spring-reactive-modules/spring-webflux-amqp/src/main/java/com/baeldung/spring/amqp/SpringWebfluxAmqpApplication.java diff --git a/spring-webflux-amqp/src/main/resources/application.yml b/spring-reactive-modules/spring-webflux-amqp/src/main/resources/application.yml similarity index 100% rename from spring-webflux-amqp/src/main/resources/application.yml rename to spring-reactive-modules/spring-webflux-amqp/src/main/resources/application.yml diff --git a/spring-reactive-modules/spring-webflux-amqp/src/main/resources/logback.xml b/spring-reactive-modules/spring-webflux-amqp/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-reactive-modules/spring-webflux-amqp/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-webflux-amqp/src/test/java/com/baeldung/SpringContextLiveTest.java b/spring-reactive-modules/spring-webflux-amqp/src/test/java/com/baeldung/SpringContextLiveTest.java similarity index 100% rename from spring-webflux-amqp/src/test/java/com/baeldung/SpringContextLiveTest.java rename to spring-reactive-modules/spring-webflux-amqp/src/test/java/com/baeldung/SpringContextLiveTest.java diff --git a/spring-webflux-amqp/src/test/java/com/baeldung/spring/amqp/SpringWebfluxAmqpLiveTest.java b/spring-reactive-modules/spring-webflux-amqp/src/test/java/com/baeldung/spring/amqp/SpringWebfluxAmqpLiveTest.java similarity index 100% rename from spring-webflux-amqp/src/test/java/com/baeldung/spring/amqp/SpringWebfluxAmqpLiveTest.java rename to spring-reactive-modules/spring-webflux-amqp/src/test/java/com/baeldung/spring/amqp/SpringWebfluxAmqpLiveTest.java diff --git a/spring-roo/pom.xml b/spring-roo/pom.xml index 94f9eb0c6f..fcfafcdaac 100644 --- a/spring-roo/pom.xml +++ b/spring-roo/pom.xml @@ -11,6 +11,9 @@ spring-roo jar + + + io.spring.platform platform-bom diff --git a/spring-scheduling/src/main/java/com/baeldung/async/config/SpringAsyncConfig.java b/spring-scheduling/src/main/java/com/baeldung/async/config/SpringAsyncConfig.java index 56fa643017..872f59ebb6 100644 --- a/spring-scheduling/src/main/java/com/baeldung/async/config/SpringAsyncConfig.java +++ b/spring-scheduling/src/main/java/com/baeldung/async/config/SpringAsyncConfig.java @@ -24,7 +24,9 @@ public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { - return new SimpleAsyncTaskExecutor(); + ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.initialize(); + return threadPoolTaskExecutor; } @Override diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 1e0ae825e1..223f0894d5 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -43,11 +43,13 @@ spring-security-web-rest-basic-auth spring-security-web-rest-custom spring-security-web-rest + spring-security-web-springdoc spring-security-web-sockets spring-security-web-thymeleaf spring-security-web-x509 spring-security-opa spring-security-pkce + spring-security-azuread \ No newline at end of file diff --git a/spring-security-modules/spring-security-auth0/src/main/java/com/baeldung/auth0/AuthConfig.java b/spring-security-modules/spring-security-auth0/src/main/java/com/baeldung/auth0/AuthConfig.java index 69cf8b3071..e010a86a0c 100644 --- a/spring-security-modules/spring-security-auth0/src/main/java/com/baeldung/auth0/AuthConfig.java +++ b/spring-security-modules/spring-security-auth0/src/main/java/com/baeldung/auth0/AuthConfig.java @@ -7,10 +7,9 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -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.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import com.auth0.AuthenticationController; @@ -20,7 +19,7 @@ import com.auth0.jwk.JwkProviderBuilder; @Configuration @EnableWebSecurity -public class AuthConfig extends WebSecurityConfigurerAdapter { +public class AuthConfig { @Value(value = "${com.auth0.domain}") private String domain; @@ -53,18 +52,23 @@ public class AuthConfig extends WebSecurityConfigurerAdapter { .build(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable(); - http - .authorizeRequests() - .antMatchers("/callback", "/login", "/").permitAll() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/login") - .and() - .logout().logoutSuccessHandler(logoutSuccessHandler()).permitAll(); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf() + .disable() + .authorizeRequests() + .antMatchers("/callback", "/login", "/") + .permitAll() + .anyRequest() + .authenticated() + .and() + .formLogin() + .loginPage("/login") + .and() + .logout() + .logoutSuccessHandler(logoutSuccessHandler()) + .permitAll(); + return http.build(); } public String getDomain() { diff --git a/spring-security-modules/spring-security-azuread/README.md b/spring-security-modules/spring-security-azuread/README.md new file mode 100644 index 0000000000..8b4d6d9666 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Authenticating Users with AzureAD in Spring Boot](https://www.baeldung.com/spring-boot-azuerad-authenticate-users) diff --git a/spring-security-modules/spring-security-azuread/pom.xml b/spring-security-modules/spring-security-azuread/pom.xml new file mode 100644 index 0000000000..c4dbbd14b9 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/pom.xml @@ -0,0 +1,76 @@ + + + + 4.0.0 + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + spring-security-azuread + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/Application.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/Application.java new file mode 100644 index 0000000000..ac36bc1328 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.security.azuread; + +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-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationConfiguration.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationConfiguration.java new file mode 100644 index 0000000000..4d82e930ae --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationConfiguration.java @@ -0,0 +1,72 @@ +package com.baeldung.security.azuread.config; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +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.core.GrantedAuthority; +import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; +import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; +import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.web.SecurityFilterChain; + +import com.baeldung.security.azuread.support.GroupsClaimMapper; +import com.baeldung.security.azuread.support.NamedOidcUser; + +@Configuration +@EnableConfigurationProperties(JwtAuthorizationProperties.class) +public class JwtAuthorizationConfiguration { + + + + @Bean + SecurityFilterChain customJwtSecurityChain(HttpSecurity http, JwtAuthorizationProperties props) throws Exception { + // @formatter:off + return http + .authorizeRequests( r -> r.anyRequest().authenticated()) + .oauth2Login(oauth2 -> { + oauth2.userInfoEndpoint(ep -> + ep.oidcUserService(customOidcUserService(props))); + }) + .build(); + // @formatter:on + } + + private OAuth2UserService customOidcUserService(JwtAuthorizationProperties props) { + final OidcUserService delegate = new OidcUserService(); + final GroupsClaimMapper mapper = new GroupsClaimMapper( + props.getAuthoritiesPrefix(), + props.getGroupsClaim(), + props.getGroupToAuthorities()); + + return (userRequest) -> { + OidcUser oidcUser = delegate.loadUser(userRequest); + // Enrich standard authorities with groups + Set mappedAuthorities = new HashSet<>(); + mappedAuthorities.addAll(oidcUser.getAuthorities()); + mappedAuthorities.addAll(mapper.mapAuthorities(oidcUser)); + + oidcUser = new NamedOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo(),oidcUser.getName()); + + return oidcUser; + }; + } + + + +// @Bean +// GrantedAuthoritiesMapper jwtAuthoritiesMapper(JwtAuthorizationProperties props) { +// return new MappingJwtGrantedAuthoritiesMapper( +// props.getAuthoritiesPrefix(), +// props.getGroupsClaim(), +// props.getGroupToAuthorities()); +// } + + +} diff --git a/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationProperties.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationProperties.java new file mode 100644 index 0000000000..981be317a3 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/config/JwtAuthorizationProperties.java @@ -0,0 +1,68 @@ +package com.baeldung.security.azuread.config; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Baeldung + * + */ +@ConfigurationProperties(prefix="baeldung.jwt.authorization") +public class JwtAuthorizationProperties { + + // Claim that has the group list + private String groupsClaim = "groups"; + + private String authoritiesPrefix = "ROLE_"; + + // map groupIds to a list of authorities. + private Map> groupToAuthorities = new HashMap<>(); + + /** + * @return the groupsClaim + */ + public String getGroupsClaim() { + return groupsClaim; + } + + /** + * @param groupsClaim the groupsClaim to set + */ + public void setGroupsClaim(String groupsClaim) { + this.groupsClaim = groupsClaim; + } + + /** + * @return the groupToAuthorities + */ + public Map> getGroupToAuthorities() { + return groupToAuthorities; + } + + /** + * @param groupToAuthorities the groupToAuthorities to set + */ + public void setGroupToAuthorities(Map> groupToAuthorities) { + this.groupToAuthorities = groupToAuthorities; + } + + /** + * @return the authoritiesPrefix + */ + public String getAuthoritiesPrefix() { + return authoritiesPrefix; + } + + /** + * @param authoritiesPrefix the authoritiesPrefix to set + */ + public void setAuthoritiesPrefix(String authoritiesPrefix) { + this.authoritiesPrefix = authoritiesPrefix; + } + + + +} diff --git a/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/controllers/IndexController.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/controllers/IndexController.java new file mode 100644 index 0000000000..d2cebd0231 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/controllers/IndexController.java @@ -0,0 +1,22 @@ +package com.baeldung.security.azuread.controllers; + +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import lombok.extern.slf4j.Slf4j; + +@Controller +@RequestMapping("/") +@Slf4j +public class IndexController { + + @GetMapping + public String index(Model model, Authentication user) { + log.info("GET /: user={}", user); + model.addAttribute("user", user); + return "index"; + } +} diff --git a/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/GroupsClaimMapper.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/GroupsClaimMapper.java new file mode 100644 index 0000000000..2487cd9db3 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/GroupsClaimMapper.java @@ -0,0 +1,61 @@ +/** + * + */ +package com.baeldung.security.azuread.support; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.oauth2.core.ClaimAccessor; +import org.springframework.security.oauth2.jwt.Jwt; + +/** + * @author Baeldung + * + */ +public class GroupsClaimMapper { + + private final String authoritiesPrefix; + private final String groupsClaim; + private final Map> groupToAuthorities; + + public GroupsClaimMapper(String authoritiesPrefix, String groupsClaim, Map> groupToAuthorities) { + this.authoritiesPrefix = authoritiesPrefix; + this.groupsClaim = groupsClaim; + this.groupToAuthorities = Collections.unmodifiableMap(groupToAuthorities); + } + + public Collection mapAuthorities(ClaimAccessor source) { + + List groups = source.getClaimAsStringList(groupsClaim); + if ( groups == null || groups.isEmpty()) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + for( String g : groups) { + List authNames = groupToAuthorities.get(g); + if ( authNames == null ) { + continue; + } + + List mapped = authNames.stream() + .map( s -> authoritiesPrefix + s) + .map( SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + result.addAll(mapped); + } + + return result; + } + +} diff --git a/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/NamedOidcUser.java b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/NamedOidcUser.java new file mode 100644 index 0000000000..b29b04fe7b --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/java/com/baeldung/security/azuread/support/NamedOidcUser.java @@ -0,0 +1,24 @@ +package com.baeldung.security.azuread.support; + +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.core.oidc.OidcIdToken; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; + +public class NamedOidcUser extends DefaultOidcUser { + private static final long serialVersionUID = 1L; + private final String userName; + + public NamedOidcUser(Collection authorities, OidcIdToken idToken, + OidcUserInfo userInfo, String userName) { + super(authorities,idToken,userInfo); + this.userName= userName; + } + + @Override + public String getName() { + return this.userName; + } +} diff --git a/spring-security-modules/spring-security-azuread/src/main/resources/application-azuread.yml b/spring-security-modules/spring-security-azuread/src/main/resources/application-azuread.yml new file mode 100644 index 0000000000..5e65c381c8 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/resources/application-azuread.yml @@ -0,0 +1,27 @@ +spring: + security: + oauth2: + client: + provider: + azure: + issuer-uri: https://login.microsoftonline.com/2e9fde3a-38ec-44f9-8bcd-c184dc1e8033/v2.0 + user-name-attribute: name + registration: + azure-dev: + provider: azure + #client-id: "6035bfd4-22f0-437c-b76f-da729a916cbf" + #client-secret: "fo28Q~-aLbmQvonnZtzbgtSiqYstmBWEmGPAodmx" + client-id: your-client-id + client-secret: your-secret-id + scope: + - openid + - email + - profile + +# Group mapping +baeldung: + jwt: + authorization: + group-to-authorities: + "ceef656a-fca9-49b6-821b-f7543b7065cb": BAELDUNG_RW + "eaaecb69-ccbc-4143-b111-7dd1ce1d99f1": BAELDUNG_RO,BAELDUNG_ADMIN \ No newline at end of file diff --git a/spring-security-modules/spring-security-azuread/src/main/resources/application.properties b/spring-security-modules/spring-security-azuread/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/spring-security-modules/spring-security-azuread/src/main/resources/templates/index.html b/spring-security-modules/spring-security-azuread/src/main/resources/templates/index.html new file mode 100644 index 0000000000..ca9a9bdbe8 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/main/resources/templates/index.html @@ -0,0 +1,53 @@ + + + + +Insert title here + + + +

Hello, NOMO_NOMO

+ +

User info:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeValue
Nameuser.name
Classuser.class
Principal Classuser.principal.class
isAuthenticated?user.authenticated
clientRegistrationIduser.authorizedClientregistrationId
Claim: keyvalue
Granted Authority: authority
+ + \ No newline at end of file diff --git a/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/ApplicationLiveTest.java b/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/ApplicationLiveTest.java new file mode 100644 index 0000000000..8c941aa787 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/ApplicationLiveTest.java @@ -0,0 +1,62 @@ +package com.baeldung.security.azuread; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; + +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.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("azuread") +class ApplicationLiveTest { + + @Autowired + TestRestTemplate rest; + + @LocalServerPort + int port; + + @Test + void testWhenAccessRootPath_thenRedirectToAzureAD() { + + ResponseEntity response = rest.getForEntity("http://localhost:" + port , String.class); + HttpStatus st = response.getStatusCode(); + assertThat(st) + .isEqualTo(HttpStatus.FOUND); + + URI location1 = response.getHeaders().getLocation(); + assertThat(location1) + .isNotNull(); + assertThat(location1.getPath()) + .isEqualTo("/oauth2/authorization/azure-dev"); + + assertThat(location1.getPort()) + .isEqualTo(port); + + assertThat(location1.getHost()) + .isEqualTo("localhost"); + + // Now let't follow this redirect + response = rest.getForEntity(location1, String.class); + assertThat(st) + .isEqualTo(HttpStatus.FOUND); + URI location2 = response.getHeaders().getLocation(); + assertThat(location2) + .isNotNull(); + + assertThat(location2.getHost()) + .describedAs("Should redirect to AzureAD") + .isEqualTo("login.microsoftonline.com"); + + } + +} diff --git a/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/support/GroupsClaimMapperUnitTest.java b/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/support/GroupsClaimMapperUnitTest.java new file mode 100644 index 0000000000..0a8f85d0d1 --- /dev/null +++ b/spring-security-modules/spring-security-azuread/src/test/java/com/baeldung/security/azuread/support/GroupsClaimMapperUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.security.azuread.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.core.ClaimAccessor; + +class GroupsClaimMapperUnitTest { + + private Map> g2a = new HashMap<>(); + + @Test + void testWhenNoGroupClaimsPresent_thenNoAuthoritiesAdded() { + + ClaimAccessor source = mock(ClaimAccessor.class); + GroupsClaimMapper mapper = new GroupsClaimMapper("ROLE", "group", g2a); + + Collection authorities = mapper.mapAuthorities(source); + assertThat(authorities) + .isNotNull() + .isEmpty(); + } + + @Test + void testWhenEmptyGroupClaimsPresent_thenNoAuthoritiesAdded() { + + ClaimAccessor source = mock(ClaimAccessor.class); + when(source.getClaimAsStringList("group")) + .thenReturn(Collections.emptyList()); + + GroupsClaimMapper mapper = new GroupsClaimMapper("ROLE", "group", g2a); + + Collection authorities = mapper.mapAuthorities(source); + assertThat(authorities) + .isNotNull() + .isEmpty(); + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/pom.xml b/spring-security-modules/spring-security-oauth2-testing/pom.xml new file mode 100644 index 0000000000..93348cb48c --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + spring-security-oauth2-testing + spring-security-oauth2-testing + pom + spring-security 6 oauth testing sample project + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + 6.1.0 + + + + + com.c4-soft.springaddons + spring-addons-oauth2-test + ${spring-addons.version} + + + + + reactive-resource-server + servlet-resource-server + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml new file mode 100644 index 0000000000..86f73cfdbf --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + reactive-resource-server + reactive-resource-server + Demo project for Spring Boot reactive resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-webflux + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file 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 new file mode 100644 index 0000000000..500d876bc4 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java @@ -0,0 +1,144 @@ +package com.baeldung; + +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +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; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +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.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Mono; + +@SpringBootApplication +public class ReactiveResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ReactiveResourceServerApplication.class, args); + } + + @Configuration + @EnableWebFluxSecurity + @EnableReactiveMethodSecurity + public 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 -> { + final var response = exchange.getResponse(); + 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())); + return response.writeWith(Mono.just(buffer)) + .doOnError(error -> DataBufferUtils.release(buffer)); + })); + + http.authorizeExchange() + .pathMatchers("/secured-route") + .hasRole("AUTHORIZED_PERSONNEL") + .anyExchange() + .authenticated(); + + return http.build(); + } + + static interface AuthoritiesConverter extends Converter>> { + } + + @Bean + AuthoritiesConverter realmRoles2AuthoritiesConverter() { + return (Jwt jwt) -> { + 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()); + }; + } + } + + @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"))); + } + + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public Mono getSecret() { + return Mono.just("Only authorized personnel can read that"); + } + } + + @RestController + @RequiredArgsConstructor + public class GreetingController { + private final MessageService messageService; + + @GetMapping("/greet") + public Mono> greet() { + return messageService.greet() + .map(ResponseEntity::ok); + } + + @GetMapping("/secured-route") + public Mono> securedRoute() { + return messageService.getSecret() + .map(ResponseEntity::ok); + } + + @GetMapping("/secured-method") + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public Mono> securedMethod() { + return messageService.getSecret() + .map(ResponseEntity::ok); + } + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml new file mode 100644 index 0000000000..01e655e1b3 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml @@ -0,0 +1,6 @@ +spring: + security: + oauth2: + resourceserver: + jwt: + issuer-uri: https://localhost:8443/realms/master 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 new file mode 100644 index 0000000000..97893bc1fb --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -0,0 +1,86 @@ +package com.baeldung; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +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({ MessageService.class }) +@ExtendWith(SpringExtension.class) +@EnableReactiveMethodSecurity +class MessageServiceUnitTest { + @Autowired + MessageService messageService; + + /*----------------------------------------------------------------------------*/ + /* greet() */ + /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ + /*----------------------------------------------------------------------------*/ + + @Test + void givenSecurityContextIsEmpty_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { + assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet() + .block()); + } + + @Test + @WithAnonymousUser + void givenUserIsAnonymous_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet() + .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() + .block()); + } + + @Test + @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") + void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet() + .block()); + } + + /*--------------------------------------------------------------------*/ + /* getSecret() */ + /* is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" */ + /*--------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsAnonymous_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret() + .block()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + assertEquals("Only authorized personnel can read that", messageService.getSecret() + .block()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret() + .block()); + } + +} 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 new file mode 100644 index 0000000000..1ee6fc7e87 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -0,0 +1,120 @@ +package com.baeldung; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.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; + +@SpringBootTest(webEnvironment = WebEnvironment.MOCK) +@AutoConfigureWebTestClient +class ReactiveResourceServerApplicationIntegrationTest { + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + api.get() + .uri("/greet") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Only authorized personnel can read that"); + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Only authorized personnel can read that"); + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); + } +} 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 new file mode 100644 index 0000000000..6f55f287d8 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -0,0 +1,142 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +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 reactor.core.publisher.Mono; + +@WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringAddonsGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() 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); + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth("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); + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /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(); + } + + @Test + @WithMockJwtAuth("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); + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java new file mode 100644 index 0000000000..e048481ce4 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -0,0 +1,149 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockAuthentication; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.ReactiveResourceServerApplication.GreetingController; +import com.baeldung.ReactiveResourceServerApplication.MessageService; + +import reactor.core.publisher.Mono; + +@WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringSecurityTestGreetingControllerUnitTest { + private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); + + @MockBean + MessageService messageService; + + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get() + .uri("/greet") + .exchange() + .expectStatus() + .isUnauthorized(); + } + + @Test + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(Mono.just(greeting)); + + api.mutateWith(mockJwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))) + .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 */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isUnauthorized(); + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isUnauthorized(); + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml new file mode 100644 index 0000000000..271cc7dc18 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + servlet-resource-server + servlet-resource-server + Demo project for Spring Boot servlet resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + 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 new file mode 100644 index 0000000000..a30c60eab0 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java @@ -0,0 +1,126 @@ +package com.baeldung; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.GrantedAuthority; +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.JwtAuthenticationToken; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; + +@SpringBootApplication +public class ServletResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ServletResourceServerApplication.class, args); + } + + @Configuration + @EnableMethodSecurity + @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()); + }); + + http.authorizeHttpRequests() + .requestMatchers("/secured-route") + .hasRole("AUTHORIZED_PERSONNEL") + .anyRequest() + .authenticated(); + + return http.build(); + } + + static interface AuthoritiesConverter extends Converter> { + } + + @Bean + AuthoritiesConverter realmRoles2AuthoritiesConverter() { + return (Jwt jwt) -> { + 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(); + }; + } + } + + @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()); + } + + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public String getSecret() { + return "Only authorized personnel can read that"; + } + } + + @RestController + @RequiredArgsConstructor + public static class GreetingController { + private final MessageService messageService; + + @GetMapping("/greet") + public ResponseEntity greet() { + return ResponseEntity.ok(messageService.greet()); + } + + @GetMapping("/secured-route") + public ResponseEntity securedRoute() { + return ResponseEntity.ok(messageService.getSecret()); + } + + @GetMapping("/secured-method") + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public ResponseEntity securedMethod() { + return ResponseEntity.ok(messageService.getSecret()); + } + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties new file mode 100644 index 0000000000..998f6303aa --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.security.oauth2.resourceserver.jwt.issuer-uri=https://localhost:8443/realms/master 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 new file mode 100644 index 0000000000..3c608d226e --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +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({ MessageService.class }) +@ExtendWith(SpringExtension.class) +@EnableMethodSecurity +class MessageServiceUnitTest { + @Autowired + MessageService messageService; + + /*----------------------------------------------------------------------------*/ + /* greet() */ + /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ + /*----------------------------------------------------------------------------*/ + + @Test + void givenSecurityContextIsNotSet_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { + assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.getSecret()); + } + + @Test + @WithAnonymousUser + void givenUserIsAnonymous_whenGreet_thenThrowsAccessDeniedException() { + 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()); + } + + @Test + @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") + void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet()); + } + + /*--------------------------------------------------------------------*/ + /* getSecret() */ + /* is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" */ + /*--------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsAnonymous_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + assertEquals("Only authorized personnel can read that", messageService.getSecret()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); + } + +} 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 new file mode 100644 index 0000000000..5bb539741f --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -0,0 +1,98 @@ +package com.baeldung; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +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.context.SpringBootTest; +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; + +@SpringBootTest(webEnvironment = WebEnvironment.MOCK) +@AutoConfigureMockMvc +class ServletResourceServerApplicationIntegrationTest { + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + api.perform(get("/greet")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + api.perform(get("/greet")) + .andExpect(status().isOk()) + .andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].")); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /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.perform(get("/secured-route")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + api.perform(get("/secured-route")) + .andExpect(status().isOk()) + .andExpect(content().string("Only authorized personnel can read that")); + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.perform(get("/secured-route")) + .andExpect(status().isForbidden()); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + api.perform(get("/secured-method")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + api.perform(get("/secured-method")) + .andExpect(status().isOk()) + .andExpect(content().string("Only authorized personnel can read that")); + } + + @Test + @WithMockJwtAuth("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 new file mode 100644 index 0000000000..9162768930 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -0,0 +1,116 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +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.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; + +@WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringAddonsGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + api.perform(get("/greet")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(greeting); + + api.perform(get("/greet")) + .andExpect(status().isOk()) + .andExpect(content().string(greeting)); + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /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.perform(get("/secured-route")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + api.perform(get("/secured-route")) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + } + + @Test + @WithMockJwtAuth({ "admin" }) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.perform(get("/secured-route")) + .andExpect(status().isForbidden()); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + api.perform(get("/secured-method")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + api.perform(get("/secured-method")) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + } + + @Test + @WithMockJwtAuth(authorities = { "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/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java new file mode 100644 index 0000000000..0e710bcc9f --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -0,0 +1,112 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; + +import org.junit.jupiter.api.Test; +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.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.ServletResourceServerApplication.GreetingController; +import com.baeldung.ServletResourceServerApplication.MessageService; + +@WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringSecurityTestGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + api.perform(get("/greet").with(anonymous())) + .andExpect(status().isUnauthorized()); + } + + @Test + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(greeting); + + api.perform(get("/greet").with(jwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy")))) + .andExpect(status().isOk()) + .andExpect(content().string(greeting)); + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { + api.perform(get("/secured-route").with(anonymous())) + .andExpect(status().isUnauthorized()); + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) + .andExpect(status().isForbidden()); + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + api.perform(get("/secured-method").with(anonymous())) + .andExpect(status().isUnauthorized()); + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) + .andExpect(status().isForbidden()); + } + +} diff --git a/spring-security-modules/spring-security-saml/src/main/resources/application.properties b/spring-security-modules/spring-security-saml/src/main/resources/application.properties index fd7798dda9..332278225c 100644 --- a/spring-security-modules/spring-security-saml/src/main/resources/application.properties +++ b/spring-security-modules/spring-security-saml/src/main/resources/application.properties @@ -1,9 +1,9 @@ -saml.keystore.location=classpath:/saml/saml-keystore +saml.keystore.location=classpath:/saml/saml-keystore.jks # Password for Java keystore and item therein -saml.keystore.password= -saml.keystore.alias= +saml.keystore.password=baeldungsamlokta +saml.keystore.alias=baeldungspringsaml # SAML Entity ID extracted from top of SAML metadata file -saml.idp= +saml.idp=http://www.okta.com/exk26fxqrz8LLk9dV4x7 saml.sp=http://localhost:8080/saml/metadata spring.main.allow-circular-references=true \ No newline at end of file diff --git a/spring-security-modules/spring-security-saml/src/main/resources/saml/saml-keystore.jks b/spring-security-modules/spring-security-saml/src/main/resources/saml/saml-keystore.jks new file mode 100644 index 0000000000..535c611180 Binary files /dev/null and b/spring-security-modules/spring-security-saml/src/main/resources/saml/saml-keystore.jks differ diff --git a/spring-security-modules/spring-security-saml/src/main/resources/saml/samlKeystore.jks b/spring-security-modules/spring-security-saml/src/main/resources/saml/samlKeystore.jks deleted file mode 100644 index 7f3a5850d9..0000000000 Binary files a/spring-security-modules/spring-security-saml/src/main/resources/saml/samlKeystore.jks and /dev/null differ diff --git a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/basicauth/config/BasicAuthConfiguration.java b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/basicauth/config/BasicAuthConfiguration.java index 504dbf63e3..5f4b82a191 100644 --- a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/basicauth/config/BasicAuthConfiguration.java +++ b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/basicauth/config/BasicAuthConfiguration.java @@ -1,5 +1,7 @@ package com.baeldung.springbootsecurityrest.basicauth.config; +import static org.springframework.security.config.Customizer.withDefaults; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -27,6 +29,7 @@ public class BasicAuthConfiguration { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf() .disable() + .cors(withDefaults()) .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**") .permitAll() diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/resources/application.properties b/spring-security-modules/spring-security-web-boot-1/src/main/resources/application.properties index 3cf12afeb9..cc1e92d43a 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/resources/application.properties +++ b/spring-security-modules/spring-security-web-boot-1/src/main/resources/application.properties @@ -1 +1,2 @@ server.port=8082 +server.servlet.register-default-servlet=true diff --git a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/ApplicationLiveTest.java b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/ApplicationLiveTest.java index 56f87e8aee..ea848468b4 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/ApplicationLiveTest.java +++ b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/ApplicationLiveTest.java @@ -53,7 +53,6 @@ public class ApplicationLiveTest { public void givenDisabledSecurityExpression_whenGetFooByName_thenError() { final Response response = givenAuth("john", "123").get("http://localhost:8082/foos?name=sample"); assertEquals(500, response.getStatusCode()); - assertTrue(response.asString().contains("method hasAuthority() not allowed")); } private RequestSpecification givenAuth(String username, String password) { diff --git a/spring-security-modules/spring-security-web-boot-4/README.md b/spring-security-modules/spring-security-web-boot-4/README.md index caec447846..26b19e7b33 100644 --- a/spring-security-modules/spring-security-web-boot-4/README.md +++ b/spring-security-modules/spring-security-web-boot-4/README.md @@ -9,3 +9,4 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com - [Spring Security: Upgrading the Deprecated WebSecurityConfigurerAdapter](https://www.baeldung.com/spring-deprecated-websecurityconfigureradapter) - More articles: [[<-- prev]](/spring-security-modules/spring-security-web-boot-3) +- [Spring @EnableMethodSecurity Annotation](https://www.baeldung.com/spring-enablemethodsecurity) diff --git a/spring-security-modules/spring-security-web-mvc-custom/README.md b/spring-security-modules/spring-security-web-mvc-custom/README.md index d7690257db..d8bd4cb3e0 100644 --- a/spring-security-modules/spring-security-web-mvc-custom/README.md +++ b/spring-security-modules/spring-security-web-mvc-custom/README.md @@ -9,7 +9,7 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com ### Relevant Articles: - [Spring Security Remember Me](https://www.baeldung.com/spring-security-remember-me) -- [Redirect to Different Pages after Login with Spring Security](https://www.baeldung.com/spring_redirect_after_login) +- [Redirect to Different Pages after Login with Spring Security](https://www.baeldung.com/spring-redirect-after-login) - [Changing Spring Model Parameters with Handler Interceptor](https://www.baeldung.com/spring-model-parameters-with-handler-interceptor) - [Introduction to Spring MVC HandlerInterceptor](https://www.baeldung.com/spring-mvc-handlerinterceptor) - [Using a Custom Spring MVC’s Handler Interceptor to Manage Sessions](https://www.baeldung.com/spring-mvc-custom-handler-interceptor) diff --git a/spring-security-modules/spring-security-web-mvc/README.md b/spring-security-modules/spring-security-web-mvc/README.md index 49831ea970..db17b237c8 100644 --- a/spring-security-modules/spring-security-web-mvc/README.md +++ b/spring-security-modules/spring-security-web-mvc/README.md @@ -8,7 +8,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: -- [HttpSessionListener Example – Monitoring](https://www.baeldung.com/httpsessionlistener_with_metrics) +- [HttpSessionListener Example – Monitoring](https://www.baeldung.com/java-httpsessionlistener-metrics) - [Control the Session with Spring Security](https://www.baeldung.com/spring-security-session) - [The Clear-Site-Data Header in Spring Security](https://www.baeldung.com/spring-security-clear-site-data-header) - [Spring Security – security none, filters none, access permitAll](https://www.baeldung.com/security-none-filters-none-access-permitAll) diff --git a/spring-security-modules/spring-security-web-springdoc/README.md b/spring-security-modules/spring-security-web-springdoc/README.md new file mode 100644 index 0000000000..2c24fe32b9 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/README.md @@ -0,0 +1,13 @@ +## Spring Security Web Springdoc + +This module contains articles about Springdoc with Spring Security + +### Relevant Articles: +- [Form Login and Basic Authentication in springdoc-openapi](https://www.baeldung.com/springdoc-openapi-form-login-and-basic-authentication) + +### Running This Project: + +To run the projects use the commands: +- `mvn spring-boot:run -Dstart-class=com.baeldung.basicauth.SpringBootSpringdocBasicAuth` +- `mvn spring-boot:run -Dstart-class=com.baeldung.formlogin.SpringBootSpringdocFormLogin` + diff --git a/spring-security-modules/spring-security-web-springdoc/pom.xml b/spring-security-modules/spring-security-web-springdoc/pom.xml new file mode 100644 index 0000000000..03e938f1c8 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + spring-security-web-springdoc + 0.1-SNAPSHOT + spring-security-web-springdoc + jar + Spring Security with Springdoc tutorial + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + org.springdoc + springdoc-openapi-security + ${springdoc.version} + + + com.google.guava + guava + ${guava.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + + + 1.6.13 + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/Foo.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/Foo.java new file mode 100644 index 0000000000..ab0f010e2c --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/Foo.java @@ -0,0 +1,60 @@ +package com.baeldung.basicauth; + +import java.io.Serializable; + +public class Foo implements Serializable { + + private static final long serialVersionUID = -5422285893276747592L; + + private long id; + private String name; + + 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) { + return other.name == null; + } else return name.equals(other.name); + } + + @Override + public String toString() { + return "Foo [name=" + name + "]"; + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/FooController.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/FooController.java new file mode 100644 index 0000000000..9ca2f9a6cc --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/FooController.java @@ -0,0 +1,39 @@ +package com.baeldung.basicauth; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.google.common.collect.Lists; + +@RestController +@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1")) +@SecurityRequirement(name = "basicAuth") +@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) +public class FooController { + + private static final int STRING_LENGTH = 6; + + @GetMapping(value = "/{id}") + public Foo findById(@PathVariable("id") final Long id) { + return new Foo(randomAlphabetic(STRING_LENGTH)); + } + + @GetMapping + public List findAll() { + return Lists.newArrayList(new Foo(randomAlphabetic(STRING_LENGTH)), new Foo(randomAlphabetic(STRING_LENGTH)), new Foo(randomAlphabetic(STRING_LENGTH))); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Foo create(@RequestBody final Foo foo) { + return foo; + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/SpringBootSpringdocBasicAuth.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/SpringBootSpringdocBasicAuth.java new file mode 100644 index 0000000000..0875c5d176 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/SpringBootSpringdocBasicAuth.java @@ -0,0 +1,13 @@ +package com.baeldung.basicauth; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootSpringdocBasicAuth { + + public static void main(String[] args) { + SpringApplication.run(SpringBootSpringdocBasicAuth.class, args); + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/PasswordEncoderConfiguration.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/PasswordEncoderConfiguration.java new file mode 100644 index 0000000000..4da6b5438b --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/PasswordEncoderConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.basicauth.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncoderConfiguration { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SecurityConfiguration.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SecurityConfiguration.java new file mode 100644 index 0000000000..a419162828 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SecurityConfiguration.java @@ -0,0 +1,38 @@ +package com.baeldung.basicauth.config; + +import org.springframework.beans.factory.annotation.Autowired; +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.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf().disable() + .authorizeRequests() + .antMatchers("/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html").permitAll() + .anyRequest().authenticated() + .and() + .httpBasic(); + return http.build(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth, PasswordEncoder passwordEncoder) throws Exception { + auth.inMemoryAuthentication() + .withUser("user") + .password(passwordEncoder.encode("password")) + .roles("USER"); + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SpringdocConfig.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SpringdocConfig.java new file mode 100644 index 0000000000..57d3d8bd02 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/basicauth/config/SpringdocConfig.java @@ -0,0 +1,12 @@ +package com.baeldung.basicauth.config; + +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import org.springframework.context.annotation.Configuration; + +@Configuration +@SecurityScheme( + type = SecuritySchemeType.HTTP, + name = "basicAuth", + scheme = "basic") +public class SpringdocConfig {} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/SpringBootSpringdocFormLogin.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/SpringBootSpringdocFormLogin.java new file mode 100644 index 0000000000..5c4c262fa7 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/SpringBootSpringdocFormLogin.java @@ -0,0 +1,13 @@ +package com.baeldung.formlogin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootSpringdocFormLogin { + + public static void main(String[] args) { + SpringApplication.run(SpringBootSpringdocFormLogin.class, args); + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/PasswordEncoderConfiguration.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/PasswordEncoderConfiguration.java new file mode 100644 index 0000000000..e3f9e71bd6 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/PasswordEncoderConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.formlogin.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncoderConfiguration { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/SecurityConfiguration.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/SecurityConfiguration.java new file mode 100644 index 0000000000..2b849031ce --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/config/SecurityConfiguration.java @@ -0,0 +1,40 @@ +package com.baeldung.formlogin.config; + +import org.springframework.beans.factory.annotation.Autowired; +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.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf().disable() + .authorizeRequests() + .antMatchers("/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .defaultSuccessUrl("/foos"); + return http.build(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth, PasswordEncoder passwordEncoder) throws Exception { + auth.inMemoryAuthentication() + .withUser("user") + .password(passwordEncoder.encode("password")) + .roles("USER"); + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/FooController.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/FooController.java new file mode 100644 index 0000000000..1d09789067 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/FooController.java @@ -0,0 +1,37 @@ +package com.baeldung.formlogin.controller; + +import com.baeldung.formlogin.model.Foo; +import com.google.common.collect.Lists; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +@RestController +@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE) +@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1")) +public class FooController { + + private static final int STRING_LENGTH = 6; + + @GetMapping(value = "/{id}") + public Foo findById(@PathVariable("id") final Long id) { + return new Foo(randomAlphabetic(STRING_LENGTH)); + } + + @GetMapping + public List findAll() { + return Lists.newArrayList(new Foo(randomAlphabetic(STRING_LENGTH)), new Foo(randomAlphabetic(STRING_LENGTH)), new Foo(randomAlphabetic(STRING_LENGTH))); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Foo create(@RequestBody final Foo foo) { + return foo; + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/LogoutController.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/LogoutController.java new file mode 100644 index 0000000000..ab1c635de0 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/controller/LogoutController.java @@ -0,0 +1,17 @@ +package com.baeldung.formlogin.controller; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.web.bind.annotation.*; + +@RestController +@OpenAPIDefinition(info = @Info(title = "logout-endpoint")) +public class LogoutController { + + @PostMapping("logout") + @Operation(description = "End authenticated user session") + public void logout() { + throw new UnsupportedOperationException(); + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/model/Foo.java b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/model/Foo.java new file mode 100644 index 0000000000..5133c215b3 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/java/com/baeldung/formlogin/model/Foo.java @@ -0,0 +1,62 @@ +package com.baeldung.formlogin.model; + +import java.io.Serializable; + +public class Foo implements Serializable { + + private static final long serialVersionUID = -5422285893276747592L; + + private long id; + private String name; + + public Foo(final String name) { + this.name = name; + } + + public Foo() { + } + + 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) { + return other.name == null; + } else return name.equals(other.name); + } + + @Override + public String toString() { + return "Foo [name=" + name + "]"; + } + +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/main/resources/application.properties b/spring-security-modules/spring-security-web-springdoc/src/main/resources/application.properties new file mode 100644 index 0000000000..7157c0f5b9 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/main/resources/application.properties @@ -0,0 +1 @@ +springdoc.show-login-endpoint=true diff --git a/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/basicauth/OpenAPIIntegrationTest.java b/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/basicauth/OpenAPIIntegrationTest.java new file mode 100644 index 0000000000..3e622059c1 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/basicauth/OpenAPIIntegrationTest.java @@ -0,0 +1,64 @@ +package com.baeldung.basicauth; + +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 org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class OpenAPIIntegrationTest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void whenInvokeSwagger_thenRenderIndexPage() { + String response = this.restTemplate.getForObject("http://localhost:" + port + "/swagger-ui/index.html", String.class); + + assertNotNull(response); + assertTrue(response.contains("Swagger UI")); + assertTrue(response.contains("
")); + } + + @Test + void whenInvokeOpenApi_thenCheckHeaders() { + ResponseEntity response = this.restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class); + + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getHeaders().get("Content-Type")); + assertEquals(1, response.getHeaders().get("Content-Type").size()); + assertEquals("application/json", response.getHeaders().get("Content-Type").get(0)); + } + + @Test + void whenInvokeOpenApi_thenVerifyOpenApiDoc() { + ResponseEntity response = this.restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class); + + assertNotNull(response); + assertNotNull(response.getBody()); + assertTrue(response.getBody().contains("\"openapi\":")); + assertTrue(response.getBody().contains("Foos API")); + assertTrue(response.getBody().contains("\"post\"")); + } + + @Test + void whenInvokeOpenApi_thenCheckSecurityConfig() { + ResponseEntity response = this.restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class); + + assertNotNull(response); + assertNotNull(response.getBody()); + assertTrue(response.getBody().contains("\"securitySchemes\"")); + assertTrue(response.getBody().contains("\"type\":\"http\"")); + assertTrue(response.getBody().contains("\"scheme\":\"basic\"")); + } +} diff --git a/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/formlogin/OpenAPIIntegrationTest.java b/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/formlogin/OpenAPIIntegrationTest.java new file mode 100644 index 0000000000..5d942f2126 --- /dev/null +++ b/spring-security-modules/spring-security-web-springdoc/src/test/java/com/baeldung/formlogin/OpenAPIIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.formlogin; + +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 org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class OpenAPIIntegrationTest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void whenInvokeSwagger_thenRenderIndexPage() { + String response = this.restTemplate.getForObject("http://localhost:" + port + "/swagger-ui/index.html", String.class); + + assertNotNull(response); + assertTrue(response.contains("Swagger UI")); + assertTrue(response.contains("
")); + } + + @Test + void whenInvokeOpenApi_thenCheckHeaders() { + ResponseEntity response = this.restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class); + + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getHeaders().get("Content-Type")); + assertEquals(1, response.getHeaders().get("Content-Type").size()); + assertEquals("application/json", response.getHeaders().get("Content-Type").get(0)); + } + + @Test + void whenInvokeOpenApi_thenVerifyOpenApiDoc() { + ResponseEntity response = this.restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class); + + assertNotNull(response); + assertNotNull(response.getBody()); + assertTrue(response.getBody().contains("\"openapi\":")); + assertTrue(response.getBody().contains("Foos API")); + assertTrue(response.getBody().contains("\"post\"")); + } +} diff --git a/spring-web-modules/pom.xml b/spring-web-modules/pom.xml index a676a86d80..a9970e85c0 100644 --- a/spring-web-modules/pom.xml +++ b/spring-web-modules/pom.xml @@ -16,12 +16,14 @@ spring-5-mvc + spring-freemarker spring-mvc-basics spring-mvc-basics-2 spring-mvc-basics-3 spring-mvc-basics-4 spring-mvc-basics-5 spring-mvc-crash + spring-mvc-file spring-mvc-forms-jsp spring-mvc-forms-thymeleaf spring-mvc-java diff --git a/spring-freemarker/.gitignore b/spring-web-modules/spring-freemarker/.gitignore similarity index 100% rename from spring-freemarker/.gitignore rename to spring-web-modules/spring-freemarker/.gitignore diff --git a/spring-freemarker/README.md b/spring-web-modules/spring-freemarker/README.md similarity index 100% rename from spring-freemarker/README.md rename to spring-web-modules/spring-freemarker/README.md diff --git a/spring-freemarker/pom.xml b/spring-web-modules/spring-freemarker/pom.xml similarity index 100% rename from spring-freemarker/pom.xml rename to spring-web-modules/spring-freemarker/pom.xml diff --git a/spring-freemarker/src/main/java/com/baeldung/freemarker/config/SpringWebConfig.java b/spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/config/SpringWebConfig.java similarity index 100% rename from spring-freemarker/src/main/java/com/baeldung/freemarker/config/SpringWebConfig.java rename to spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/config/SpringWebConfig.java diff --git a/spring-freemarker/src/main/java/com/baeldung/freemarker/config/WebConfiguration.java b/spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/config/WebConfiguration.java similarity index 100% rename from spring-freemarker/src/main/java/com/baeldung/freemarker/config/WebConfiguration.java rename to spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/config/WebConfiguration.java diff --git a/spring-freemarker/src/main/java/com/baeldung/freemarker/controller/SpringController.java b/spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/controller/SpringController.java similarity index 100% rename from spring-freemarker/src/main/java/com/baeldung/freemarker/controller/SpringController.java rename to spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/controller/SpringController.java diff --git a/spring-freemarker/src/main/java/com/baeldung/freemarker/method/LastCharMethod.java b/spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/method/LastCharMethod.java similarity index 100% rename from spring-freemarker/src/main/java/com/baeldung/freemarker/method/LastCharMethod.java rename to spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/method/LastCharMethod.java diff --git a/spring-freemarker/src/main/java/com/baeldung/freemarker/model/Car.java b/spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/model/Car.java similarity index 100% rename from spring-freemarker/src/main/java/com/baeldung/freemarker/model/Car.java rename to spring-web-modules/spring-freemarker/src/main/java/com/baeldung/freemarker/model/Car.java diff --git a/spring-web-modules/spring-freemarker/src/main/resources/logback.xml b/spring-web-modules/spring-freemarker/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-web-modules/spring-freemarker/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-freemarker/src/main/webapp/WEB-INF/views/ftl/commons.ftl b/spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/views/ftl/commons.ftl similarity index 100% rename from spring-freemarker/src/main/webapp/WEB-INF/views/ftl/commons.ftl rename to spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/views/ftl/commons.ftl diff --git a/spring-freemarker/src/main/webapp/WEB-INF/views/ftl/index.ftl b/spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/views/ftl/index.ftl similarity index 100% rename from spring-freemarker/src/main/webapp/WEB-INF/views/ftl/index.ftl rename to spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/views/ftl/index.ftl diff --git a/spring-freemarker/src/main/webapp/WEB-INF/web.xml b/spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from spring-freemarker/src/main/webapp/WEB-INF/web.xml rename to spring-web-modules/spring-freemarker/src/main/webapp/WEB-INF/web.xml diff --git a/spring-freemarker/src/test/java/com/baeldung/SpringContextTest.java b/spring-web-modules/spring-freemarker/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-freemarker/src/test/java/com/baeldung/SpringContextTest.java rename to spring-web-modules/spring-freemarker/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-web-modules/spring-mvc-basics-4/pom.xml b/spring-web-modules/spring-mvc-basics-4/pom.xml index 376e13ed72..455e4e488c 100644 --- a/spring-web-modules/spring-mvc-basics-4/pom.xml +++ b/spring-web-modules/spring-mvc-basics-4/pom.xml @@ -15,26 +15,26 @@
- - com.fasterxml.jackson.core - jackson-databind - - - org.springframework - spring-web - org.springframework.boot spring-boot-starter-validation - javax.servlet - javax.servlet-api - provided + org.springframework.boot + spring-boot-starter-web + 3.0.2 - org.springframework - spring-webmvc + org.apache.tomcat.embed + tomcat-embed-jasper + + + javax.servlet + jstl + + + org.springframework.boot + spring-boot-starter-thymeleaf diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/config/WebConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/config/WebConfig.java new file mode 100644 index 0000000000..e9b59a2b23 --- /dev/null +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/config/WebConfig.java @@ -0,0 +1,44 @@ +package com.baeldung.config; + +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.JstlView; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; +import org.thymeleaf.templateresolver.ITemplateResolver; + +import com.baeldung.contexts.Greeting; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Web Configuration for the entire app + */ +@Configuration +@EnableWebMvc +public class WebConfig { + + @Bean + public WebServerFactoryCustomizer enableDefaultServlet() { + return factory -> factory.setRegisterDefaultServlet(true); + } + + @Bean + public Greeting greeting() { + Greeting greeting = new Greeting(); + greeting.setMessage("Hello World !!"); + return greeting; + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper(); + } +} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationAndServletInitializer.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationAndServletInitializer.java deleted file mode 100644 index 1dffad637a..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationAndServletInitializer.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; - -public class AnnotationsBasedApplicationAndServletInitializer //extends AbstractDispatcherServletInitializer -{ - - //uncomment to run the multiple contexts example - //@Override - protected WebApplicationContext createRootApplicationContext() { - //If this is not the only class declaring a root context, we return null because it would clash - //with other classes, as there can only be a single root context. - - //AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); - //rootContext.register(RootApplicationConfig.class); - //return rootContext; - return null; - } - - //@Override - protected WebApplicationContext createServletApplicationContext() { - AnnotationConfigWebApplicationContext normalWebAppContext = new AnnotationConfigWebApplicationContext(); - normalWebAppContext.register(NormalWebAppConfig.class); - return normalWebAppContext; - } - - //@Override - protected String[] getServletMappings() { - return new String[] { "/api/*" }; - } - - //@Override - protected String getServletName() { - return "normal-dispatcher"; - } -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationInitializer.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationInitializer.java deleted file mode 100644 index ffa80d58bf..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/AnnotationsBasedApplicationInitializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; - -public class AnnotationsBasedApplicationInitializer //extends AbstractContextLoaderInitializer -{ - //uncomment to run the multiple contexts example - // @Override - protected WebApplicationContext createRootApplicationContext() { - AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); - rootContext.register(RootApplicationConfig.class); - return rootContext; - } - -} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/ApplicationInitializer.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/ApplicationInitializer.java deleted file mode 100644 index 15a2631cbb..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/ApplicationInitializer.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.contexts.config; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.web.WebApplicationInitializer; -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.context.support.XmlWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; - -public class ApplicationInitializer //implements WebApplicationInitializer -{ - //uncomment to run the multiple contexts example - //@Override - public void onStartup(ServletContext servletContext) throws ServletException { - //Here, we can define a root context and register servlets, among other things. - //However, since we've later defined other classes to do the same and they would clash, - //we leave this commented out. - - //Root XML Context - //XmlWebApplicationContext rootContext = new XmlWebApplicationContext(); - //rootContext.setConfigLocations("/WEB-INF/rootApplicationContext.xml"); - //Annotations Context - //AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); - //rootContext.register(RootApplicationConfig.class); - //Registration - //servletContext.addListener(new ContextLoaderListener(rootContext)); - - //Dispatcher Servlet - //XmlWebApplicationContext normalWebAppContext = new XmlWebApplicationContext(); - //normalWebAppContext.setConfigLocation("/WEB-INF/normal-webapp-servlet.xml"); - //ServletRegistration.Dynamic normal = servletContext.addServlet("normal-webapp", new DispatcherServlet(normalWebAppContext)); - //normal.setLoadOnStartup(1); - //normal.addMapping("/api/*"); - } - -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/NormalWebAppConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/NormalWebAppConfig.java deleted file mode 100644 index 3da3d3beb1..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/NormalWebAppConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.view.InternalResourceViewResolver; -import org.springframework.web.servlet.view.JstlView; - -@Configuration -@EnableWebMvc -@ComponentScan(basePackages = { "com.baeldung.contexts.normal" }) -public class NormalWebAppConfig implements WebMvcConfigurer { - - @Bean - public ViewResolver viewResolver() { - InternalResourceViewResolver resolver = new InternalResourceViewResolver(); - resolver.setPrefix("/WEB-INF/view/"); - resolver.setSuffix(".jsp"); - resolver.setViewClass(JstlView.class); - return resolver; - } -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/RootApplicationConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/RootApplicationConfig.java deleted file mode 100644 index 59821076d2..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/RootApplicationConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -import com.baeldung.contexts.Greeting; - -@Configuration -@ComponentScan(basePackages = { "com.baeldung.contexts.services" }) -public class RootApplicationConfig { - - @Bean - public Greeting greeting() { - Greeting greeting = new Greeting(); - greeting.setMessage("Hello World !!"); - return greeting; - } -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureAnnotationsBasedApplicationAndServletInitializer.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureAnnotationsBasedApplicationAndServletInitializer.java deleted file mode 100644 index 580e86d2b5..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureAnnotationsBasedApplicationAndServletInitializer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; - -public class SecureAnnotationsBasedApplicationAndServletInitializer// extends AbstractDispatcherServletInitializer -{ - - //uncomment to run the multiple contexts example - //@Override - protected WebApplicationContext createRootApplicationContext() { - return null; - } - - //@Override - protected WebApplicationContext createServletApplicationContext() { - AnnotationConfigWebApplicationContext secureWebAppContext = new AnnotationConfigWebApplicationContext(); - secureWebAppContext.register(SecureWebAppConfig.class); - return secureWebAppContext; - } - - //@Override - protected String[] getServletMappings() { - return new String[] { "/s/api/*" }; - } - - - //@Override - protected String getServletName() { - return "secure-dispatcher"; - } - -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureWebAppConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureWebAppConfig.java deleted file mode 100644 index acc1e3092b..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/config/SecureWebAppConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.contexts.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.view.InternalResourceViewResolver; -import org.springframework.web.servlet.view.JstlView; - -@Configuration -@EnableWebMvc -@ComponentScan(basePackages = { "com.baeldung.contexts.secure" }) -public class SecureWebAppConfig implements WebMvcConfigurer { - - @Bean - public ViewResolver viewResolver() { - InternalResourceViewResolver resolver = new InternalResourceViewResolver(); - resolver.setPrefix("/WEB-INF/secure/view/"); - resolver.setSuffix(".jsp"); - resolver.setViewClass(JstlView.class); - return resolver; - } -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/normal/HelloWorldController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/normal/HelloWorldController.java index 8b58c51eb3..46d1769349 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/normal/HelloWorldController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/normal/HelloWorldController.java @@ -3,9 +3,9 @@ package com.baeldung.contexts.normal; import java.util.Arrays; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.ContextLoader; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.ModelAndView; @@ -19,21 +19,22 @@ public class HelloWorldController { @Autowired private GreeterService greeterService; + + @Autowired + private ApplicationContext applicationContext; private void processContext() { - WebApplicationContext rootContext = ContextLoader.getCurrentWebApplicationContext(); - - System.out.println("root context : " + rootContext); - System.out.println("root context Beans: " + Arrays.asList(rootContext.getBeanDefinitionNames())); + System.out.println("root context : " + applicationContext); + System.out.println("root context Beans: " + Arrays.asList(applicationContext.getBeanDefinitionNames())); System.out.println("context : " + webApplicationContext); System.out.println("context Beans: " + Arrays.asList(webApplicationContext.getBeanDefinitionNames())); } - @RequestMapping(path = "/welcome") + @GetMapping(path = "/welcome") public ModelAndView helloWorld() { processContext(); String message = "
" + "

Normal " + greeterService.greet() + "

"; - return new ModelAndView("welcome", "message", message); + return new ModelAndView("/view/welcome", "message", message); } } diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/secure/HelloWorldSecureController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/secure/HelloWorldSecureController.java index 4ebf2d55e0..84d7808000 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/secure/HelloWorldSecureController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/contexts/secure/HelloWorldSecureController.java @@ -6,8 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.ContextLoader; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.ModelAndView; @@ -31,19 +30,15 @@ public class HelloWorldSecureController { ApplicationContext context = contextUtilService.getApplicationContext(); System.out.println("application context : " + context); System.out.println("application context Beans: " + Arrays.asList(context.getBeanDefinitionNames())); - - WebApplicationContext rootContext = ContextLoader.getCurrentWebApplicationContext(); - System.out.println("context : " + rootContext); - System.out.println("context Beans: " + Arrays.asList(rootContext.getBeanDefinitionNames())); System.out.println("context : " + webApplicationContext); System.out.println("context Beans: " + Arrays.asList(webApplicationContext.getBeanDefinitionNames())); } - @RequestMapping(path = "/welcome") + @GetMapping(path = "/welcome_secure") public ModelAndView helloWorld() { processContext(); String message = "
" + "

Secure " + greeterService.greet() + "

"; - return new ModelAndView("welcome", "message", message); + return new ModelAndView("/secure/view/welcome", "message", message); } } diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/StudentControllerConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/StudentControllerConfig.java deleted file mode 100644 index b84094132d..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/StudentControllerConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.controller.config; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; - -public class StudentControllerConfig //implements WebApplicationInitializer -{ - - //uncomment to run the student controller example - //@Override - public void onStartup(ServletContext sc) throws ServletException { - AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext(); - root.register(WebConfig.class); - root.setServletContext(sc); - sc.addListener(new ContextLoaderListener(root)); - - DispatcherServlet dv = new DispatcherServlet(root); - - ServletRegistration.Dynamic appServlet = sc.addServlet("test-mvc", dv); - appServlet.setLoadOnStartup(1); - appServlet.addMapping("/test/*"); - } -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/WebConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/WebConfig.java deleted file mode 100644 index 364f042ac7..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/config/WebConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.controller.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.view.InternalResourceViewResolver; - -@Configuration -@EnableWebMvc -@ComponentScan(basePackages = { "com.baeldung.controller", "com.baeldung.optionalpathvars" }) -public class WebConfig implements WebMvcConfigurer { - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); - } - - @Bean - public ViewResolver viewResolver() { - InternalResourceViewResolver bean = new InternalResourceViewResolver(); - bean.setPrefix("/WEB-INF/"); - bean.setSuffix(".jsp"); - return bean; - } -} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/GreetingsController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/GreetingsController.java index fbf78b8a0e..1568b94050 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/GreetingsController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/GreetingsController.java @@ -7,42 +7,26 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; -@Controller +@RestController public class GreetingsController { - @RequestMapping( - value = "/greetings-with-response-body", - method = RequestMethod.GET, - produces="application/json" - ) - @ResponseBody + @GetMapping(value = "/greetings-with-response-body", produces="application/json") public String getGreetingWhileReturnTypeIsString() { - return "{\"test\": \"Hello using @ResponseBody\"}"; + return "{\"test\": \"Hello\"}"; } - @RequestMapping( - value = "/greetings-with-response-entity", - method = RequestMethod.GET, - produces = "application/json" - ) + @GetMapping(value = "/greetings-with-response-entity", produces = "application/json") public ResponseEntity getGreetingWithResponseEntity() { final HttpHeaders httpHeaders= new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); - return new ResponseEntity("{\"test\": \"Hello with ResponseEntity\"}", httpHeaders, HttpStatus.OK); + return new ResponseEntity<>("{\"test\": \"Hello with ResponseEntity\"}", httpHeaders, HttpStatus.OK); } - @RequestMapping( - value = "/greetings-with-map-return-type", - method = RequestMethod.GET, - produces = "application/json" - ) - @ResponseBody + @GetMapping(value = "/greetings-with-map-return-type", produces = "application/json") public Map getGreetingWhileReturnTypeIsMap() { - HashMap map = new HashMap(); + HashMap map = new HashMap<>(); map.put("test", "Hello from map"); return map; } diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/PassParametersController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/PassParametersController.java index d8330333cb..46b7003f3e 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/PassParametersController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/PassParametersController.java @@ -18,19 +18,19 @@ public class PassParametersController { @GetMapping("/showViewPage") public String passParametersWithModel(Model model) { model.addAttribute("message", "Baeldung"); - return "viewPage"; + return "view/viewPage"; } @GetMapping("/printViewPage") public String passParametersWithModelMap(ModelMap map) { map.addAttribute("welcomeMessage", "welcome"); map.addAttribute("message", "Baeldung"); - return "viewPage"; + return "view/viewPage"; } @GetMapping("/goToViewPage") public ModelAndView passParametersWithModelAndView() { - ModelAndView modelAndView = new ModelAndView("viewPage"); + ModelAndView modelAndView = new ModelAndView("view/viewPage"); modelAndView.addObject("message", "Baeldung"); return modelAndView; } diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/RestController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/RestController.java index a529faeed3..eead000621 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/RestController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/controller/RestController.java @@ -1,17 +1,15 @@ package com.baeldung.controller.controller; -import com.baeldung.controller.student.Student; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.ResponseBody; -@Controller +import com.baeldung.controller.student.Student; + +@org.springframework.web.bind.annotation.RestController public class RestController { @GetMapping(value = "/student/{studentId}") - public @ResponseBody - Student getTestData(@PathVariable Integer studentId) { + public Student getTestData(@PathVariable Integer studentId) { Student student = new Student(); student.setName("Peter"); student.setId(studentId); diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/student/Student.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/student/Student.java index 8a82dd5553..5c2b991312 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/student/Student.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/controller/student/Student.java @@ -27,7 +27,14 @@ public class Student { } @Override - public boolean equals(Object obj) { - return this.name.equals(((Student) obj).getName()); + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Student)) { + return false; + } + Student student = (Student) o; + return getName().equals(student.getName()); } } \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsConfig.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsConfig.java deleted file mode 100644 index f2049554ab..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.jsonparams.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.view.InternalResourceViewResolver; - -import com.fasterxml.jackson.databind.ObjectMapper; - -@Configuration -@EnableWebMvc -@ComponentScan(basePackages = { "com.baeldung.jsonparams" }) -public class JsonParamsConfig implements WebMvcConfigurer { - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); - } - - @Bean - public ViewResolver viewResolver() { - InternalResourceViewResolver bean = new InternalResourceViewResolver(); - bean.setPrefix("/WEB-INF/"); - bean.setSuffix(".jsp"); - return bean; - } - - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } - -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsInit.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsInit.java deleted file mode 100644 index 6db2a92350..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/config/JsonParamsInit.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jsonparams.config; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; - -public class JsonParamsInit // implements WebApplicationInitializer -{ - - //uncomment to run the product controller example - //@Override - public void onStartup(ServletContext sc) throws ServletException { - AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext(); - root.register(JsonParamsConfig.class); - root.setServletContext(sc); - sc.addListener(new ContextLoaderListener(root)); - - DispatcherServlet dv = new DispatcherServlet(root); - - ServletRegistration.Dynamic appServlet = sc.addServlet("jsonparams-mvc", dv); - appServlet.setLoadOnStartup(1); - appServlet.addMapping("/"); - } - -} diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/controller/ProductController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/controller/ProductController.java index e4e2ce085d..915731581e 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/controller/ProductController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/controller/ProductController.java @@ -1,7 +1,6 @@ package com.baeldung.jsonparams.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.InitBinder; @@ -9,7 +8,7 @@ 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.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import com.baeldung.jsonparams.model.Product; import com.baeldung.jsonparams.propertyeditor.ProductEditor; @@ -17,7 +16,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; -@Controller +@RestController @RequestMapping("/products") public class ProductController { @@ -34,21 +33,18 @@ public class ProductController { } @PostMapping("/create") - @ResponseBody public Product createProduct(@RequestBody Product product) { // custom logic return product; } @GetMapping("/get") - @ResponseBody - public Product getProduct(@RequestParam String product) throws JsonMappingException, JsonProcessingException { + public Product getProduct(@RequestParam String product) throws JsonProcessingException { final Product prod = objectMapper.readValue(product, Product.class); return prod; } @GetMapping("/get2") - @ResponseBody public Product get2Product(@RequestParam Product product) { // custom logic return product; diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/propertyeditor/ProductEditor.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/propertyeditor/ProductEditor.java index 11766118cd..41d97bed84 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/propertyeditor/ProductEditor.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/jsonparams/propertyeditor/ProductEditor.java @@ -18,7 +18,7 @@ public class ProductEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { - if (StringUtils.isEmpty(text)) { + if (!StringUtils.hasText(text)) { setValue(null); } else { Product prod = new Product(); diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerController.java deleted file mode 100644 index 1876798bd6..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerController.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.optionalpathvars; - -import static com.baeldung.optionalpathvars.Article.DEFAULT_ARTICLE; - -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class ArticleViewerController { - - @RequestMapping(value = {"/article", "/article/{id}"}) - public Article getArticle(@PathVariable(name = "id") Integer articleId) { - - if (articleId != null) { - return new Article(articleId); - } else { - return DEFAULT_ARTICLE; - } - - } - -} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerWithRequiredAttributeController.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerWithRequiredAttributeController.java index 7548747f05..786a56c130 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerWithRequiredAttributeController.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/optionalpathvars/ArticleViewerWithRequiredAttributeController.java @@ -4,7 +4,7 @@ import static com.baeldung.optionalpathvars.Article.DEFAULT_ARTICLE; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController;; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/requiredAttribute") diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/validation/listvalidation/SpringListValidationApplication.java b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/validation/listvalidation/SpringListValidationApplication.java index f16d5f877f..3d518c467c 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/validation/listvalidation/SpringListValidationApplication.java +++ b/spring-web-modules/spring-mvc-basics-4/src/main/java/com/baeldung/validation/listvalidation/SpringListValidationApplication.java @@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -@ComponentScan(basePackages = "com.baeldung.validation.listvalidation") +@ComponentScan(basePackages = "com.baeldung") @Configuration @SpringBootApplication public class SpringListValidationApplication { diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/secure/view/welcome.html b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/secure/view/welcome.html new file mode 100644 index 0000000000..fac7234f15 --- /dev/null +++ b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/secure/view/welcome.html @@ -0,0 +1,11 @@ + + + + Spring Web Contexts + + +
+
Secure Web Application : +
+ + \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/viewPage.html b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/viewPage.html similarity index 58% rename from spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/viewPage.html rename to spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/viewPage.html index 71f766407e..b520d0dd51 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/viewPage.html +++ b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/viewPage.html @@ -4,6 +4,6 @@ Title -
Web Application. Passed parameter : th:text="${message}"
+
Web Application. Passed parameter :
diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/welcome.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/welcome.html similarity index 57% rename from spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/welcome.jsp rename to spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/welcome.html index 4eda3c58e2..291f3b8919 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/welcome.jsp +++ b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/view/welcome.html @@ -1,11 +1,12 @@ - + + Spring Web Contexts
- Normal Web Application : ${message} + Normal Web Application :
\ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/welcome.html b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/welcome.html new file mode 100644 index 0000000000..c5b88e135e --- /dev/null +++ b/spring-web-modules/spring-mvc-basics-4/src/main/resources/templates/welcome.html @@ -0,0 +1,10 @@ + + + + + Insert title here + + +Data returned is + + \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/resources/test-mvc.xml b/spring-web-modules/spring-mvc-basics-4/src/main/resources/test-mvc.xml deleted file mode 100644 index 44c300dfc6..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/resources/test-mvc.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - /WEB-INF/ - - - .jsp - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/greeting.xml b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/greeting.xml deleted file mode 100644 index 1ad5484d80..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/greeting.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/index.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/index.jsp deleted file mode 100644 index c38169bb95..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/index.jsp +++ /dev/null @@ -1,5 +0,0 @@ - - -

Hello World!

- - diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/normal-webapp-servlet.xml b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/normal-webapp-servlet.xml deleted file mode 100644 index 8addbe3cf3..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/normal-webapp-servlet.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/rootApplicationContext.xml b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/rootApplicationContext.xml deleted file mode 100644 index 12e5d8f161..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/rootApplicationContext.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure-webapp-servlet.xml b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure-webapp-servlet.xml deleted file mode 100644 index 86797ad081..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure-webapp-servlet.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure/view/welcome.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure/view/welcome.jsp deleted file mode 100644 index 49ca0f8e87..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/secure/view/welcome.jsp +++ /dev/null @@ -1,11 +0,0 @@ - - - Spring Web Contexts - - -
-
- Secure Web Application : ${message} -
- - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/sample.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/sample.jsp deleted file mode 100644 index 4c64bf97f2..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/sample.jsp +++ /dev/null @@ -1,7 +0,0 @@ - - - - -

This is the body of the sample view

- - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/scopesExample.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/scopesExample.jsp deleted file mode 100644 index e9abcf194c..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/view/scopesExample.jsp +++ /dev/null @@ -1,10 +0,0 @@ - - - - -

Bean Scopes Examples

-
Previous Message: ${previousMessage } -
Current Message: ${currentMessage } -
- - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/web-old.xml b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/web-old.xml deleted file mode 100644 index 1344362d19..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/web-old.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - normal-webapp-annotations - - org.springframework.web.servlet.DispatcherServlet - - - contextClass - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - contextConfigLocation - com.baeldung.contexts.config.NormalWebAppConfig - - 1 - - - normal-webapp-annotations - /api-ann/* - - - - /WEB-INF/index.jsp - - diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/welcome.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/welcome.jsp deleted file mode 100644 index c34223b411..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/WEB-INF/welcome.jsp +++ /dev/null @@ -1,12 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" - pageEncoding="UTF-8" %> - - - - - Insert title here - - -Data returned is ${data} - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/index.jsp b/spring-web-modules/spring-mvc-basics-4/src/main/webapp/index.jsp deleted file mode 100644 index c38169bb95..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/main/webapp/index.jsp +++ /dev/null @@ -1,5 +0,0 @@ - - -

Hello World!

- - diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerAnnotationIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerAnnotationIntegrationTest.java index f378357548..7fd8f0c97f 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerAnnotationIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerAnnotationIntegrationTest.java @@ -1,26 +1,24 @@ package com.baeldung.controller; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.baeldung.controller.config.WebConfig; -import com.baeldung.controller.student.Student; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.AnnotationConfigWebContextLoader; -import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.ModelAndView; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }, loader = AnnotationConfigWebContextLoader.class) +import com.baeldung.controller.student.Student; +import com.baeldung.validation.listvalidation.SpringListValidationApplication; +import com.fasterxml.jackson.databind.ObjectMapper; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class ControllerAnnotationIntegrationTest { private MockMvc mockMvc; diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerIntegrationTest.java index 7e5cf1532e..a7e6bd6c4b 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/ControllerIntegrationTest.java @@ -5,9 +5,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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.setup.MockMvcBuilders; @@ -15,11 +14,11 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.ModelAndView; import com.baeldung.controller.student.Student; +import com.baeldung.validation.listvalidation.SpringListValidationApplication; import com.fasterxml.jackson.databind.ObjectMapper; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration({ "classpath:test-mvc.xml" }) +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class ControllerIntegrationTest { private MockMvc mockMvc; diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/GreetingsControllerUnitTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/GreetingsControllerUnitTest.java index ee9a8da8d4..4917d68ef4 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/GreetingsControllerUnitTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/GreetingsControllerUnitTest.java @@ -1,24 +1,21 @@ package com.baeldung.controller; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.baeldung.controller.controller.GreetingsController; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.AnnotationConfigWebContextLoader; -import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { GreetingsController.class }, loader = AnnotationConfigWebContextLoader.class) +import com.baeldung.validation.listvalidation.SpringListValidationApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class GreetingsControllerUnitTest { private MockMvc mockMvc; diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/PassParametersControllerIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/PassParametersControllerIntegrationTest.java index aa8148c1ef..7408ae825d 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/PassParametersControllerIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/controller/PassParametersControllerIntegrationTest.java @@ -5,24 +5,24 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.ModelAndView; +import com.baeldung.validation.listvalidation.SpringListValidationApplication; + /** * This is the test class for {@link com.baeldung.controller.controller.PassParametersController} class. * 09/09/2017 * * @author Ahmet Cetin */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration({"classpath:test-mvc.xml"}) +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class PassParametersControllerIntegrationTest { private MockMvc mockMvc; @@ -39,7 +39,7 @@ public class PassParametersControllerIntegrationTest { ModelAndView mv = this.mockMvc.perform(MockMvcRequestBuilders.get("/showViewPage")).andReturn().getModelAndView(); //Validate view - Assert.assertEquals(mv.getViewName(), "viewPage"); + Assert.assertEquals(mv.getViewName(), "view/viewPage"); //Validate attribute Assert.assertEquals(mv.getModelMap().get("message").toString(), "Baeldung"); @@ -50,7 +50,7 @@ public class PassParametersControllerIntegrationTest { ModelAndView mv = this.mockMvc.perform(MockMvcRequestBuilders.get("/printViewPage")).andReturn().getModelAndView(); //Validate view - Assert.assertEquals(mv.getViewName(), "viewPage"); + Assert.assertEquals(mv.getViewName(), "view/viewPage"); //Validate attribute Assert.assertEquals(mv.getModelMap().get("message").toString(), "Baeldung"); @@ -61,7 +61,7 @@ public class PassParametersControllerIntegrationTest { ModelAndView mv = this.mockMvc.perform(MockMvcRequestBuilders.get("/goToViewPage")).andReturn().getModelAndView(); //Validate view - Assert.assertEquals(mv.getViewName(), "viewPage"); + Assert.assertEquals(mv.getViewName(), "view/viewPage"); //Validate attribute Assert.assertEquals(mv.getModelMap().get("message").toString(), "Baeldung"); diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/jsonparams/JsonParamsIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/jsonparams/JsonParamsIntegrationTest.java index bceadc4896..9d414ed4ca 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/jsonparams/JsonParamsIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/jsonparams/JsonParamsIntegrationTest.java @@ -1,26 +1,25 @@ package com.baeldung.jsonparams; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.AnnotationConfigWebContextLoader; -import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import com.baeldung.validation.listvalidation.SpringListValidationApplication; -import com.baeldung.jsonparams.config.JsonParamsConfig; - -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { JsonParamsConfig.class }, loader = AnnotationConfigWebContextLoader.class) +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class JsonParamsIntegrationTest { private MockMvc mockMvc; diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerIntegrationTest.java deleted file mode 100644 index 0e2313c2ac..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerIntegrationTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.optionalpathvars; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -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.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; -import com.baeldung.controller.config.WebConfig; - -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }) -public class ArticleViewerControllerIntegrationTest { - - @Autowired - private WebApplicationContext wac; - - private MockMvc mockMvc; - - @Before - public void setup() throws Exception { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } - - @Test - public void whenIdPathVariableIsPassed_thenResponseOK() throws Exception { - - int articleId = 5; - - this.mockMvc - .perform(MockMvcRequestBuilders.get("/article/{id}", articleId)) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId)); - - } - - @Test - public void whenIdPathVariableIsNotPassed_thenResponse500() throws Exception { - - this.mockMvc - .perform(MockMvcRequestBuilders.get("/article")) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()); - - } - - -} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java index 094995ba67..2685946b4c 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java @@ -4,19 +4,18 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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 org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.controller.config.WebConfig; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }) +import com.baeldung.validation.listvalidation.SpringListValidationApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class ArticleViewerControllerWithOptionalParamIntegrationTest { @Autowired diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java index a4b12c7163..e7d864d9be 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java @@ -12,42 +12,38 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.controller.config.WebConfig; +import com.baeldung.validation.listvalidation.SpringListValidationApplication; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }) +@ContextConfiguration(classes = { SpringListValidationApplication.class }) public class ArticleViewerControllerWithRequiredAttributeIntegrationTest { @Autowired private WebApplicationContext wac; - + private MockMvc mockMvc; @Before - public void setup() throws Exception { + public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test - public void givenRequiredAttributeIsFalse_whenIdPathVariableIsPassed_thenResponseOK() throws Exception { - - int articleId = 154; + public void whenIdPathVariableIsPassed_thenResponseOK() throws Exception { + int articleId = 5; this.mockMvc .perform(MockMvcRequestBuilders.get("/requiredAttribute/article/{id}", articleId)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId)); - } - + @Test - public void givenRequiredAttributeIsFalse_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception { - + public void whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception { this.mockMvc .perform(MockMvcRequestBuilders.get("/requiredAttribute/article")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId())); - + .andExpect(MockMvcResultMatchers.status().isOk()); + } } \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java index 044a1c8bce..2be6d1e679 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java @@ -4,19 +4,18 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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 org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.controller.config.WebConfig; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }) +import com.baeldung.validation.listvalidation.SpringListValidationApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class ArticleViewerWithMapParamIntegrationTest { @Autowired diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java index 1ca926277d..e70ac5e5a6 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java @@ -4,19 +4,18 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; 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.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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 org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.controller.config.WebConfig; -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = { WebConfig.class }) +import com.baeldung.validation.listvalidation.SpringListValidationApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringListValidationApplication.class) public class ArticleViewerWithTwoSeparateMethodsIntegrationTest { @Autowired diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/validation/listvalidation/MovieControllerIntegrationTest.java b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/validation/listvalidation/MovieControllerIntegrationTest.java index cddc6c6bd9..14ceb651d7 100644 --- a/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/validation/listvalidation/MovieControllerIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-4/src/test/java/com/baeldung/validation/listvalidation/MovieControllerIntegrationTest.java @@ -34,7 +34,7 @@ public class MovieControllerIntegrationTest { Movie movie = new Movie("Movie3"); movies.add(movie); mvc.perform(MockMvcRequestBuilders.post("/movies") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(movies))) .andExpect(MockMvcResultMatchers.status() .isOk()); @@ -44,7 +44,7 @@ public class MovieControllerIntegrationTest { public void givenEmptyMovieList_whenAddingMovieList_thenThrowBadRequest() throws Exception { List movies = new ArrayList<>(); mvc.perform(MockMvcRequestBuilders.post("/movies") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(movies))) .andExpect(MockMvcResultMatchers.status() .isBadRequest()); @@ -54,7 +54,7 @@ public class MovieControllerIntegrationTest { public void givenEmptyMovieName_whenAddingMovieList_thenThrowBadRequest() throws Exception { Movie movie = new Movie(""); mvc.perform(MockMvcRequestBuilders.post("/movies") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(Arrays.asList(movie)))) .andExpect(MockMvcResultMatchers.status() .isBadRequest()); @@ -74,7 +74,7 @@ public class MovieControllerIntegrationTest { movies.add(movie4); movies.add(movie5); mvc.perform(MockMvcRequestBuilders.post("/movies") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(movies))) .andExpect(MockMvcResultMatchers.status() .isBadRequest()); diff --git a/spring-web-modules/spring-mvc-basics-4/src/test/resources/test-mvc.xml b/spring-web-modules/spring-mvc-basics-4/src/test/resources/test-mvc.xml deleted file mode 100644 index f1aa8e9504..0000000000 --- a/spring-web-modules/spring-mvc-basics-4/src/test/resources/test-mvc.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - /WEB-INF/ - - - .jsp - - - \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-file/.gitignore b/spring-web-modules/spring-mvc-file/.gitignore new file mode 100644 index 0000000000..da9ec604ff --- /dev/null +++ b/spring-web-modules/spring-mvc-file/.gitignore @@ -0,0 +1,9 @@ +*.class + +#folders# +/target + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-file/README.md b/spring-web-modules/spring-mvc-file/README.md new file mode 100644 index 0000000000..c4843031ff --- /dev/null +++ b/spring-web-modules/spring-mvc-file/README.md @@ -0,0 +1,9 @@ +## Spring MVC File + + + +### The Course + + +### Relevant Articles: +- [Convert byte[] to MultipartFile in Java](https://www.baeldung.com/java-convert-byte-array-to-multipartfile) diff --git a/spring-web-modules/spring-mvc-file/pom.xml b/spring-web-modules/spring-mvc-file/pom.xml new file mode 100644 index 0000000000..c6b063c785 --- /dev/null +++ b/spring-web-modules/spring-mvc-file/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + spring-mvc-file + 0.1-SNAPSHOT + spring-mvc-file + jar + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + commons-io + commons-io + ${commons-io.version} + + + + + + spring-mvc-file + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.Application + JAR + + + + + + \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-file/src/main/java/com/baeldung/Application.java b/spring-web-modules/spring-mvc-file/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..d58049fb35 --- /dev/null +++ b/spring-web-modules/spring-mvc-file/src/main/java/com/baeldung/Application.java @@ -0,0 +1,11 @@ +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-web-modules/spring-mvc-file/src/main/java/com/baeldung/file/CustomMultipartFile.java b/spring-web-modules/spring-mvc-file/src/main/java/com/baeldung/file/CustomMultipartFile.java new file mode 100644 index 0000000000..c68729588f --- /dev/null +++ b/spring-web-modules/spring-mvc-file/src/main/java/com/baeldung/file/CustomMultipartFile.java @@ -0,0 +1,60 @@ +package com.baeldung.file; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.springframework.web.multipart.MultipartFile; + +public class CustomMultipartFile implements MultipartFile { + private byte[] input; + + public CustomMultipartFile(byte[] input) { + this.input = input; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getOriginalFilename() { + return null; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public boolean isEmpty() { + return input == null || input.length == 0; + } + + @Override + public long getSize() { + return input.length; + } + + @Override + public byte[] getBytes() throws IOException { + return input; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(input); + } + + @Override + public void transferTo(File destination) throws IOException, IllegalStateException { + try(FileOutputStream fos = new FileOutputStream(destination)) { + fos.write(input); + } + } + +} diff --git a/spring-web-modules/spring-mvc-file/src/test/java/com/baeldung/file/CustomMultipartFileUnitTest.java b/spring-web-modules/spring-mvc-file/src/test/java/com/baeldung/file/CustomMultipartFileUnitTest.java new file mode 100644 index 0000000000..1aa07766ca --- /dev/null +++ b/spring-web-modules/spring-mvc-file/src/test/java/com/baeldung/file/CustomMultipartFileUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.file; + +import java.io.IOException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockMultipartFile; + +class CustomMultipartFileUnitTest { + + @Test + void whenProvidingByteArray_thenMultipartFileCreated() throws IOException { + byte[] inputArray = "Test String".getBytes(); + CustomMultipartFile customMultipartFile = new CustomMultipartFile(inputArray); + Assertions.assertFalse(customMultipartFile.isEmpty()); + Assertions.assertArrayEquals(inputArray, customMultipartFile.getBytes()); + Assertions.assertEquals(inputArray.length, customMultipartFile.getSize()); + } + + @Test + void whenProvidingEmptyByteArray_thenMockMultipartFileIsEmpty() throws IOException { + byte[] inputArray = "".getBytes(); + MockMultipartFile mockMultipartFile = new MockMultipartFile("tempFileName", inputArray); + Assertions.assertTrue(mockMultipartFile.isEmpty()); + } + + @Test + void whenProvidingNullByteArray_thenMockMultipartFileIsEmpty() throws IOException { + byte[] inputArray = null; + MockMultipartFile mockMultipartFile = new MockMultipartFile("tempFileName", inputArray); + Assertions.assertTrue(mockMultipartFile.isEmpty()); + } + + @Test + void whenProvidingByteArray_thenMultipartFileInputSizeMatches() throws IOException { + byte[] inputArray = "Testing String".getBytes(); + CustomMultipartFile customMultipartFile = new CustomMultipartFile(inputArray); + Assertions.assertEquals(inputArray.length, customMultipartFile.getSize()); + } + + @Test + void whenProvidingByteArray_thenMockMultipartFileCreated() throws IOException { + byte[] inputArray = "Test String".getBytes(); + MockMultipartFile mockMultipartFile = new MockMultipartFile("tempFileName", inputArray); + Assertions.assertFalse(mockMultipartFile.isEmpty()); + Assertions.assertArrayEquals(inputArray, mockMultipartFile.getBytes()); + Assertions.assertEquals(inputArray.length, mockMultipartFile.getSize()); + } +} diff --git a/spring-web-modules/spring-resttemplate-3/README.md b/spring-web-modules/spring-resttemplate-3/README.md index 6a00d226db..1944221138 100644 --- a/spring-web-modules/spring-resttemplate-3/README.md +++ b/spring-web-modules/spring-resttemplate-3/README.md @@ -8,4 +8,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Uploading MultipartFile with Spring RestTemplate](https://www.baeldung.com/spring-rest-template-multipart-upload) - [Get and Post Lists of Objects with RestTemplate](https://www.baeldung.com/spring-rest-template-list) -- [Download a Large File Through a Spring RestTemplate](https://www.baeldung.com/spring-resttemplate-download-large-file) \ No newline at end of file +- [Download a Large File Through a Spring RestTemplate](https://www.baeldung.com/spring-resttemplate-download-large-file) +- [Access HTTPS REST Service Using Spring RestTemplate](https://www.baeldung.com/spring-resttemplate-secure-https-service) +- [Encoding of URI Variables on RestTemplate](https://www.baeldung.com/spring-resttemplate-uri-variables-encode) +- [Difference Between exchange(), postForEntity() and execute() in RestTemplate](https://www.baeldung.com/spring-resttemplate-exchange-postforentity-execute) diff --git a/spring-web-modules/spring-resttemplate-3/pom.xml b/spring-web-modules/spring-resttemplate-3/pom.xml index b036a5ffcb..5ce7d348a2 100644 --- a/spring-web-modules/spring-resttemplate-3/pom.xml +++ b/spring-web-modules/spring-resttemplate-3/pom.xml @@ -26,4 +26,4 @@ - \ No newline at end of file + diff --git a/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/Application.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/Application.java new file mode 100644 index 0000000000..c6160a83d9 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.encoding; + +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-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/UriEncodingInterceptor.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/UriEncodingInterceptor.java new file mode 100644 index 0000000000..0a4bf4dc42 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/UriEncodingInterceptor.java @@ -0,0 +1,29 @@ +package com.baeldung.encoding; + + +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.IOException; +import java.net.URI; + +public class UriEncodingInterceptor implements ClientHttpRequestInterceptor { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + HttpRequest encodedRequest = new HttpRequestWrapper(request) { + @Override + public URI getURI() { + URI uri = super.getURI(); + String escapedQuery = uri.getRawQuery().replace("+", "%2B"); + return UriComponentsBuilder.fromUri(uri) + .replaceQuery(escapedQuery) + .build(true).toUri(); + } + }; + return execution.execute(encodedRequest, body); + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateConfig.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateConfig.java new file mode 100644 index 0000000000..a820a3d4cb --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateConfig.java @@ -0,0 +1,19 @@ +package com.baeldung.encoding.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@Configuration +public class RestTemplateConfig { + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory(); + defaultUriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY); + restTemplate.setUriTemplateHandler(defaultUriBuilderFactory); + return restTemplate; + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateWithInterceptorsConfig.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateWithInterceptorsConfig.java new file mode 100644 index 0000000000..87c50f2e17 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/config/RestTemplateWithInterceptorsConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.encoding.config; + +import com.baeldung.encoding.UriEncodingInterceptor; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +@Configuration +public class RestTemplateWithInterceptorsConfig { + @Qualifier("restTemplateWithInterceptors") + @Bean + public RestTemplate restTemplateWithInterceptors() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setInterceptors(Collections.singletonList(new UriEncodingInterceptor())); + return restTemplate; + } +} diff --git a/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/service/HttpBinService.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/service/HttpBinService.java new file mode 100644 index 0000000000..53cbb5e1a8 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/encoding/service/HttpBinService.java @@ -0,0 +1,27 @@ +package com.baeldung.encoding.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class HttpBinService { + private final RestTemplate restTemplate; + + public HttpBinService(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public String get(String parameter) throws JsonProcessingException { + String url = "http://httpbin.org/get?parameter={parameter}"; + ResponseEntity response = restTemplate.getForEntity(url, String.class, parameter); + Map mapping = new ObjectMapper().readValue(response.getBody(), HashMap.class); + Map args = (Map) mapping.get("args"); + return args.get("parameter"); + } +} diff --git a/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/resttemplate/methods/RestTemplateMethodsApplication.java b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/resttemplate/methods/RestTemplateMethodsApplication.java new file mode 100644 index 0000000000..72201aa5c9 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/main/java/com/baeldung/resttemplate/methods/RestTemplateMethodsApplication.java @@ -0,0 +1,102 @@ +package com.baeldung.resttemplate.methods; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.RequestCallback; +import org.springframework.web.client.ResponseExtractor; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; + +/** + * Examples of making the same call with RestTemplate + * using postForEntity(), exchange(), and execute(). + */ +@SpringBootApplication +public class RestTemplateMethodsApplication { + private final static RestTemplate restTemplate = new RestTemplate(); + + public static void main(String[] args) { + + } + + private static void postForEntity() { + Book book = new Book( + "Cruising Along with Java", + "Venkat Subramaniam", + 2023); + + ResponseEntity response = restTemplate.postForEntity( + "https://api.bookstore.com", + book, + Book.class); + } + + private static void exchange() { + Book book = new Book( + "Effective Java", + "Joshua Bloch", + 2001); + + HttpHeaders headers = new HttpHeaders(); + headers.setBasicAuth("username", "password"); + + ResponseEntity response = restTemplate.exchange( + "https://api.bookstore.com", + HttpMethod.POST, + new HttpEntity<>(book, headers), + Book.class); + } + + private static void execute() { + ResponseEntity response = restTemplate.execute( + "https://api.bookstore.com", + HttpMethod.POST, + new RequestCallback() { + @Override + public void doWithRequest(ClientHttpRequest request) throws IOException { + // Create or decorate the request object as needed + } + }, + new ResponseExtractor>() { + @Override + public ResponseEntity extractData(ClientHttpResponse response) throws IOException { + // extract required data from response + return null; + } + } + ); + + // Could also use some factory methods in RestTemplate for + // the request callback and/or response extractor + + Book book = new Book( + "Reactive Spring", + "Josh Long", + 2020); + + response = restTemplate.execute( + "https://api.bookstore.com", + HttpMethod.POST, + restTemplate.httpEntityCallback(book), + restTemplate.responseEntityExtractor(Book.class) + ); + } + + private static class Book { + String title; + String author; + int yearPublished; + + public Book(String title, String author, int yearPublished) { + this.title = title; + this.author = author; + this.yearPublished = yearPublished; + } + } +} diff --git a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/encoding/service/HttpBinServiceUnitTest.java b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/encoding/service/HttpBinServiceUnitTest.java new file mode 100644 index 0000000000..c45f1991e5 --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/encoding/service/HttpBinServiceUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.encoding.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class HttpBinServiceUnitTest { + @Autowired + private HttpBinService httpBinService; + + @Test + void givenWithoutPlusSign_whenGet_thenSameValueReturned() throws JsonProcessingException { + String parameterWithoutPlusSign = "springboot"; + String responseWithoutPlusSign = httpBinService.get(parameterWithoutPlusSign); + assertEquals(parameterWithoutPlusSign, responseWithoutPlusSign); + } + + @Test + void givenWithPlusSign_whenGet_thenSameValueReturned() throws JsonProcessingException { + String parameterWithPlusSign = "spring+boot"; + String responseWithPlusSign = httpBinService.get(parameterWithPlusSign); + assertEquals(parameterWithPlusSign, responseWithPlusSign); + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/resttemplate/methods/RestTemplateMethodsUnitTest.java b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/resttemplate/methods/RestTemplateMethodsUnitTest.java new file mode 100644 index 0000000000..c7a2880f9d --- /dev/null +++ b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/resttemplate/methods/RestTemplateMethodsUnitTest.java @@ -0,0 +1,86 @@ +package com.baeldung.resttemplate.methods; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.*; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.client.response.MockRestResponseCreators; +import org.springframework.web.client.RestTemplate; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; + +/** + * Unit tests for different ways to send POST with RestTemplate. + */ +public class RestTemplateMethodsUnitTest +{ + + private final RestTemplate restTemplate = new RestTemplate(); + + private final String URL = "https://localhost:8080"; + + private MockRestServiceServer mockServer; + + @BeforeEach + public void setup() { + mockServer = MockRestServiceServer.createServer(restTemplate); + } + + /** + * Test that postForEntity sends a POST to the desired URL. + */ + @Test + public void testPostForEntity() { + + mockServer.expect(requestTo(URL)) + .andExpect(method(HttpMethod.POST)) + .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK) + .contentType(MediaType.TEXT_PLAIN) + .body("Ok")); + + restTemplate.postForEntity( + URL, + "Test Body", + String.class); + + mockServer.verify(); + } + + /** + * Test that exchange with POST method sends a POST to the desired URL. + */ + @Test + public void testPostExchange() { + mockServer.expect(requestTo(URL)) + .andExpect(method(HttpMethod.POST)) + .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK) + .contentType(MediaType.TEXT_PLAIN) + .body("Ok")); + + restTemplate.exchange( + URL, + HttpMethod.POST, + new HttpEntity<>("Test Body"), + String.class); + + mockServer.verify(); + } + + @Test + public void testPostExecute() { + mockServer.expect(requestTo(URL)) + .andExpect(method(HttpMethod.POST)) + .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK) + .contentType(MediaType.TEXT_PLAIN) + .body("Ok")); + + restTemplate.execute( + URL, + HttpMethod.POST, + restTemplate.httpEntityCallback("Test body"), + restTemplate.responseEntityExtractor(String.class)); + + mockServer.verify(); + } +} diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java index ea51ca3cd9..b646717ec2 100644 --- a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java +++ b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java @@ -2,42 +2,43 @@ package com.baeldung.thymeleaf.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +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; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) -public class WebMVCSecurity extends WebSecurityConfigurerAdapter { +public class WebMVCSecurity { @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withUsername("user1") + .password("{noop}user1Pass") + .authorities("ROLE_USER") + .build(); + + return new InMemoryUserDetailsManager(user); } - public WebMVCSecurity() { - super(); + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring() + .antMatchers("/resources/**"); } - @Override - protected void configure(final AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user1").password("{noop}user1Pass").authorities("ROLE_USER"); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + return http.build(); } - - @Override - public void configure(final WebSecurity web) throws Exception { - web.ignoring().antMatchers("/resources/**"); - } - - @Override - protected void configure(final HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().authenticated().and().httpBasic(); - } - } diff --git a/spring-web-modules/spring-thymeleaf-5/README.md b/spring-web-modules/spring-thymeleaf-5/README.md index 177d28e506..c06b47d240 100644 --- a/spring-web-modules/spring-thymeleaf-5/README.md +++ b/spring-web-modules/spring-thymeleaf-5/README.md @@ -9,4 +9,5 @@ This module contains articles about Spring with Thymeleaf - [Spring MVC Data and Thymeleaf](https://www.baeldung.com/spring-mvc-thymeleaf-data) - [Upload Image With Spring Boot and Thymeleaf](https://www.baeldung.com/spring-boot-thymeleaf-image-upload) - [Getting a URL Attribute Value in Thymeleaf](https://www.baeldung.com/thymeleaf-url-attribute-value) +- [Expression Types in Thymeleaf](https://www.baeldung.com/java-thymeleaf-expression-types) - [[<-- prev]](/spring-thymeleaf) diff --git a/spring-web-modules/spring-web-url/README.md b/spring-web-modules/spring-web-url/README.md index 41b479337b..79a89f4386 100644 --- a/spring-web-modules/spring-web-url/README.md +++ b/spring-web-modules/spring-web-url/README.md @@ -6,3 +6,4 @@ This module contains articles about Spring MVC - [Using a Slash Character in Spring URLs](https://www.baeldung.com/spring-slash-character-in-url) - [Excluding URLs for a Filter in a Spring Web Application](https://www.baeldung.com/spring-exclude-filter) - [Handling URL Encoded Form Data in Spring REST](https://www.baeldung.com/spring-url-encoded-form-data) +- [Spring MVC – Mapping the Root URL to a Page](https://www.baeldung.com/spring-mvc-map-root-url) diff --git a/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/RootMappingApplication.java b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/RootMappingApplication.java new file mode 100644 index 0000000000..f64753fa36 --- /dev/null +++ b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/RootMappingApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.rootmapping; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@EnableWebMvc +public class RootMappingApplication { + + public static void main(String[] args) { + SpringApplication.run(RootMappingApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/config/WebConfig.java b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/config/WebConfig.java new file mode 100644 index 0000000000..ba15bc992c --- /dev/null +++ b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/config/WebConfig.java @@ -0,0 +1,13 @@ +package com.baeldung.rootmapping.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("index"); + } +} diff --git a/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/controller/RootController.java b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/controller/RootController.java new file mode 100644 index 0000000000..7724e43e71 --- /dev/null +++ b/spring-web-modules/spring-web-url/src/main/java/com/baeldung/rootmapping/controller/RootController.java @@ -0,0 +1,12 @@ +package com.baeldung.rootmapping.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class RootController { + @GetMapping("/") + public String index() { + return "index"; + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-web-url/src/main/resources/templates/index.html b/spring-web-modules/spring-web-url/src/main/resources/templates/index.html new file mode 100644 index 0000000000..acfb847868 --- /dev/null +++ b/spring-web-modules/spring-web-url/src/main/resources/templates/index.html @@ -0,0 +1,10 @@ + + + + + Index Page + + +

Hello World!

+ + \ No newline at end of file diff --git a/tablesaw/README.md b/tablesaw/README.md index e7409a0b6b..679e5c9a14 100644 --- a/tablesaw/README.md +++ b/tablesaw/README.md @@ -1,5 +1,5 @@ This module contains tutorials related to the tablesaw java library. ### Relevant Articles: - +- [Working with Tabular Data Using Tablesaw](https://www.baeldung.com/tablesaw) diff --git a/tablesaw/pom.xml b/tablesaw/pom.xml index b54c9aa13e..f38e4cb8b4 100644 --- a/tablesaw/pom.xml +++ b/tablesaw/pom.xml @@ -20,10 +20,6 @@ - - 0.43.1 - - @@ -38,4 +34,8 @@ - + + 0.43.1 + + + \ No newline at end of file diff --git a/testing-modules/assertion-libraries/README.md b/testing-modules/assertion-libraries/README.md index 5be5c7e004..4363ba2ed7 100644 --- a/testing-modules/assertion-libraries/README.md +++ b/testing-modules/assertion-libraries/README.md @@ -10,3 +10,4 @@ - [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) - [Using Conditions with AssertJ Assertions](http://www.baeldung.com/assertj-conditions) - [AssertJ Exception Assertions](http://www.baeldung.com/assertj-exception-assertion) +- [Extract Values using AssertJ in Java](https://www.baeldung.com/java-extract-values-assertj) diff --git a/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Address.java b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Address.java new file mode 100644 index 0000000000..aa6ee85351 --- /dev/null +++ b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Address.java @@ -0,0 +1,25 @@ +package com.baeldung.assertj.extracting; + +class Address { + private String street; + private String city; + private ZipCode zipCode; + + Address(String street, String city, ZipCode zipCode) { + this.street = street; + this.city = city; + this.zipCode = zipCode; + } + + public String getStreet() { + return street; + } + + public String getCity() { + return city; + } + + public ZipCode getZipCode() { + return zipCode; + } +} diff --git a/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Person.java b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Person.java new file mode 100644 index 0000000000..b8a987cf09 --- /dev/null +++ b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/Person.java @@ -0,0 +1,25 @@ +package com.baeldung.assertj.extracting; + +class Person { + private String firstName; + private String lastName; + private Address address; + + Person(String firstName, String lastName, Address address) { + this.firstName = firstName; + this.lastName = lastName; + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public Address getAddress() { + return address; + } +} diff --git a/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/ZipCode.java b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/ZipCode.java new file mode 100644 index 0000000000..1523ef7144 --- /dev/null +++ b/testing-modules/assertion-libraries/src/main/java/com/baeldung/assertj/extracting/ZipCode.java @@ -0,0 +1,13 @@ +package com.baeldung.assertj.extracting; + +class ZipCode { + private long zipcode; + + ZipCode(long zipcode) { + this.zipcode = zipcode; + } + + public long getZipcode() { + return zipcode; + } +} diff --git a/testing-modules/assertion-libraries/src/test/java/com/baeldung/assertj/extracting/AssertJExtractingUnitTest.java b/testing-modules/assertion-libraries/src/test/java/com/baeldung/assertj/extracting/AssertJExtractingUnitTest.java new file mode 100644 index 0000000000..aae4f8a041 --- /dev/null +++ b/testing-modules/assertion-libraries/src/test/java/com/baeldung/assertj/extracting/AssertJExtractingUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.assertj.extracting; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.as; +import static org.assertj.core.api.Assertions.assertThat; + +class AssertJExtractingUnitTest { + static final List
RESTRICTED_ADDRESSES = new ArrayList<>(); + + @Test + void whenUsingRegularAssertionFlow_thenCorrect() { + + // Given + Person person = new Person("aName", "aLastName", new Address("aStreet", "aCity", new ZipCode(90210))); + + // Then + Address address = person.getAddress(); + assertThat(address).isNotNull() + .isNotIn(RESTRICTED_ADDRESSES); + ZipCode zipCode = address.getZipCode(); + assertThat(zipCode).isNotNull(); + assertThat(zipCode.getZipcode()).isBetween(1000L, 100_000L); + } + + @Test + void whenUsingExtractingAssertionFlow_thenCorrect() { + + // Given + Person person = new Person("aName", "aLastName", new Address("aStreet", "aCity", new ZipCode(90210))); + + // Then + assertThat(person) + .extracting(Person::getAddress) + .isNotNull() + .isNotIn(RESTRICTED_ADDRESSES) + .extracting(Address::getZipCode) + .isNotNull() + .extracting(ZipCode::getZipcode, as(InstanceOfAssertFactories.LONG)) + .isBetween(1_000L, 100_000L); + } +} diff --git a/testing-modules/instancio/.gitignore b/testing-modules/instancio/.gitignore new file mode 100644 index 0000000000..7f300600e6 --- /dev/null +++ b/testing-modules/instancio/.gitignore @@ -0,0 +1,14 @@ +*.class + +.settings +.project + +#folders# +/target +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear diff --git a/testing-modules/instancio/README.md b/testing-modules/instancio/README.md new file mode 100644 index 0000000000..35166ee017 --- /dev/null +++ b/testing-modules/instancio/README.md @@ -0,0 +1,2 @@ +## Relevant articles +- [Generate Unit Test Data in Java Using Instancio](https://www.baeldung.com/java-test-data-instancio) diff --git a/testing-modules/instancio/pom.xml b/testing-modules/instancio/pom.xml new file mode 100644 index 0000000000..7687ce282d --- /dev/null +++ b/testing-modules/instancio/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + instancio + instancio + jar + + + com.baeldung + testing-modules + 1.0.0-SNAPSHOT + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + + + org.instancio + instancio-junit + ${instancio.version} + test + + + org.assertj + assertj-core + ${assertj.version} + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + + + + + 2.9.0 + 2.14.1 + 5.9.2 + + diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/abstracttype/AbstractItem.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/abstracttype/AbstractItem.java new file mode 100644 index 0000000000..4dd21e6ffb --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/abstracttype/AbstractItem.java @@ -0,0 +1,6 @@ +package com.baeldung.instancio.abstracttype; + +public interface AbstractItem { + + T getValue(); +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Item.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Item.java new file mode 100644 index 0000000000..19450a936c --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Item.java @@ -0,0 +1,18 @@ +package com.baeldung.instancio.generics; + +import com.baeldung.instancio.abstracttype.AbstractItem; + +public class Item implements AbstractItem { + + private T value; + + @Override + public T getValue() { + return value; + } + + @Override + public String toString() { + return String.format("Item[value=%s]", value); + } +} \ No newline at end of file diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Pair.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Pair.java new file mode 100644 index 0000000000..48b43fe9aa --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Pair.java @@ -0,0 +1,20 @@ +package com.baeldung.instancio.generics; + +public class Pair { + + private L left; + private R right; + + public L getLeft() { + return left; + } + + public R getRight() { + return right; + } + + @Override + public String toString() { + return String.format("Pair[left=%s, right=%s]", left, right); + } +} \ No newline at end of file diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Triplet.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Triplet.java new file mode 100644 index 0000000000..528c4d7c98 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/generics/Triplet.java @@ -0,0 +1,24 @@ +package com.baeldung.instancio.generics; + +public class Triplet { + private L left; + private M middle; + private R right; + + public L getLeft() { + return left; + } + + public M getMiddle() { + return middle; + } + + public R getRight() { + return right; + } + + @Override + public String toString() { + return String.format("Triplet[left=%s, middle=%s, right=%s]", left, right, middle); + } +} \ No newline at end of file diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Address.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Address.java new file mode 100644 index 0000000000..cda34690e5 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Address.java @@ -0,0 +1,31 @@ +package com.baeldung.instancio.student.model; + +import com.baeldung.instancio.util.PrettyToString; + +public class Address { + private String street; + private String city; + private String country; + + public String getStreet() { + return street; + } + + public String getCity() { + return city; + } + + public String getCountry() { + return country; + } + + public void setCountry(final String country) { + this.country = country; + } + + @Override + public String toString() { + return PrettyToString.toPrettyString(this); + } + +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/ContactInfo.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/ContactInfo.java new file mode 100644 index 0000000000..71534192c6 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/ContactInfo.java @@ -0,0 +1,28 @@ +package com.baeldung.instancio.student.model; + +import com.baeldung.instancio.util.PrettyToString; + +import java.util.List; + +public class ContactInfo { + private Address address; + private List phones; + private String email; + + public Address getAddress() { + return address; + } + + public List getPhones() { + return phones; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return PrettyToString.toPrettyString(this); + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Course.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Course.java new file mode 100644 index 0000000000..543f6eaf4e --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Course.java @@ -0,0 +1,53 @@ +package com.baeldung.instancio.student.model; + +import com.baeldung.instancio.util.PrettyToString; + +import java.time.Duration; +import java.time.LocalDate; +import java.util.Objects; + +public class Course { + private String title; + private String code; + private LocalDate startDate; + private Duration duration; + private String instructor; + + public String getTitle() { + return title; + } + + public String getCode() { + return code; + } + + public LocalDate getStartDate() { + return startDate; + } + + public Duration getDuration() { + return duration; + } + + public String getInstructor() { + return instructor; + } + + @Override + public String toString() { + return PrettyToString.toPrettyString(this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Course)) return false; + final Course course = (Course) o; + return Objects.equals(getCode(), course.getCode()); + } + + @Override + public int hashCode() { + return Objects.hash(getCode()); + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/EmergencyContact.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/EmergencyContact.java new file mode 100644 index 0000000000..7c5ce21738 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/EmergencyContact.java @@ -0,0 +1,14 @@ +package com.baeldung.instancio.student.model; + +public class EmergencyContact { + private String name; + private Phone phone; + + public String getName() { + return name; + } + + public Phone getPhone() { + return phone; + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Grade.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Grade.java new file mode 100644 index 0000000000..8bd9341a18 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Grade.java @@ -0,0 +1,5 @@ +package com.baeldung.instancio.student.model; + +public enum Grade { + A, B, C, D, F +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Phone.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Phone.java new file mode 100644 index 0000000000..887cce5c7d --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Phone.java @@ -0,0 +1,23 @@ +package com.baeldung.instancio.student.model; + +import com.baeldung.instancio.util.PrettyToString; + +public class Phone { + + private String countryCode; + private String number; + + public String getCountryCode() { + return countryCode; + } + + public String getNumber() { + return number; + } + + @Override + public String toString() { + return PrettyToString.toPrettyString(this); + } + +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Student.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Student.java new file mode 100644 index 0000000000..fd6b3cbc1c --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/model/Student.java @@ -0,0 +1,57 @@ +package com.baeldung.instancio.student.model; + + +import com.baeldung.instancio.util.PrettyToString; + +import java.time.LocalDate; +import java.time.Year; +import java.util.Map; +import java.util.UUID; + +public class Student { + private UUID id; + private String firstName; + private String lastName; + private LocalDate dateOfBirth; + private ContactInfo contactInfo; + private EmergencyContact emergencyContact; + private Year enrollmentYear; + private Map courseGrades; + + public UUID getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public ContactInfo getContactInfo() { + return contactInfo; + } + + public EmergencyContact getEmergencyContact() { + return emergencyContact; + } + + public Year getEnrollmentYear() { + return enrollmentYear; + } + + public Map getCourseGrades() { + return courseGrades; + } + + @Override + public String toString() { + return PrettyToString.toPrettyString(this); + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/CourseService.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/CourseService.java new file mode 100644 index 0000000000..e71da0b23e --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/CourseService.java @@ -0,0 +1,11 @@ +package com.baeldung.instancio.student.service; + +import com.baeldung.instancio.student.model.Course; + +public class CourseService { + + public Course getByCode(String courseCode) { + throw new UnsupportedOperationException( + "This class should be mocked. Persistence is not available in a unit test"); + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentException.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentException.java new file mode 100644 index 0000000000..2398556b73 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentException.java @@ -0,0 +1,8 @@ +package com.baeldung.instancio.student.service; + +public class EnrollmentException extends RuntimeException { + + public EnrollmentException(final String message) { + super(message); + } +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentService.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentService.java new file mode 100644 index 0000000000..d505a5881c --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/student/service/EnrollmentService.java @@ -0,0 +1,30 @@ +package com.baeldung.instancio.student.service; + +import com.baeldung.instancio.student.model.Course; +import com.baeldung.instancio.student.model.Grade; +import com.baeldung.instancio.student.model.Student; + +import java.util.Collection; + +public class EnrollmentService { + + private CourseService courseService; + + public boolean enrollStudent(Student student, Course course) { + Collection grades = student.getCourseGrades().values(); + if (grades.contains(Grade.F)) { + throw new EnrollmentException(String.format("Student %s has at least 1 failed course", student.getId())); + } + // process enrollment... + return true; + } + + public boolean enrollStudent(Student student, String courseCode) { + Course course = courseService.getByCode(courseCode); + if (course == null) { + throw new EnrollmentException("Course not found: " + courseCode); + } + return enrollStudent(student, course); + } + +} diff --git a/testing-modules/instancio/src/main/java/com/baeldung/instancio/util/PrettyToString.java b/testing-modules/instancio/src/main/java/com/baeldung/instancio/util/PrettyToString.java new file mode 100644 index 0000000000..163f3673c7 --- /dev/null +++ b/testing-modules/instancio/src/main/java/com/baeldung/instancio/util/PrettyToString.java @@ -0,0 +1,21 @@ +package com.baeldung.instancio.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +public class PrettyToString { + + private static final ObjectWriter objectWriter = new ObjectMapper() + .registerModules(new JavaTimeModule()) + .writerWithDefaultPrettyPrinter(); + + public static String toPrettyString(Object obj) { + try { + return objectWriter.writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/basics/CreateStudentUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/basics/CreateStudentUnitTest.java new file mode 100644 index 0000000000..524c8dbc91 --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/basics/CreateStudentUnitTest.java @@ -0,0 +1,174 @@ +package com.baeldung.instancio.basics; + +import com.baeldung.instancio.student.model.Address; +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.Course; +import com.baeldung.instancio.student.model.Grade; +import com.baeldung.instancio.student.model.Phone; +import com.baeldung.instancio.student.model.Student; +import org.instancio.Instancio; +import org.instancio.Model; +import org.instancio.junit.InstancioExtension; +import org.instancio.junit.InstancioSource; +import org.instancio.junit.Seed; +import org.instancio.junit.WithSettings; +import org.instancio.settings.Keys; +import org.instancio.settings.Settings; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; + +import java.time.LocalDate; +import java.time.Year; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.all; +import static org.instancio.Select.field; + +/** + * Sample test class using Instancio to generate test objects. + * + *

Note: using {@link InstancioExtension} is optional. The extension adds support for: + *

+ * - reporting seed value if a test fails + * - {@link Seed} annotation for reproducing failed tests + * - {@link WithSettings} for injecting custom settings, if needed + */ +@ExtendWith(InstancioExtension.class) +class CreateStudentUnitTest { + + /** + * Common settings to be used by all test methods. + */ + @WithSettings + private static final Settings settings = Settings.create() + .set(Keys.COLLECTION_MAX_SIZE, 3); + + /** + * A {@link Model} is a template for creating objects. + * Objects created from a model can be created as is, or customized, if needed. + */ + private static Model studentModel() { + return Instancio.of(Student.class) + .generate(field(Student::getDateOfBirth), gen -> gen.temporal().localDate().past()) + .generate(field(Student::getEnrollmentYear), gen -> gen.temporal().year().past()) + .generate(field(ContactInfo::getEmail), gen -> gen.text().pattern("#a#a#a#a#a#a@example.com")) + .generate(field(Phone::getCountryCode), gen -> gen.string().prefix("+").digits().maxLength(2)) + .withNullable(field(Student::getEmergencyContact)) + .toModel(); + } + + private static void assertModelProperties(Student student) { + assertThat(student.getDateOfBirth()).isBefore(LocalDate.now()); + assertThat(student.getEnrollmentYear()).isLessThan(Year.now()); + assertThat(student.getContactInfo().getEmail()).matches("^[a-zA-Z0-9]+@example.com$"); + assertThat(student.getContactInfo().getPhones()) + .extracting(Phone::getCountryCode) + .allSatisfy(countryCode -> assertThat(countryCode).matches("^\\+\\d\\d?$")); + } + + /** + * Generates random Student objects based on the Model. + */ + @Test + void whenGivenAModel_thenShouldCreateAStudentBasedOnModel() { + Student student = Instancio.create(studentModel()); + + assertModelProperties(student); + } + + /** + * Generate a list of international students based on the Model. + */ + @Test + void whenGivenAModel_thenShouldCreateAListOfStudents() { + // Given + final int numberOfStudents = 100; + final List countries = Arrays.asList( + "China", "Germany", "India", "Poland", "Romania", "Sweden", "Switzerland"); + + // When + List studentList = Instancio.ofList(studentModel()) + .size(numberOfStudents) + .generate(field(Address::getCountry), gen -> gen.oneOf(countries)) + .create(); + + // Then + assertThat(studentList).hasSize(numberOfStudents) + .allSatisfy(CreateStudentUnitTest::assertModelProperties) + .extracting(student -> student.getContactInfo().getAddress().getCountry()) + .allSatisfy(country -> assertThat(country).isIn(countries)); + } + + /** + * Use the Model to create a student with a failed course. + * This test also demonstrates how Instancio can provide + * arguments to parameterized tests. + * + * @param failedCourse provided by Instancio + */ + @InstancioSource + @ParameterizedTest + void whenGivenFailingGrade_thenStudentShouldHaveAFailedCourse(final Course failedCourse) { + // Given + final Model model = studentModel(); + final Grade failingGrade = Grade.F; + + // When + Student student = Instancio.of(model) + .generate(field(Student::getCourseGrades), gen -> gen.map().with(failedCourse, failingGrade)) + .create(); + + // Then + Map courseGrades = student.getCourseGrades(); + assertModelProperties(student); + assertThat(courseGrades).containsEntry(failedCourse, failingGrade); + } + + /** + * Generate a student with only Grades A and/or B. + */ + @Test + void whenGivenGoodGrades_thenCreatedStudentShouldHaveExpectedGrades() { + // Given + final int numOfCourses = 10; + final Grade[] grades = {Grade.A, Grade.B}; + + // When + Student student = Instancio.of(studentModel()) + .generate(all(Grade.class), gen -> gen.oneOf(grades)) + .generate(field(Student::getCourseGrades), gen -> gen.map().size(numOfCourses)) + .create(); + + // Then + Map courseGrades = student.getCourseGrades(); + assertModelProperties(student); + assertThat(courseGrades.values()) + .hasSize(numOfCourses) + .containsAnyOf(grades) + .doesNotContain(Grade.C, Grade.D, Grade.F); + } + + /** + * Generate String fields prefixed with the field's name. + */ + @Test + void whenGivenCustomSettings_thenStudentShouldBeCreatedUsingTheSettings() { + // Given + Settings customSettings = Settings.create() + .set(Keys.STRING_FIELD_PREFIX_ENABLED, true); + + // When + Student student = Instancio.of(studentModel()) + .withSettings(customSettings) + .create(); + + // Then + assertThat(student.getFirstName()).startsWith("firstName_"); + assertThat(student.getLastName()).startsWith("lastName_"); + assertThat(student.getContactInfo().getAddress().getCity()).startsWith("city_"); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/generators/UsingCustomGeneratorUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/generators/UsingCustomGeneratorUnitTest.java new file mode 100644 index 0000000000..8e5643baec --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/generators/UsingCustomGeneratorUnitTest.java @@ -0,0 +1,57 @@ +package com.baeldung.instancio.generators; + +import com.baeldung.instancio.student.model.Address; +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.Phone; +import com.baeldung.instancio.student.model.Student; +import org.instancio.Instancio; +import org.instancio.Random; +import org.instancio.generator.AfterGenerate; +import org.instancio.generator.Generator; +import org.instancio.generator.Hints; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.all; +import static org.instancio.Select.field; + +class UsingCustomGeneratorUnitTest { + private static final String ARGENTINA = "Argentina"; + private static final int PHONES_SIZE = 5; + + private static final Generator

ADDRESS_GENERATOR = new Generator
() { + @Override + public Address generate(final Random random) { + Address address = new Address(); + address.setCountry(ARGENTINA); + return address; + } + + @Override + public Hints hints() { + // The hint telling the engine to populate any field that has a null value + return Hints.afterGenerate(AfterGenerate.POPULATE_NULLS); + } + }; + + @Test + void whenGivenAGenerator_objectShouldBeCreatedUsingCustomGenerator() { + Student student = Instancio.of(Student.class) + .supply(all(Address.class), ADDRESS_GENERATOR) + .generate(field(ContactInfo::getPhones), gen -> gen.collection().size(PHONES_SIZE)) + .create(); + + ContactInfo contactInfo = student.getContactInfo(); + Address address = contactInfo.getAddress(); + List phones = contactInfo.getPhones(); + + assertThat(phones).hasSize(PHONES_SIZE); + assertThat(address.getCountry()).isEqualTo(ARGENTINA); + // null fields were populated with random values + assertThat(address.getStreet()).isNotNull(); + assertThat(address.getCity()).isNotNull(); + } + +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/generics/CreatingGenericTypesUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/generics/CreatingGenericTypesUnitTest.java new file mode 100644 index 0000000000..4ed22abeaf --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/generics/CreatingGenericTypesUnitTest.java @@ -0,0 +1,100 @@ +package com.baeldung.instancio.generics; + +import com.baeldung.instancio.student.model.Address; +import org.instancio.Instancio; +import org.instancio.TypeToken; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.allLongs; +import static org.instancio.Select.allStrings; + +/** + * Examples of creating generic types using {@link TypeToken}. + */ +class CreatingGenericTypesUnitTest { + + + @Test + void whenGivenTypeToken_shouldCreateItem() { + Item item = Instancio.create(new TypeToken>() {}); + + assertThat(item.getValue()).isNotBlank(); + } + + @Test + void whenGivenTypeToken_shouldCreateCustomizedItem() { + Pair pair = Instancio.of(new TypeToken>() {}) + .generate(allStrings(), gen -> gen.oneOf("foo", "bar")) + .generate(allLongs(), gen -> gen.longs().range(5L, 10L)) + .create(); + + assertThat(pair.getLeft()).isIn("foo", "bar"); + assertThat(pair.getRight()).isBetween(5L, 10L); + } + + @Test + void whenGivenTypeToken_shouldCreateTriplet() { + Triplet triplet = Instancio.create(new TypeToken>() {}); + + assertThat(triplet.getLeft()).isNotBlank(); + assertThat(triplet.getMiddle()).isNotNull(); + assertThat(triplet.getRight()).isNotNull(); + } + + @Test + void whenGivenTypeToken_shouldCreateCollection() { + List list = Instancio.create(new TypeToken>() {}); + + assertThat(list).isNotEmpty().doesNotContainNull(); + } + + @Test + void whenGivenTypeToken_shouldCreateMap() { + Map map = Instancio.create(new TypeToken>() {}); + + assertThat(map).isNotEmpty(); + } + + /** + * Using type token to create more complex generic objects. + */ + @Test + void whenGivenTypeTokenWithNestGenerics_shouldCreateAnInstanceOfSpecifiedType() { + List>> list = Instancio.create( + new TypeToken>>>() {}); + + assertThat(list) + .isNotEmpty() + .allSatisfy(triplet -> { + assertThat(triplet.getLeft()).isInstanceOf(Integer.class); + assertThat(triplet.getMiddle()).isInstanceOf(LocalDate.class); + assertThat(triplet.getRight()) + .isInstanceOf(Item.class) + .satisfies(item -> assertThat(item.getValue()).isNotBlank()); + }); + + // Sample output + list.forEach(System.out::println); + } + + + /** + * Alternative way to create generic objects is using 'withTypeParameters'. + * However, this approach generates an "unchecked assignment" warning. + */ + @Test + @SuppressWarnings("unchecked") + void whenGivenClassWithTypeParameters_shouldCreateGenericType() { + Map map = Instancio.of(Map.class) + .withTypeParameters(UUID.class, Address.class) + .create(); + + assertThat(map).isNotEmpty(); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/mockito/InstancioWithMockitoUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/mockito/InstancioWithMockitoUnitTest.java new file mode 100644 index 0000000000..1382589a84 --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/mockito/InstancioWithMockitoUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.instancio.mockito; + +import com.baeldung.instancio.student.model.Course; +import com.baeldung.instancio.student.model.Grade; +import com.baeldung.instancio.student.model.Student; +import com.baeldung.instancio.student.service.CourseService; +import com.baeldung.instancio.student.service.EnrollmentService; +import org.instancio.Instancio; +import org.instancio.junit.InstancioExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.all; +import static org.mockito.Mockito.when; + +@ExtendWith({MockitoExtension.class, InstancioExtension.class}) +class InstancioWithMockitoUnitTest { + + @Mock + private CourseService courseService; + + @InjectMocks + private EnrollmentService enrollmentService; + + @Test + void givenStudentWithoutGradeF_thenShouldEnrollStudentInCourse() { + // Given + Student student = Instancio.of(Student.class) + .generate(all(Grade.class), gen -> gen.enumOf(Grade.class).excluding(Grade.F)) + .create(); + + Course course = Instancio.create(Course.class); + when(courseService.getByCode(course.getCode())).thenReturn(course); + + // When + boolean isEnrolled = enrollmentService.enrollStudent(student, course.getCode()); + + // Then + assertThat(isEnrolled).isTrue(); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/reproducing/ReproducingTestFailureUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/reproducing/ReproducingTestFailureUnitTest.java new file mode 100644 index 0000000000..0d6c8cfa9a --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/reproducing/ReproducingTestFailureUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.instancio.reproducing; + +import com.baeldung.instancio.student.model.Course; +import com.baeldung.instancio.student.model.Student; +import com.baeldung.instancio.student.service.EnrollmentService; +import org.instancio.Instancio; +import org.instancio.junit.InstancioExtension; +import org.instancio.junit.Seed; +import org.instancio.junit.WithSettings; +import org.instancio.settings.Keys; +import org.instancio.settings.Settings; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(InstancioExtension.class) +class ReproducingTestFailureUnitTest { + + @WithSettings + private static final Settings settings = Settings.create() + .set(Keys.COLLECTION_MIN_SIZE, 50) + .set(Keys.COLLECTION_MAX_SIZE, 100) + .lock(); + + private final EnrollmentService enrollmentService = new EnrollmentService(); + + /** + * This test fails because the {@code enrollInCourse()} method + * throws an exception if the student has at least one grade F. + * + *

Sample error message generated by {@link InstancioExtension}: + * + *

+     * timestamp = 2023-01-24T13:50:12.436704221, Instancio = Test method 'enrollStudent' failed with seed: 1234
+     * 
+ *

+ * Using the reported seed value we can reproduce the test failure. + */ + @Test + @Seed(1234) + @Disabled("This test fails on purpose to demonstrate failure reporting by InstancioExtension") + void whenGivenNoFailingGrades_thenShouldEnrollStudentInCourse() { + // Given + Course course = Instancio.create(Course.class); + Student student = Instancio.of(Student.class) + // The test can be fixed by uncommenting the line below: + //.generate(all(Grade.class), gen -> gen.enumOf(Grade.class).excluding(Grade.F)) + .create(); + + System.out.println(student); // same data generated on each run + + // When + boolean isEnrolled = enrollmentService.enrollStudent(student, course); + + // Then + assertThat(isEnrolled).isTrue(); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorScopesUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorScopesUnitTest.java new file mode 100644 index 0000000000..683b510f0c --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorScopesUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.instancio.selectors; + +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.EmergencyContact; +import com.baeldung.instancio.student.model.Phone; +import com.baeldung.instancio.student.model.Student; +import org.instancio.Instancio; +import org.instancio.Scope; +import org.instancio.Select; +import org.instancio.TargetSelector; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.allStrings; +import static org.instancio.Select.scope; + +/** + * Examples of various selector {@link Scope}. + * Scopes allow narrowing down selector targets. + */ +class SelectorScopesUnitTest { + + /** + * Prefix all String fields in Phone class with "phone_". + */ + @Test + void whenGivenClassScope_shouldSelectTargetsWithinClass() { + // Given + final String prefix = "phone_"; + final Scope phoneClass = scope(Phone.class); + + // When + Student student = Instancio.of(Student.class) + .generate(allStrings().within(phoneClass), gen -> gen.string().prefix(prefix)) + .create(); + + // Then + + // matches phone numbers + Phone emergencyContactPhone = student.getEmergencyContact().getPhone(); + assertThat(emergencyContactPhone.getCountryCode()).startsWith(prefix); + assertThat(emergencyContactPhone.getNumber()).startsWith(prefix); + assertThat(student.getContactInfo().getPhones()).allSatisfy(phone -> { + assertThat(phone.getCountryCode()).startsWith(prefix); + assertThat(phone.getNumber()).startsWith(prefix); + }); + + // does not match other fields + assertThat(student.getContactInfo().getAddress().getCity()).doesNotStartWith(prefix); + } + + /** + * Using scope to set student's and their emergency contact's + * phone number to different values. + */ + @Test + void whenGivenFieldScope_shouldSelectTargetsWithinField() { + // Given + TargetSelector studentPhone = Select.field(Phone::getNumber).within(scope(ContactInfo.class)); + TargetSelector emergencyPhone = Select.field(Phone::getNumber).within(scope(EmergencyContact.class)); + + // When + Student student = Instancio.of(Student.class) + .set(studentPhone, "student") + .set(emergencyPhone, "emergency") + .create(); + + // Then + assertThat(student.getContactInfo().getPhones()) + .isNotEmpty() + .allSatisfy(phone -> assertThat(phone.getNumber()).isEqualTo("student")); + + assertThat(student.getEmergencyContact().getPhone().getNumber()) + .isEqualTo("emergency"); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorsUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorsUnitTest.java new file mode 100644 index 0000000000..fe6b9cc3f4 --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/selectors/SelectorsUnitTest.java @@ -0,0 +1,104 @@ +package com.baeldung.instancio.selectors; + +import com.baeldung.instancio.student.model.Address; +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.Phone; +import com.baeldung.instancio.student.model.Student; +import org.instancio.FieldSelectorBuilder; +import org.instancio.Instancio; +import org.instancio.Select; +import org.instancio.Selector; +import org.instancio.SelectorGroup; +import org.instancio.TargetSelector; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.all; +import static org.instancio.Select.field; +import static org.instancio.Select.fields; +import static org.instancio.Select.types; + +/** + * Examples of various types of selectors provided by the {@link Select} class. + */ +class SelectorsUnitTest { + + @Test + void whenGivenFieldSelector_shouldCustomizeSelectedField() { + Address address = Instancio.of(Address.class) + .set(field(Address::getCity), "London") + .set(field(Address.class, "country"), "UK") + .create(); + + assertThat(address.getCity()).isEqualTo("London"); + assertThat(address.getCountry()).isEqualTo("UK"); + } + + @Test + void whenGivenClassSelector_shouldCustomizeSelectedClass() { + // Given + final Selector allStrings = all(String.class); + final String prefix = "test_"; + + // When + Address address = Instancio.of(Address.class) + .generate(allStrings, gen -> gen.string().prefix(prefix)) + .create(); + + // Then + assertThat(address.getCity()).startsWith(prefix); + assertThat(address.getCountry()).startsWith(prefix); + } + + @Test + void whenGivenPredicateFieldSelector_shouldCustomizeMatchingFields() { + // Given: regie matching 'city' and 'country' fields + final FieldSelectorBuilder fieldsMatchingRegex = fields().matching("c.*y"); + + // When + Address address = Instancio.of(Address.class) + .ignore(fieldsMatchingRegex) + .create(); + + // Then + assertThat(address.getCity()).isNull(); + assertThat(address.getCountry()).isNull(); + assertThat(address.getStreet()).isNotBlank(); + } + + @Test + void whenGivenPredicateClassSelector_shouldCustomizeMatchingClasses() { + // Given + final TargetSelector allTypesOfCollections = types().of(Collection.class); + final int size = 3; + + // When + ContactInfo contactInfo = Instancio.of(ContactInfo.class) + .generate(allTypesOfCollections, gen -> gen.collection().size(size)) + .create(); + + // Then + List phones = contactInfo.getPhones(); + assertThat(phones).hasSize(size); + } + + @Test + void whenGivenSelectorGroup_shouldCustomizeSelectedFields() { + // Given + SelectorGroup ignoredFields = all( + field(Student::getId), + field(Student::getDateOfBirth)); + + // When + Student student = Instancio.of(Student.class) + .ignore(ignoredFields) + .create(); + + // Then + assertThat(student.getId()).isNull(); + assertThat(student.getDateOfBirth()).isNull(); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/CustomSettingsUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/CustomSettingsUnitTest.java new file mode 100644 index 0000000000..b9b8b4ac6d --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/CustomSettingsUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.instancio.settings; + +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.Phone; +import org.instancio.Instancio; +import org.instancio.junit.InstancioExtension; +import org.instancio.junit.WithSettings; +import org.instancio.settings.Keys; +import org.instancio.settings.Settings; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * {@link InstancioExtension} allows injecting custom settings + * using the {@link WithSettings} annotation. + */ +@ExtendWith(InstancioExtension.class) +class CustomSettingsUnitTest { + + private static final int MIN_SIZE = 0; + private static final int MAX_SIZE = 3; + + /** + * Common settings to be used by all test methods. + */ + @WithSettings + private static final Settings settings = Settings.create() + .set(Keys.COLLECTION_MIN_SIZE, MIN_SIZE) + .set(Keys.COLLECTION_MAX_SIZE, MAX_SIZE) + .lock(); + + + @Test + void whenGivenInjectedSettings_shouldUseCustomSettings() { + ContactInfo info = Instancio.create(ContactInfo.class); + + List phones = info.getPhones(); + assertThat(phones).hasSizeBetween(MIN_SIZE, MAX_SIZE); + } + + @Test + void whenSettingsOverridden_shouldUseTheOverrides() { + // Given + final int collectionSize = 50; + Settings additionalSettings = Settings.create() + .set(Keys.STRING_FIELD_PREFIX_ENABLED, true) + .set(Keys.COLLECTION_MIN_SIZE, collectionSize) + .set(Keys.COLLECTION_MAX_SIZE, collectionSize); + + // When + ContactInfo info = Instancio.of(ContactInfo.class) + .withSettings(additionalSettings) + .create(); + + // Then + assertThat(info.getPhones()) + .hasSize(collectionSize) + .allSatisfy(phone -> { + assertThat(phone.getCountryCode()).startsWith("countryCode_"); + assertThat(phone.getNumber()).startsWith("number_"); + }); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/UsingInstancioPropertiesUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/UsingInstancioPropertiesUnitTest.java new file mode 100644 index 0000000000..6a14d8dc88 --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/settings/UsingInstancioPropertiesUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.instancio.settings; + +import org.instancio.Instancio; +import org.instancio.settings.Keys; +import org.instancio.settings.Settings; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class UsingInstancioPropertiesUnitTest { + + /** + * Instancio automatically loads {@code instancio.properties} file, + * if it's present, from the root of the classpath. + * + *

Float range was overridden to [0, 100]. + * See: {@code src/test/resources/instancio.properties} + */ + @Test + void whenInstancioPropertiesAreOnClasspath_shouldUseConfiguredProperties() { + Set floats = Instancio.ofSet(Float.class).create(); + + assertThat(floats) + .isNotEmpty() + .allSatisfy(f -> assertThat(f).isBetween(0f, 100f)); + } + + /** + * We can override global configuration using {@link Settings}. + */ + @Test + void whenCustomSettingsAreProvided_shouldOverrideInstancioProperties() { + // Given + Settings settings = Settings.create() + .set(Keys.FLOAT_MIN, 100f) + .set(Keys.FLOAT_MAX, 200f); + + // When + Set floats = Instancio.ofSet(Float.class) + .withSettings(settings) + .create(); + + // Then + assertThat(floats) + .isNotEmpty() + .allSatisfy(f -> assertThat(f).isBetween(100f, 200f)); + } +} diff --git a/testing-modules/instancio/src/test/java/com/baeldung/instancio/subtype/SubtypeUnitTest.java b/testing-modules/instancio/src/test/java/com/baeldung/instancio/subtype/SubtypeUnitTest.java new file mode 100644 index 0000000000..7bbfaa497f --- /dev/null +++ b/testing-modules/instancio/src/test/java/com/baeldung/instancio/subtype/SubtypeUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.instancio.subtype; + +import com.baeldung.instancio.abstracttype.AbstractItem; +import com.baeldung.instancio.generics.Item; +import com.baeldung.instancio.student.model.ContactInfo; +import com.baeldung.instancio.student.model.Student; +import org.instancio.Instancio; +import org.instancio.TypeToken; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; +import java.util.LinkedList; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.instancio.Select.all; +import static org.instancio.Select.field; + +/** + * Using {@code subtype()} method we can specify a specific implementation + * class for an abstract type, or a specialized subclass for a concrete class. + */ +class SubtypeUnitTest { + + @Test + void whenGivenCollectionSubtype_shouldUseSpecifiedCollectionClass() { + // Given + final Class subtype = LinkedList.class; + + // When + Student student = Instancio.of(Student.class) + .subtype(field(ContactInfo::getPhones), subtype) + .create(); + + // Then + assertThat(student.getContactInfo().getPhones()) + .isNotEmpty() + .isExactlyInstanceOf(subtype); + } + + @Test + void whenGivenSubtypeForGenericAbstractType_shouldUseSpecifiedConcreteClass() { + // Given + final Class subtype = Item.class; + + // When + AbstractItem abstractItem = Instancio.of(new TypeToken>() {}) + .subtype(all(AbstractItem.class), subtype) + .create(); + + // Then + assertThat(abstractItem).isExactlyInstanceOf(subtype); + assertThat(abstractItem.getValue()).isNotNull(); + } +} diff --git a/testing-modules/instancio/src/test/resources/instancio.properties b/testing-modules/instancio/src/test/resources/instancio.properties new file mode 100644 index 0000000000..a314af0a3f --- /dev/null +++ b/testing-modules/instancio/src/test/resources/instancio.properties @@ -0,0 +1,2 @@ +float.min=1 +float.max=100 diff --git a/testing-modules/junit-5-advanced/README.md b/testing-modules/junit-5-advanced/README.md index 16509b75bf..9b3a5fa299 100644 --- a/testing-modules/junit-5-advanced/README.md +++ b/testing-modules/junit-5-advanced/README.md @@ -7,3 +7,4 @@ - [Run JUnit Test Cases From the Command Line](https://www.baeldung.com/junit-run-from-command-line) - [Parallel Test Execution for JUnit 5](https://www.baeldung.com/junit-5-parallel-tests) - [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) diff --git a/testing-modules/junit-5-advanced/pom.xml b/testing-modules/junit-5-advanced/pom.xml index ae6fd1559e..bfc490b03e 100644 --- a/testing-modules/junit-5-advanced/pom.xml +++ b/testing-modules/junit-5-advanced/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 junit-5-advanced 1.0-SNAPSHOT @@ -27,23 +27,32 @@ ${jmockit.version} test + + org.assertj + assertj-core + ${assertj.version} + test + - - - org.apache.maven.plugins - maven-surefire-plugin - - - -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar - - true - - - + + + org.apache.maven.plugins + maven-surefire-plugin + + + -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar + + true + + + + 1.49 + 3.24.2 + \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/multiassertions/MultiAssertionsInOneUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/multiassertions/MultiAssertionsInOneUnitTest.java new file mode 100644 index 0000000000..6fec9015cf --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/multiassertions/MultiAssertionsInOneUnitTest.java @@ -0,0 +1,94 @@ +package com.baeldung.multiassertions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.from; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import org.junit.jupiter.api.Test; + +public class MultiAssertionsInOneUnitTest { + private static final Product EXPECTED = new Product(42L, "LG Monitor", "32 inches, 4K Resolution, Ideal for programmer", true, new BigDecimal("429.99"), 77); + private static final Product TO_BE_TESTED = new Product(-1L, "LG Monitor", "dummy value: whatever", true, new BigDecimal("429.99"), 77); + + @Test + void givenAProductObject_whenUsingAssertAll_thenAssertMultiPropertiesInOneCall() { + //@formatter:off + assertAll("Verify Product properties", + () -> assertEquals(EXPECTED.getName(), TO_BE_TESTED.getName()), + () -> assertEquals(EXPECTED.isOnSale(), TO_BE_TESTED.isOnSale()), + () -> assertEquals(EXPECTED.getStockQuantity(), TO_BE_TESTED.getStockQuantity()), + () -> assertEquals(EXPECTED.getPrice(), TO_BE_TESTED.getPrice())); + //@formatter:on + } + + @Test + void givenAProductObject_whenUsingAssertJExtracting_thenAssertMultiPropertiesInOneCall() { + //@formatter:off + assertThat(TO_BE_TESTED) + .extracting("name", "onSale", "stockQuantity", "price") + .containsExactly(EXPECTED.getName(), EXPECTED.isOnSale(), EXPECTED.getStockQuantity(), EXPECTED.getPrice()); + + assertThat(TO_BE_TESTED) + .extracting(Product::getName, Product::isOnSale, Product::getStockQuantity,Product::getPrice) + .containsExactly(EXPECTED.getName(), EXPECTED.isOnSale(), EXPECTED.getStockQuantity(), EXPECTED.getPrice()); + //@formatter:on + } + + @Test + void givenAProductObject_whenUsingAssertJReturns_thenAssertMultiPropertiesInOneCall() { + //@formatter:off + assertThat(TO_BE_TESTED) + .returns(EXPECTED.getName(),from(Product::getName)) + .returns(EXPECTED.isOnSale(), from(Product::isOnSale)) + .returns(EXPECTED.getStockQuantity(), from(Product::getStockQuantity)) + .returns(EXPECTED.getPrice(), from(Product::getPrice)) + + .doesNotReturn(EXPECTED.getId(), from(Product::getId)) + .doesNotReturn(EXPECTED.getDescription(), from(Product::getDescription)); + //@formatter:on + } +} + +class Product { + private Long id; + private String name; + private String description; + private boolean onSale; + private BigDecimal price; + private int stockQuantity; + + public Product(Long id, String name, String description, boolean onSale, BigDecimal price, int stockQuantity) { + this.id = id; + this.name = name; + this.description = description; + this.onSale = onSale; + this.price = price; + this.stockQuantity = stockQuantity; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public boolean isOnSale() { + return onSale; + } + + public BigDecimal getPrice() { + return price; + } + + public int getStockQuantity() { + return stockQuantity; + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AnnotationTestExampleUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AnnotationTestExampleUnitTest.java index b324910ab7..4e3e0b36a9 100644 --- a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AnnotationTestExampleUnitTest.java +++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AnnotationTestExampleUnitTest.java @@ -9,9 +9,10 @@ import org.junit.jupiter.api.Test; @Tag("annotations") @Tag("junit5") -public class AnnotationTestExampleUnitTest { +class AnnotationTestExampleUnitTest { + @Test - public void shouldRaiseAnException() throws Exception { + void shouldRaiseAnException() { Assertions.assertThrows(Exception.class, () -> { throw new Exception("This is my expected exception"); }); @@ -19,7 +20,7 @@ public class AnnotationTestExampleUnitTest { @Test @Disabled - public void shouldFailBecauseTimeout() throws InterruptedException { + void shouldFailBecauseTimeout() { Assertions.assertTimeout(Duration.ofMillis(1), () -> Thread.sleep(10)); } } diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AssertionsExampleUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AssertionsExampleUnitTest.java index 14b1162ecf..896c9dcd9e 100644 --- a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AssertionsExampleUnitTest.java +++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/AssertionsExampleUnitTest.java @@ -8,30 +8,28 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class AssertionsExampleUnitTest { + @Test @Disabled - public void shouldFailBecauseTheNumbersAreNotEqual() { + void shouldFailBecauseTheNumbersAreNotEqual() { Assertions.assertEquals(2, 3, "Numbers are not equal!"); } @Test @Disabled - public void shouldFailBecauseItsNotTrue_overloading() { + void shouldFailBecauseItsNotTrue_overloading() { Assertions.assertTrue(() -> { return false; }, () -> "It's not true!"); } @Test - public void shouldAssertAllTheGroup() { + void shouldAssertAllTheGroup() { List list = Arrays.asList(1, 2, 3); - Assertions.assertAll("List is not incremental", () -> Assertions.assertEquals(list.get(0) - .intValue(), 1), () -> Assertions.assertEquals( - list.get(1) - .intValue(), - 2), - () -> Assertions.assertEquals(list.get(2) - .intValue(), 3)); + Assertions.assertAll("List is not incremental", + () -> Assertions.assertEquals(list.get(0).intValue(), 1), + () -> Assertions.assertEquals(list.get(1).intValue(), 2), + () -> Assertions.assertEquals(list.get(2).intValue(), 3)); } } diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeAllAndAfterAllAnnotationsUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeAllAndAfterAllAnnotationsUnitTest.java index 68bb66657e..4087bb9b85 100644 --- a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeAllAndAfterAllAnnotationsUnitTest.java +++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeAllAndAfterAllAnnotationsUnitTest.java @@ -6,27 +6,27 @@ import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BeforeAllAndAfterAllAnnotationsUnitTest { +class BeforeAllAndAfterAllAnnotationsUnitTest { private static final Logger LOG = LoggerFactory.getLogger(BeforeAllAndAfterAllAnnotationsUnitTest.class); - + @BeforeAll - public static void setup() { + static void setup() { LOG.debug("startup - creating DB connection"); } @AfterAll - public static void tearDown() { + static void tearDown() { LOG.debug("closing DB connection"); } @Test - public void simpleTest() { + void simpleTest() { LOG.debug("simple test"); } @Test - public void anotherSimpleTest() { + void anotherSimpleTest() { LOG.debug("another simple test"); } } diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeEachAndAfterEachAnnotationsUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeEachAndAfterEachAnnotationsUnitTest.java index 283665798d..9da15cac27 100644 --- a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeEachAndAfterEachAnnotationsUnitTest.java +++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/BeforeEachAndAfterEachAnnotationsUnitTest.java @@ -1,37 +1,37 @@ package com.baeldung.migration.junit5; -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BeforeEachAndAfterEachAnnotationsUnitTest { +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BeforeEachAndAfterEachAnnotationsUnitTest { private static final Logger LOG = LoggerFactory.getLogger(BeforeEachAndAfterEachAnnotationsUnitTest.class); - + private List list; - - @BeforeEach - public void init() { + + @BeforeEach + void init() { LOG.debug("startup"); list = new ArrayList<>(Arrays.asList("test1", "test2")); } @AfterEach - public void teardown() { + void teardown() { LOG.debug("teardown"); list.clear(); } @Test - public void whenCheckingListSize_ThenSizeEqualsToInit() { + void whenCheckingListSize_thenSizeEqualsToInit() { LOG.debug("executing test"); assertEquals(2, list.size()); @@ -39,7 +39,7 @@ public class BeforeEachAndAfterEachAnnotationsUnitTest { } @Test - public void whenCheckingListSizeAgain_ThenSizeEqualsToInit() { + public void whenCheckingListSizeAgain_thenSizeEqualsToInit() { LOG.debug("executing another test"); assertEquals(2, list.size()); diff --git a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/RuleExampleUnitTest.java b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/RuleExampleUnitTest.java index 5c878ef7d3..7e86cff003 100644 --- a/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/RuleExampleUnitTest.java +++ b/testing-modules/junit-5-basics/src/test/java/com/baeldung/migration/junit5/RuleExampleUnitTest.java @@ -8,12 +8,12 @@ import org.slf4j.LoggerFactory; import com.baeldung.migration.junit5.extensions.TraceUnitExtension; @ExtendWith(TraceUnitExtension.class) -public class RuleExampleUnitTest { +class RuleExampleUnitTest { private static final Logger LOGGER = LoggerFactory.getLogger(RuleExampleUnitTest.class); - + @Test - public void whenTracingTests() { + void whenTracingTests() { LOGGER.debug("This is my test"); /*...*/ } diff --git a/testing-modules/junit-5/README.md b/testing-modules/junit-5/README.md index 9f1fd53ee5..6bd95cd9fc 100644 --- a/testing-modules/junit-5/README.md +++ b/testing-modules/junit-5/README.md @@ -8,4 +8,4 @@ - [Determine the Execution Time of JUnit Tests](https://www.baeldung.com/junit-test-execution-time) - [@BeforeAll and @AfterAll in Non-Static Methods](https://www.baeldung.com/java-beforeall-afterall-non-static) - [The java.lang.NoClassDefFoundError in JUnit](https://www.baeldung.com/junit-noclassdeffounderror) -- [assertAll() vs Multiple Assertions in JUnit5](https://github.com/eugenp/tutorials/tree/master/testing-modules/junit-5) +- [assertAll() vs Multiple Assertions in JUnit5](https://www.baeldung.com/junit5-assertall-vs-multiple-assertions) diff --git a/testing-modules/junit5-annotations/README.md b/testing-modules/junit5-annotations/README.md index 6fd524592b..49d596607c 100644 --- a/testing-modules/junit5-annotations/README.md +++ b/testing-modules/junit5-annotations/README.md @@ -8,3 +8,4 @@ This module contains articles about JUnit 5 Annotations - [JUnit5 Programmatic Extension Registration with @RegisterExtension](https://www.baeldung.com/junit-5-registerextension-annotation) - [Guide to JUnit 5 Parameterized Tests](https://www.baeldung.com/parameterized-tests-junit-5) - [Writing Templates for Test Cases Using JUnit 5](https://www.baeldung.com/junit5-test-templates) +- [JUnit 5 @Nested Test Classes](https://www.baeldung.com/junit-5-nested-test-classes) diff --git a/testing-modules/junit5-annotations/pom.xml b/testing-modules/junit5-annotations/pom.xml index a4035a23f1..847baa827c 100644 --- a/testing-modules/junit5-annotations/pom.xml +++ b/testing-modules/junit5-annotations/pom.xml @@ -15,6 +15,12 @@ + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + org.junit.platform junit-platform-engine @@ -39,7 +45,7 @@ - 2.17.1 + 2.19.0 \ No newline at end of file diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Article.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Article.java new file mode 100644 index 0000000000..6beac24827 --- /dev/null +++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Article.java @@ -0,0 +1,19 @@ +package com.baeldung.junit5.nested; + +public class Article { + private String name; + private Membership articleLevel; + + public Article(String name, Membership articleLevel) { + this.name = name; + this.articleLevel = articleLevel; + } + + public String getName() { + return name; + } + + public Membership getArticleLevel() { + return articleLevel; + } +} \ No newline at end of file diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Membership.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Membership.java new file mode 100644 index 0000000000..de8e6f1fc8 --- /dev/null +++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Membership.java @@ -0,0 +1,16 @@ +package com.baeldung.junit5.nested; + +public enum Membership { + FREE(0), SILVER(10), GOLD(20); + + private final int level; + + Membership(int level) { + this.level = level; + } + + public int compare(Membership other) { + return level - other.level; + } + +} \ No newline at end of file diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Publication.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Publication.java new file mode 100644 index 0000000000..bfadbd3fe8 --- /dev/null +++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/Publication.java @@ -0,0 +1,32 @@ +package com.baeldung.junit5.nested; + +import java.util.List; +import java.util.stream.Collectors; + +public class Publication { + private final List

articles; + + public Publication(List
articles) { + this.articles = articles; + } + + public List getReadableArticles(User user) { + return articles.stream() + .filter(a -> a.getArticleLevel() + .compare(user.getMembership()) <= 0) + .map(Article::getName) + .collect(Collectors.toList()); + } + + public List getLockedArticles(User user) { + return articles.stream() + .filter(a -> a.getArticleLevel() + .compare(user.getMembership()) > 0) + .map(Article::getName) + .collect(Collectors.toList()); + } + + public List
getArticles() { + return articles; + } +} \ No newline at end of file diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/User.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/User.java new file mode 100644 index 0000000000..3e9d7ebeff --- /dev/null +++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/nested/User.java @@ -0,0 +1,19 @@ +package com.baeldung.junit5.nested; + +public class User { + private String name; + private Membership membership; + + public User(String name, Membership membership) { + this.name = name; + this.membership = membership; + } + + public String getName() { + return name; + } + + public Membership getMembership() { + return membership; + } +} \ No newline at end of file diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/NestedUnitTest.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/NestedUnitTest.java new file mode 100644 index 0000000000..e30094cc9d --- /dev/null +++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/NestedUnitTest.java @@ -0,0 +1,41 @@ +package com.baeldung.junit5.nested; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class NestedUnitTest { + + @BeforeEach + void beforeEach() { + System.out.println("NestedUnitTest.beforeEach()"); + } + + @Nested + class FirstNestedClass { + @BeforeEach + void beforeEach() { + System.out.println("FirstNestedClass.beforeEach()"); + } + + @Test + void test() { + System.out.println("FirstNestedClass.test()"); + } + } + + + @Nested + class SecondNestedClass { + @BeforeEach + void beforeEach() { + System.out.println("SecondNestedClass.beforeEach()"); + } + + @Test + void test() { + System.out.println("SecondNestedClass.test()"); + } + } + +} diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/OnlinePublicationUnitTest.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/OnlinePublicationUnitTest.java new file mode 100644 index 0000000000..bf3f15ff4e --- /dev/null +++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/nested/OnlinePublicationUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.junit5.nested; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +@DisplayName("given a article publication with three articles") +class OnlinePublicationUnitTest { + private Publication publication; + + @BeforeEach + void setupArticlesAndPublication() { + Article freeArticle = new Article("free article", Membership.FREE); + Article silverArticle = new Article("silver level article", Membership.SILVER); + Article goldArticle = new Article("gold level article", Membership.GOLD); + publication = new Publication(Arrays.asList(freeArticle, silverArticle, goldArticle)); + } + + @Test + @DisplayName("then 3 articles are available") + void shouldHaveThreeArticlesInTotal() { + List
allArticles = publication.getArticles(); + assertThat(allArticles).hasSize(3); + } + + @Nested + @DisplayName("when a user with a 'free' membership logs in") + class UserWithAFreeMembership { + User freeFreya = new User("Freya", Membership.FREE); + + @Test + @DisplayName("then he should be able to read the 'free' articles") + void shouldOnlyReadFreeArticles() { + List articles = publication.getReadableArticles(freeFreya); + assertThat(articles).containsExactly("free article"); + } + + @Test + @DisplayName("then he shouldn't be able to read the 'silver' and 'gold' articles") + void shouldSeeSilverAndGoldLevelArticlesAsLocked() { + List articles = publication.getLockedArticles(freeFreya); + assertThat(articles).containsExactlyInAnyOrder("silver level article", "gold level article"); + } + } + + @Nested + @DisplayName("when a user with a 'silver' membership logs in") + class UserWithSilverMembership { + User silverSilvester = new User("Silvester", Membership.SILVER); + + @Test + @DisplayName("then he should be able to read the 'free' and 'silver' level articles") + void shouldOnlyReadFreeAndSilverLevelArticles() { + List articles = publication.getReadableArticles(silverSilvester); + assertThat(articles).containsExactlyInAnyOrder("free article", "silver level article"); + } + + @Test + @DisplayName("then he should see the 'gold' level articles as locked") + void shouldSeeGoldLevelArticlesAsLocked() { + List articles = publication.getLockedArticles(silverSilvester); + assertThat(articles).containsExactlyInAnyOrder("gold level article"); + } + } + + @Nested + @DisplayName("when a user with a 'gold' membership logs in") + class UserWithGoldMembership { + User goldenGeorge = new User("George", Membership.GOLD); + + @Test + @DisplayName("then he should be able to read all the articles") + void shouldSeeAllArticles() { + List articles = publication.getReadableArticles(goldenGeorge); + assertThat(articles).containsExactlyInAnyOrder("free article", "silver level article", "gold level article"); + } + + @Test + @DisplayName("then he should not see any article as locked") + void shouldNotHaveHiddenArticles() { + List articles = publication.getLockedArticles(goldenGeorge); + assertThat(articles).isEmpty(); + } + + } + +} \ No newline at end of file diff --git a/testing-modules/mockito-2/pom.xml b/testing-modules/mockito-2/pom.xml index 6ce6e8fca0..25e9fd51a2 100644 --- a/testing-modules/mockito-2/pom.xml +++ b/testing-modules/mockito-2/pom.xml @@ -1,22 +1,15 @@ + 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 + mockito-2 + testing-modules com.baeldung 1.0.0-SNAPSHOT - 4.0.0 - - mockito-2 - - - 8 - 8 - UTF-8 - 4.8.1 - @@ -27,4 +20,11 @@ + + 8 + 8 + UTF-8 + 4.8.1 + + \ No newline at end of file diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java index df3561d646..d611cd9e45 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java @@ -1,6 +1,7 @@ package com.baeldung.app.rest; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.AdditionalMatchers.or; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -10,18 +11,18 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.exceptions.misusing.InvalidUseOfMatchersException; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import com.baeldung.app.api.Flower; import com.baeldung.domain.service.FlowerService; -@RunWith(MockitoJUnitRunner.class) -public class FlowerControllerUnitTest { +@ExtendWith(MockitoExtension.class) +class FlowerControllerUnitTest { @InjectMocks private FlowerController flowerController; @@ -30,7 +31,7 @@ public class FlowerControllerUnitTest { private FlowerService flowerService; @Test - public void givenPoppyFlower_whenUsingDoReturn_thenCorrect() { + void givenPoppyFlower_whenUsingDoReturn_thenCorrect() { doReturn("Flower").when(flowerService).analyze("poppy"); String response = flowerController.isAFlower("poppy"); @@ -38,25 +39,27 @@ public class FlowerControllerUnitTest { } @Test - public void givenAnyString_whenUsingArgumentMatcher_thenCorrect() { + void givenAnyString_whenUsingArgumentMatcher_thenCorrect() { when(flowerService.analyze(anyString())).thenReturn("Flower"); String response = flowerController.isAFlower("violetta"); assertThat(response).isEqualTo("Flower"); } - @Test(expected = InvalidUseOfMatchersException.class) - public void whenIncorrectMatchers_thenThrowsError() { - when(flowerService.isABigFlower("poppy", anyInt())).thenReturn(true); + @Test + void whenIncorrectMatchers_thenThrowsError() { + assertThrows(InvalidUseOfMatchersException.class, () -> { + when(flowerService.isABigFlower("poppy", anyInt())).thenReturn(true); + }); Flower flower = new Flower("poppy", 15); Boolean response = flowerController.isABigFlower(flower); - assertThat(response).isTrue(); + assertThat(response).isFalse(); } @Test - public void whenCorrectMatchers_thenCorrect() { + void whenCorrectMatchers_thenCorrect() { when(flowerService.isABigFlower(eq("poppy"), anyInt())).thenReturn(true); Flower flower = new Flower("poppy", 15); @@ -65,23 +68,25 @@ public class FlowerControllerUnitTest { assertThat(response).isTrue(); } - @Test(expected = InvalidUseOfMatchersException.class) - public void whenUsingMatchersAsReturnValue_thenThrowsError() { + @Test + void whenUsingMatchersAsReturnValue_thenThrowsError() { flowerController.isAFlower("poppy"); String orMatcher = or(eq("poppy"), endsWith("y")); - verify(flowerService).analyze(orMatcher); + assertThrows(InvalidUseOfMatchersException.class, () -> { + verify(flowerService).analyze(orMatcher); + }); } @Test - public void whenUsingMatchersAsOngoingStubbing_thenCorrect1() { + void whenUsingMatchersAsOngoingStubbing_thenCorrect1() { flowerController.isAFlower("poppy"); verify(flowerService).analyze(or(eq("poppy"), endsWith("y"))); } @Test - public void whenUsingMatchersAsOngoingStubbing_thenCorrect2() { + void whenUsingMatchersAsOngoingStubbing_thenCorrect2() { flowerController.isAFlower("lily"); verify(flowerService).analyze(or(eq("poppy"), endsWith("y"))); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java index 1bfbeecfec..84b5bf241e 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java @@ -5,52 +5,52 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import com.baeldung.app.api.MessageDTO; import com.baeldung.domain.model.Message; import com.baeldung.domain.service.MessageService; import com.baeldung.domain.util.MessageMatcher; -@RunWith(MockitoJUnitRunner.class) -public class MessageControllerUnitTest { +@ExtendWith(MockitoExtension.class) +class MessageControllerUnitTest { - @InjectMocks - private MessageController messageController; - - @Mock - private MessageService messageService; + @InjectMocks + private MessageController messageController; - @Test - public void givenMsg_whenVerifyUsingAnyMatcher_thenOk() { - MessageDTO messageDTO = new MessageDTO(); - messageDTO.setFrom("me"); - messageDTO.setTo("you"); - messageDTO.setText("Hello, you!"); + @Mock + private MessageService messageService; - messageController.createMessage(messageDTO); + @Test + void givenMsg_whenVerifyUsingAnyMatcher_thenOk() { + MessageDTO messageDTO = new MessageDTO(); + messageDTO.setFrom("me"); + messageDTO.setTo("you"); + messageDTO.setText("Hello, you!"); - verify(messageService, times(1)).deliverMessage(any(Message.class)); - } + messageController.createMessage(messageDTO); - @Test - public void givenMsg_whenVerifyUsingMessageMatcher_thenOk() { - MessageDTO messageDTO = new MessageDTO(); - messageDTO.setFrom("me"); - messageDTO.setTo("you"); - messageDTO.setText("Hello, you!"); + verify(messageService, times(1)).deliverMessage(any(Message.class)); + } - messageController.createMessage(messageDTO); + @Test + void givenMsg_whenVerifyUsingMessageMatcher_thenOk() { + MessageDTO messageDTO = new MessageDTO(); + messageDTO.setFrom("me"); + messageDTO.setTo("you"); + messageDTO.setText("Hello, you!"); - Message message = new Message(); - message.setFrom("me"); - message.setTo("you"); - message.setText("Hello, you!"); + messageController.createMessage(messageDTO); - verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message))); - } + Message message = new Message(); + message.setFrom("me"); + message.setTo("you"); + message.setText("Hello, you!"); + + verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message))); + } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/junit5/mockito/UserServiceUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/junit5/mockito/UserServiceUnitTest.java index 8a350e5d9f..cc38d617b7 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/junit5/mockito/UserServiceUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/junit5/mockito/UserServiceUnitTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -13,7 +14,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; @@ -115,7 +115,7 @@ class UserServiceUnitTest { void givenUserWithExistingName_whenSaveUser_thenGiveUsernameAlreadyExistsError() { // Given user = new User("jerry", 12); - Mockito.reset(userRepository); + reset(userRepository); when(userRepository.isUsernameAlreadyExists(any(String.class))).thenReturn(true); // When diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinalsUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinalsUnitTest.java index 24ab67049f..a4b2bd03b4 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinalsUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockFinalsUnitTest.java @@ -4,12 +4,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class MockFinalsUnitTest { +class MockFinalsUnitTest { @Test - public void whenMockFinalMethodMockWorks() { + void whenMockFinalMethodMockWorks() { MyList myList = new MyList(); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java index bd68afac75..acfd87e047 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationUnitTest.java @@ -1,23 +1,27 @@ package com.baeldung.mockito; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) -public class MockitoAnnotationUnitTest { +@ExtendWith(MockitoExtension.class) +class MockitoAnnotationUnitTest { @Mock private List mockedList; @@ -36,61 +40,61 @@ public class MockitoAnnotationUnitTest { // tests @Test - public void whenNotUseMockAnnotation_thenCorrect() { - final List mockList = Mockito.mock(List.class); + void whenNotUseMockAnnotation_thenCorrect() { + final List mockList = mock(List.class); mockList.add("one"); - Mockito.verify(mockList).add("one"); + verify(mockList).add("one"); assertEquals(0, mockList.size()); - Mockito.when(mockList.size()).thenReturn(100); + when(mockList.size()).thenReturn(100); assertEquals(100, mockList.size()); } @Test - public void whenUseMockAnnotation_thenMockIsInjected() { + void whenUseMockAnnotation_thenMockIsInjected() { mockedList.add("one"); - Mockito.verify(mockedList).add("one"); + verify(mockedList).add("one"); assertEquals(0, mockedList.size()); - Mockito.when(mockedList.size()).thenReturn(100); + when(mockedList.size()).thenReturn(100); assertEquals(100, mockedList.size()); } @Test - public void whenNotUseSpyAnnotation_thenCorrect() { - final List spyList = Mockito.spy(new ArrayList()); + void whenNotUseSpyAnnotation_thenCorrect() { + final List spyList = spy(new ArrayList()); spyList.add("one"); spyList.add("two"); - Mockito.verify(spyList).add("one"); - Mockito.verify(spyList).add("two"); + verify(spyList).add("one"); + verify(spyList).add("two"); assertEquals(2, spyList.size()); - Mockito.doReturn(100).when(spyList).size(); + doReturn(100).when(spyList).size(); assertEquals(100, spyList.size()); } @Test - public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() { + void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() { spiedList.add("one"); spiedList.add("two"); - Mockito.verify(spiedList).add("one"); - Mockito.verify(spiedList).add("two"); + verify(spiedList).add("one"); + verify(spiedList).add("two"); assertEquals(2, spiedList.size()); - Mockito.doReturn(100).when(spiedList).size(); + doReturn(100).when(spiedList).size(); assertEquals(100, spiedList.size()); } @Test - public void whenNotUseCaptorAnnotation_thenCorrect() { - final List mockList = Mockito.mock(List.class); + void whenNotUseCaptorAnnotation_thenCorrect() { + final List mockList = mock(List.class); final ArgumentCaptor arg = ArgumentCaptor.forClass(String.class); mockList.add("one"); - Mockito.verify(mockList).add(arg.capture()); + verify(mockList).add(arg.capture()); assertEquals("one", arg.getValue()); } @@ -100,9 +104,9 @@ public class MockitoAnnotationUnitTest { ArgumentCaptor argCaptor; @Test - public void whenUseCaptorAnnotation_thenTheSame() { + void whenUseCaptorAnnotation_thenTheSame() { mockedList.add("one"); - Mockito.verify(mockedList).add(argCaptor.capture()); + verify(mockedList).add(argCaptor.capture()); assertEquals("one", argCaptor.getValue()); } @@ -114,8 +118,8 @@ public class MockitoAnnotationUnitTest { private MyDictionary dic = new MyDictionary(); @Test - public void whenUseInjectMocksAnnotation_thenCorrect() { - Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning"); + void whenUseInjectMocksAnnotation_thenCorrect() { + when(wordMap.get("aWord")).thenReturn("aMeaning"); assertEquals("aMeaning", dic.getMeaning("aWord")); } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java index 88a9410101..512f538a58 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest.java @@ -6,16 +6,18 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; + import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; + public class MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest { @Rule public MockitoRule initRule = MockitoJUnit.rule(); - + @Mock private List mockedList; @@ -23,6 +25,6 @@ public class MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest { public void whenUsingMockitoJUnitRule_thenMocksInitialized() { when(mockedList.size()).thenReturn(41); - assertThat(mockedList.size()).isEqualTo(41); + assertThat(mockedList).hasSize(41); } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java index 9d3a00f8b9..89a253c855 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsInjectIntoSpyUnitTest.java @@ -1,22 +1,28 @@ package com.baeldung.mockito; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.openMocks; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.Map; -import static org.junit.Assert.assertEquals; -@RunWith(MockitoJUnitRunner.class) -public class MockitoAnnotationsInjectIntoSpyUnitTest { +@ExtendWith(MockitoExtension.class) +class MockitoAnnotationsInjectIntoSpyUnitTest { - @Before + @BeforeEach public void init() { - MockitoAnnotations.openMocks(this); - spyDic = Mockito.spy(new MyDictionary(wordMap)); + openMocks(this); + spyDic = spy(new MyDictionary(wordMap)); } @Mock @@ -28,8 +34,8 @@ public class MockitoAnnotationsInjectIntoSpyUnitTest { private MyDictionary spyDic; @Test - public void whenUseInjectMocksAnnotation_thenCorrect() { - Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning"); + void whenUseInjectMocksAnnotation_thenCorrect() { + when(wordMap.get("aWord")).thenReturn("aMeaning"); assertEquals("aMeaning", spyDic.getMeaning("aWord")); } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsUninitializedUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsUninitializedUnitTest.java index ed50732183..10b0aa6626 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsUninitializedUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoAnnotationsUninitializedUnitTest.java @@ -1,18 +1,23 @@ package com.baeldung.mockito; -import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.Mockito; import java.util.List; -public class MockitoAnnotationsUninitializedUnitTest { +class MockitoAnnotationsUninitializedUnitTest { @Mock List mockedList; - @Test(expected = NullPointerException.class) - public void whenMockitoAnnotationsUninitialized_thenNPEThrown() { - Mockito.when(mockedList.size()).thenReturn(1); + @Test + void whenMockitoAnnotationsUninitialized_thenNPEThrown() { + assertThrows(NullPointerException.class, () -> { + when(mockedList.size()).thenReturn(1); + }); } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoExceptionUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoExceptionUnitTest.java index 7ed4fbdf37..843edd8d0a 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoExceptionUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoExceptionUnitTest.java @@ -1,57 +1,71 @@ package com.baeldung.mockito; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.junit.Test; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; -public class MockitoExceptionUnitTest { +@ExtendWith(MockitoExtension.class) +class MockitoExceptionUnitTest { - @Test(expected = NullPointerException.class) - public void whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() { + @Test + void whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() { MyDictionary dictMock = mock(MyDictionary.class); when(dictMock.getMeaning(anyString())).thenThrow(NullPointerException.class); + assertThrows(NullPointerException.class, () -> { + dictMock.getMeaning("word"); + }); - dictMock.getMeaning("word"); } - @Test(expected = IllegalStateException.class) - public void whenConfigVoidRetunMethodToThrowEx_thenExIsThrown() { + @Test + void whenConfigVoidRetunMethodToThrowEx_thenExIsThrown() { MyDictionary dictMock = mock(MyDictionary.class); doThrow(IllegalStateException.class).when(dictMock) .add(anyString(), anyString()); + assertThrows(IllegalStateException.class, () -> { + dictMock.add("word", "meaning"); + }); - dictMock.add("word", "meaning"); } - @Test(expected = NullPointerException.class) - public void whenConfigNonVoidRetunMethodToThrowExWithNewExObj_thenExIsThrown() { + @Test + void whenConfigNonVoidRetunMethodToThrowExWithNewExObj_thenExIsThrown() { MyDictionary dictMock = mock(MyDictionary.class); when(dictMock.getMeaning(anyString())).thenThrow(new NullPointerException("Error occurred")); + assertThrows(NullPointerException.class, () -> { + dictMock.getMeaning("word"); + }); - dictMock.getMeaning("word"); } - @Test(expected = IllegalStateException.class) - public void whenConfigVoidRetunMethodToThrowExWithNewExObj_thenExIsThrown() { + @Test + void whenConfigVoidRetunMethodToThrowExWithNewExObj_thenExIsThrown() { MyDictionary dictMock = mock(MyDictionary.class); doThrow(new IllegalStateException("Error occurred")).when(dictMock) .add(anyString(), anyString()); + assertThrows(IllegalStateException.class, () -> { + dictMock.add("word", "meaning"); + }); - dictMock.add("word", "meaning"); } // ===== - @Test(expected = NullPointerException.class) - public void givenSpy_whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() { + @Test + void givenSpy_whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() { MyDictionary dict = new MyDictionary(); MyDictionary spy = Mockito.spy(dict); - when(spy.getMeaning(anyString())).thenThrow(NullPointerException.class); - spy.getMeaning("word"); + assertThrows(NullPointerException.class, () -> { + spy.getMeaning("word"); + }); } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java index 6b2bae16c3..6e9167f0d0 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java @@ -10,16 +10,16 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.MockSettings; import org.mockito.exceptions.verification.TooFewActualInvocations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -public class MockitoMockUnitTest { +class MockitoMockUnitTest { @Test - public void whenUsingSimpleMock_thenCorrect() { + void whenUsingSimpleMock_thenCorrect() { MyList listMock = mock(MyList.class); when(listMock.add(anyString())).thenReturn(false); boolean added = listMock.add(randomAlphabetic(6)); @@ -29,7 +29,7 @@ public class MockitoMockUnitTest { } @Test - public void whenUsingMockWithName_thenCorrect() { + void whenUsingMockWithName_thenCorrect() { MyList listMock = mock(MyList.class, "myMock"); when(listMock.add(anyString())).thenReturn(false); listMock.add(randomAlphabetic(6)); @@ -47,7 +47,7 @@ public class MockitoMockUnitTest { } @Test - public void whenUsingMockWithAnswer_thenCorrect() { + void whenUsingMockWithAnswer_thenCorrect() { MyList listMock = mock(MyList.class, new CustomAnswer()); boolean added = listMock.add(randomAlphabetic(6)); @@ -56,7 +56,7 @@ public class MockitoMockUnitTest { } @Test - public void whenUsingMockWithSettings_thenCorrect() { + void whenUsingMockWithSettings_thenCorrect() { MockSettings customSettings = withSettings().defaultAnswer(new CustomAnswer()); MyList listMock = mock(MyList.class, customSettings); boolean added = listMock.add(randomAlphabetic(6)); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java index c3c5758950..a236fc7cfc 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java @@ -1,9 +1,11 @@ package com.baeldung.mockito; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -13,69 +15,71 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; -import org.mockito.Mockito; import org.mockito.exceptions.verification.NoInteractionsWanted; import com.google.common.collect.Lists; -public class MockitoVerifyExamplesUnitTest { +class MockitoVerifyExamplesUnitTest { // tests @Test - public final void givenInteractionWithMockOccurred_whenVerifyingInteraction_thenCorrect() { + final void givenInteractionWithMockOccurred_whenVerifyingInteraction_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.size(); verify(mockedList).size(); } @Test - public final void givenOneInteractionWithMockOccurred_whenVerifyingNumberOfInteractions_thenCorrect() { + final void givenOneInteractionWithMockOccurred_whenVerifyingNumberOfInteractions_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.size(); verify(mockedList, times(1)).size(); } @Test - public final void givenNoInteractionWithMockOccurred_whenVerifyingInteractions_thenCorrect() { + final void givenNoInteractionWithMockOccurred_whenVerifyingInteractions_thenCorrect() { final List mockedList = mock(MyList.class); verifyNoInteractions(mockedList); } @Test - public final void givenNoInteractionWithMethodOfMockOccurred_whenVerifyingInteractions_thenCorrect() { + final void givenNoInteractionWithMethodOfMockOccurred_whenVerifyingInteractions_thenCorrect() { final List mockedList = mock(MyList.class); verify(mockedList, times(0)).size(); } - @Test(expected = NoInteractionsWanted.class) - public final void givenUnverifiedInteraction_whenVerifyingNoUnexpectedInteractions_thenFail() { + @Test + final void givenUnverifiedInteraction_whenVerifyingNoUnexpectedInteractions_thenFail() { final List mockedList = mock(MyList.class); mockedList.size(); mockedList.clear(); verify(mockedList).size(); - verifyNoMoreInteractions(mockedList); + assertThrows(NoInteractionsWanted.class, () -> { + verifyNoMoreInteractions(mockedList); + }); + } @Test - public final void whenVerifyingOrderOfInteractions_thenCorrect() { + final void whenVerifyingOrderOfInteractions_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.size(); mockedList.add("a parameter"); mockedList.clear(); - final InOrder inOrder = Mockito.inOrder(mockedList); + final InOrder inOrder = inOrder(mockedList); inOrder.verify(mockedList).size(); inOrder.verify(mockedList).add("a parameter"); inOrder.verify(mockedList).clear(); } @Test - public final void whenVerifyingAnInteractionHasNotOccurred_thenCorrect() { + final void whenVerifyingAnInteractionHasNotOccurred_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.size(); @@ -83,7 +87,7 @@ public class MockitoVerifyExamplesUnitTest { } @Test - public final void whenVerifyingAnInteractionHasOccurredAtLeastOnce_thenCorrect() { + final void whenVerifyingAnInteractionHasOccurredAtLeastOnce_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.clear(); mockedList.clear(); @@ -96,7 +100,7 @@ public class MockitoVerifyExamplesUnitTest { // with arguments @Test - public final void whenVerifyingAnInteractionWithExactArgument_thenCorrect() { + final void whenVerifyingAnInteractionWithExactArgument_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.add("test"); @@ -104,7 +108,7 @@ public class MockitoVerifyExamplesUnitTest { } @Test - public final void whenVerifyingAnInteractionWithAnyArgument_thenCorrect() { + final void whenVerifyingAnInteractionWithAnyArgument_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.add("test"); @@ -112,7 +116,7 @@ public class MockitoVerifyExamplesUnitTest { } @Test - public final void whenVerifyingAnInteractionWithArgumentCapture_thenCorrect() { + final void whenVerifyingAnInteractionWithArgumentCapture_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.addAll(Lists.newArrayList("someElement")); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java index d110fff00f..c570629ccd 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoWhenThenExamplesUnitTest.java @@ -2,21 +2,24 @@ package com.baeldung.mockito; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import org.junit.Test; -import org.mockito.Mockito; +import org.junit.jupiter.api.Test; -public class MockitoWhenThenExamplesUnitTest { + +class MockitoWhenThenExamplesUnitTest { @Test - public final void whenMockReturnBehaviorIsConfigured_thenBehaviorIsVerified() { - final MyList listMock = Mockito.mock(MyList.class); + final void whenMockReturnBehaviorIsConfigured_thenBehaviorIsVerified() { + final MyList listMock = mock(MyList.class); when(listMock.add(anyString())).thenReturn(false); final boolean added = listMock.add(randomAlphabetic(6)); @@ -24,67 +27,79 @@ public class MockitoWhenThenExamplesUnitTest { } @Test - public final void whenMockReturnBehaviorIsConfigured2_thenBehaviorIsVerified() { - final MyList listMock = Mockito.mock(MyList.class); + final void whenMockReturnBehaviorIsConfigured2_thenBehaviorIsVerified() { + final MyList listMock = mock(MyList.class); doReturn(false).when(listMock).add(anyString()); final boolean added = listMock.add(randomAlphabetic(6)); assertThat(added).isFalse(); } - @Test(expected = IllegalStateException.class) - public final void givenMethodIsConfiguredToThrowException_whenCallingMethod_thenExceptionIsThrown() { - final MyList listMock = Mockito.mock(MyList.class); + @Test + final void givenMethodIsConfiguredToThrowException_whenCallingMethod_thenExceptionIsThrown() { + final MyList listMock = mock(MyList.class); when(listMock.add(anyString())).thenThrow(IllegalStateException.class); - listMock.add(randomAlphabetic(6)); + assertThrows(IllegalStateException.class, () -> { + listMock.add(randomAlphabetic(6)); + }); + } @Test - public final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingOnlyOnce_thenNoExceptionIsThrown() { - final MyList listMock = Mockito.mock(MyList.class); + final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingOnlyOnce_thenNoExceptionIsThrown() { + final MyList listMock = mock(MyList.class); when(listMock.add(anyString())).thenReturn(false).thenThrow(IllegalStateException.class); listMock.add(randomAlphabetic(6)); } - @Test(expected = NullPointerException.class) - public final void whenMethodHasNoReturnType_whenConfiguringBehaviorOfMethod_thenPossible() { - final MyList listMock = Mockito.mock(MyList.class); + @Test + final void whenMethodHasNoReturnType_whenConfiguringBehaviorOfMethod_thenPossible() { + final MyList listMock = mock(MyList.class); doThrow(NullPointerException.class).when(listMock).clear(); - listMock.clear(); + assertThrows(NullPointerException.class, () -> { + listMock.clear(); + }); + } - @Test(expected = IllegalStateException.class) - public final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingTwice_thenExceptionIsThrown() { - final MyList listMock = Mockito.mock(MyList.class); + @Test + final void givenBehaviorIsConfiguredToThrowExceptionOnSecondCall_whenCallingTwice_thenExceptionIsThrown() { + final MyList listMock = mock(MyList.class); when(listMock.add(anyString())).thenReturn(false).thenThrow(IllegalStateException.class); - listMock.add(randomAlphabetic(6)); - listMock.add(randomAlphabetic(6)); + assertThrows(IllegalStateException.class, () -> { + listMock.add(randomAlphabetic(6)); + listMock.add(randomAlphabetic(6)); + }); + } - @Test(expected = NullPointerException.class) - public final void givenSpy_whenConfiguringBehaviorOfSpy_thenCorrectlyConfigured() { + @Test + final void givenSpy_whenConfiguringBehaviorOfSpy_thenCorrectlyConfigured() { final MyList instance = new MyList(); - final MyList spy = Mockito.spy(instance); + final MyList spy = spy(instance); doThrow(NullPointerException.class).when(spy).size(); - spy.size(); + assertThrows(NullPointerException.class, () -> { + spy.size(); + }); + } @Test - public final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMethodIsCalled() { - final MyList listMock = Mockito.mock(MyList.class); + final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMethodIsCalled() { + final MyList listMock = mock(MyList.class); when(listMock.size()).thenCallRealMethod(); assertThat(listMock).hasSize(1); } @Test - public final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMethodIsCalled() { - final MyList listMock = Mockito.mock(MyList.class); + final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMethodIsCalled() { + final MyList listMock = mock(MyList.class); doAnswer(invocation -> "Always the same").when(listMock).get(anyInt()); final String element = listMock.get(1); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/argumentcaptor/EmailServiceUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/argumentcaptor/EmailServiceUnitTest.java index c757a8bfb9..36c26659a6 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/argumentcaptor/EmailServiceUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/argumentcaptor/EmailServiceUnitTest.java @@ -3,18 +3,20 @@ package com.baeldung.mockito.argumentcaptor; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) -public class EmailServiceUnitTest { +@ExtendWith(MockitoExtension.class) +class EmailServiceUnitTest { @Mock DeliveryPlatform platform; @@ -29,34 +31,34 @@ public class EmailServiceUnitTest { ArgumentCaptor credentialsCaptor; @Test - public void whenDoesNotSupportHtml_expectTextOnlyEmailFormat() { + void whenDoesNotSupportHtml_expectTextOnlyEmailFormat() { String to = "info@baeldung.com"; String subject = "Using ArgumentCaptor"; String body = "Hey, let'use ArgumentCaptor"; emailService.send(to, subject, body, false); - Mockito.verify(platform).deliver(emailCaptor.capture()); + verify(platform).deliver(emailCaptor.capture()); Email emailCaptorValue = emailCaptor.getValue(); assertThat(emailCaptorValue.getFormat()).isEqualTo(Format.TEXT_ONLY); } @Test - public void whenDoesSupportHtml_expectHTMLEmailFormat() { + void whenDoesSupportHtml_expectHTMLEmailFormat() { String to = "info@baeldung.com"; String subject = "Using ArgumentCaptor"; String body = "Hey, let'use ArgumentCaptor"; emailService.send(to, subject, body, true); - Mockito.verify(platform).deliver(emailCaptor.capture()); + verify(platform).deliver(emailCaptor.capture()); Email value = emailCaptor.getValue(); assertThat(value.getFormat()).isEqualTo(Format.HTML); } @Test - public void whenServiceRunning_expectUpResponse() { - Mockito.when(platform.getServiceStatus()).thenReturn("OK"); + void whenServiceRunning_expectUpResponse() { + when(platform.getServiceStatus()).thenReturn("OK"); ServiceStatus serviceStatus = emailService.checkServiceStatus(); @@ -64,8 +66,8 @@ public class EmailServiceUnitTest { } @Test - public void whenServiceNotRunning_expectDownResponse() { - Mockito.when(platform.getServiceStatus()).thenReturn("Error"); + void whenServiceNotRunning_expectDownResponse() { + when(platform.getServiceStatus()).thenReturn("Error"); ServiceStatus serviceStatus = emailService.checkServiceStatus(); @@ -73,26 +75,26 @@ public class EmailServiceUnitTest { } @Test - public void whenUsingArgumentMatcherForValidCredentials_expectTrue() { + void whenUsingArgumentMatcherForValidCredentials_expectTrue() { Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); - Mockito.when(platform.authenticate(Mockito.eq(credentials))).thenReturn(AuthenticationStatus.AUTHENTICATED); + when(platform.authenticate(eq(credentials))).thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials)); } @Test - public void whenUsingArgumentCaptorForValidCredentials_expectTrue() { + void whenUsingArgumentCaptorForValidCredentials_expectTrue() { Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); - Mockito.when(platform.authenticate(credentialsCaptor.capture())).thenReturn(AuthenticationStatus.AUTHENTICATED); + when(platform.authenticate(credentialsCaptor.capture())).thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials)); assertThat(credentialsCaptor.getValue()).isEqualTo(credentials); } @Test - public void whenNotAuthenticated_expectFalse() { + void whenNotAuthenticated_expectFalse() { Credentials credentials = new Credentials("baeldung", "incorrect_password", "incorrect_key"); - Mockito.when(platform.authenticate(Mockito.eq(credentials))).thenReturn(AuthenticationStatus.NOT_AUTHENTICATED); + when(platform.authenticate(eq(credentials))).thenReturn(AuthenticationStatus.NOT_AUTHENTICATED); assertFalse(emailService.authenticatedSuccessfully(credentials)); } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/mockedstatic/MockedStaticUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/mockedstatic/MockedStaticUnitTest.java index a212e6e3eb..309f066a87 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/mockedstatic/MockedStaticUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/mockedstatic/MockedStaticUnitTest.java @@ -2,9 +2,9 @@ package com.baeldung.mockito.mockedstatic; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; -import org.mockito.Mockito; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.mockStatic; import java.util.Arrays; @@ -14,7 +14,7 @@ class MockedStaticUnitTest { void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() { assertThat(StaticUtils.name()).isEqualTo("Baeldung"); - try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + try (MockedStatic utilities = mockStatic(StaticUtils.class)) { utilities.when(StaticUtils::name).thenReturn("Eugen"); assertThat(StaticUtils.name()).isEqualTo("Eugen"); } @@ -26,7 +26,7 @@ class MockedStaticUnitTest { void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() { assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); - try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + try (MockedStatic utilities = mockStatic(StaticUtils.class)) { utilities.when(() -> StaticUtils.range(2, 6)) .thenReturn(Arrays.asList(10, 11, 12)); diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoMisusingMockOrSpyUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoMisusingMockOrSpyUnitTest.java index b3f470427a..e1023c5e57 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoMisusingMockOrSpyUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoMisusingMockOrSpyUnitTest.java @@ -2,29 +2,30 @@ package com.baeldung.mockito.spy; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import java.util.ArrayList; import java.util.List; -import org.junit.Test; -import org.mockito.Mockito; +import org.junit.jupiter.api.Test; import org.mockito.exceptions.misusing.NotAMockException; -public class MockitoMisusingMockOrSpyUnitTest { +class MockitoMisusingMockOrSpyUnitTest { @Test - public void givenNotASpy_whenDoReturn_thenThrowNotAMock() { + void givenNotASpy_whenDoReturn_thenThrowNotAMock() { List list = new ArrayList(); - assertThatThrownBy(() -> Mockito.doReturn(100).when(list).size()) + assertThatThrownBy(() -> doReturn(100).when(list).size()) .isInstanceOf(NotAMockException.class) .hasMessageContaining("Argument passed to when() is not a mock!"); } @Test - public void givenASpy_whenDoReturn_thenNoError() { - final List spyList = Mockito.spy(new ArrayList<>()); + void givenASpy_whenDoReturn_thenNoError() { + final List spyList = spy(new ArrayList<>()); - assertThatNoException().isThrownBy(() -> Mockito.doReturn(100).when(spyList).size()); + assertThatNoException().isThrownBy(() -> doReturn(100).when(spyList).size()); } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoSpyUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoSpyUnitTest.java index 28ca0c327b..caef0c3b4b 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoSpyUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/spy/MockitoSpyUnitTest.java @@ -1,30 +1,33 @@ package com.baeldung.mockito.spy; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import java.util.ArrayList; import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class MockitoSpyUnitTest { @Test - public void whenSpyingOnList_thenCorrect() { + void whenSpyingOnList_thenCorrect() { final List list = new ArrayList(); - final List spyList = Mockito.spy(list); + final List spyList = spy(list); spyList.add("one"); spyList.add("two"); - Mockito.verify(spyList).add("one"); - Mockito.verify(spyList).add("two"); + verify(spyList).add("one"); + verify(spyList).add("two"); assertThat(spyList).hasSize(2); } @@ -33,43 +36,43 @@ public class MockitoSpyUnitTest { private List aSpyList = new ArrayList(); @Test - public void whenUsingTheSpyAnnotation_thenObjectIsSpied() { + void whenUsingTheSpyAnnotation_thenObjectIsSpied() { aSpyList.add("one"); aSpyList.add("two"); - Mockito.verify(aSpyList).add("one"); - Mockito.verify(aSpyList).add("two"); + verify(aSpyList).add("one"); + verify(aSpyList).add("two"); assertThat(aSpyList).hasSize(2); } @Test - public void whenStubASpy_thenStubbed() { + void whenStubASpy_thenStubbed() { final List list = new ArrayList(); - final List spyList = Mockito.spy(list); + final List spyList = spy(list); assertEquals(0, spyList.size()); - Mockito.doReturn(100).when(spyList).size(); + doReturn(100).when(spyList).size(); assertThat(spyList).hasSize(100); } @Test - public void whenCreateMock_thenCreated() { - final List mockedList = Mockito.mock(ArrayList.class); + void whenCreateMock_thenCreated() { + final List mockedList = mock(ArrayList.class); mockedList.add("one"); - Mockito.verify(mockedList).add("one"); + verify(mockedList).add("one"); assertThat(mockedList).hasSize(0); } @Test - public void whenCreateSpy_thenCreate() { - final List spyList = Mockito.spy(new ArrayList<>()); + void whenCreateSpy_thenCreate() { + final List spyList = spy(new ArrayList<>()); spyList.add("one"); - Mockito.verify(spyList).add("one"); + verify(spyList).add("one"); assertThat(spyList).hasSize(1); } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/voidmethods/MockitoVoidMethodsUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/voidmethods/MockitoVoidMethodsUnitTest.java index dddfaa4c37..9b8a713a15 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/voidmethods/MockitoVoidMethodsUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/voidmethods/MockitoVoidMethodsUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.mockito.voidmethods; -import static org.junit.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.isNull; @@ -12,34 +14,36 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import com.baeldung.mockito.MyList; -@RunWith(MockitoJUnitRunner.class) -public class MockitoVoidMethodsUnitTest { +@ExtendWith(MockitoExtension.class) +class MockitoVoidMethodsUnitTest { @Test - public void whenAddCalledVerified() { + void whenAddCalledVerified() { MyList myList = mock(MyList.class); myList.add(0, ""); verify(myList, times(1)).add(0, ""); } - @Test(expected = Exception.class) - public void givenNull_addThrows() { + @Test + void givenNull_addThrows() { MyList myList = mock(MyList.class); - doThrow().when(myList).add(isA(Integer.class), isNull()); + assertThrows(Exception.class, () -> { + doThrow().when(myList).add(isA(Integer.class), isNull()); + }); myList.add(0, null); } @Test - public void whenAddCalledValueCaptured() { + void whenAddCalledValueCaptured() { MyList myList = mock(MyList.class); ArgumentCaptor valueCapture = ArgumentCaptor.forClass(String.class); doNothing().when(myList).add(any(Integer.class), valueCapture.capture()); @@ -49,7 +53,7 @@ public class MockitoVoidMethodsUnitTest { } @Test - public void whenAddCalledAnswered() { + void whenAddCalledAnswered() { MyList myList = mock(MyList.class); doAnswer(invocation -> { Object arg0 = invocation.getArgument(0); @@ -64,7 +68,7 @@ public class MockitoVoidMethodsUnitTest { } @Test - public void whenAddCalledRealMethodCalled() { + void whenAddCalledRealMethodCalled() { MyList myList = mock(MyList.class); doCallRealMethod().when(myList).add(any(Integer.class), any(String.class)); myList.add(1, "real"); diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index f237d2d6fc..64546b5064 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -22,6 +22,7 @@ gatling groovy-spock hamcrest + instancio junit-4 junit-5-advanced junit-5-basics diff --git a/testing-modules/selenium-junit-testng/README.md b/testing-modules/selenium-junit-testng/README.md index ce56de65a1..65eb269056 100644 --- a/testing-modules/selenium-junit-testng/README.md +++ b/testing-modules/selenium-junit-testng/README.md @@ -7,6 +7,7 @@ - [Taking Screenshots With Selenium WebDriver](https://www.baeldung.com/java-selenium-screenshots) - [Running Selenium Scripts with JMeter](https://www.baeldung.com/selenium-jmeter) - [Fixing Selenium WebDriver Executable Path Error](https://www.baeldung.com/java-selenium-webdriver-path-error) +- [Handle Browser Tabs With Selenium](https://www.baeldung.com/java-handle-browser-tabs-selenium) #### Notes: - to run the live tests for the article *Fixing Selenium WebDriver Executable Path Error*, follow the manual setup described diff --git a/testing-modules/selenium-junit-testng/pom.xml b/testing-modules/selenium-junit-testng/pom.xml index cf7c121dc8..f0a2e43eeb 100644 --- a/testing-modules/selenium-junit-testng/pom.xml +++ b/testing-modules/selenium-junit-testng/pom.xml @@ -57,7 +57,7 @@ 6.10 - 3.141.59 + 4.6.0 1.5.4 5.3.0 diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java b/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java index b1b7754648..14b2db7fc8 100644 --- a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java +++ b/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java @@ -1,24 +1,22 @@ package com.baeldung.selenium.config; import java.io.File; +import java.time.Duration; import java.util.concurrent.TimeUnit; -import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; -import org.openqa.selenium.remote.DesiredCapabilities; public class SeleniumConfig { private WebDriver driver; public SeleniumConfig() { - Capabilities capabilities = DesiredCapabilities.firefox(); - driver = new FirefoxDriver(capabilities); + driver = new FirefoxDriver(); driver.manage() .timeouts() - .implicitlyWait(5, TimeUnit.SECONDS); + .implicitlyWait(Duration.ofSeconds(5)); } static { @@ -50,4 +48,4 @@ public class SeleniumConfig { public WebDriver getDriver() { return driver; } -} +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/tabs/TabHelper.java b/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/tabs/TabHelper.java new file mode 100644 index 0000000000..0ad91c51f0 --- /dev/null +++ b/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/tabs/TabHelper.java @@ -0,0 +1,76 @@ +package com.baeldung.selenium.tabs; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +import javax.annotation.Nonnull; +import java.util.Optional; +import java.util.Set; + +/** + * Helper class for browser tab handling. + */ +public class TabHelper { + + private final WebDriver driver; + + public TabHelper(@Nonnull final WebDriver driver) { + this.driver = driver; + } + + /** + * Switch to the given browser tab. + * + * @param destinationWindowHandle the window handle of the destination tab. + * @return the window handle of the current tab before switching. + */ + public String switchToTab(@Nonnull final String destinationWindowHandle) { + final String currentWindowHandle = driver.getWindowHandle(); + driver.switchTo().window(destinationWindowHandle); + return currentWindowHandle; + } + + /** + * Close all browser tabs except the given one. + * + * @param windowHandle the window handle of the tab that should stay open. + */ + public void closeAllTabsExcept(@Nonnull final String windowHandle) { + for (final String handle : driver.getWindowHandles()) { + if (!handle.equals(windowHandle)) { + driver.switchTo().window(handle); + driver.close(); + } + } + driver.switchTo().window(windowHandle); + } + + /** + * Close all browser tabs except the current active one. + */ + public void closeAllTabsExceptCurrent() { + final String currentWindow = driver.getWindowHandle(); + closeAllTabsExcept(currentWindow); + } + + /** + * Open the given link and switch to the new opened tab. + * If the link is not opened in a new tab then no switch will be performed. + * + * @param link By of the link to open. + * @return the window handle of the tab before switching. + */ + public String openLinkAndSwitchToNewTab(@Nonnull final By link) { + final String windowHandle = driver.getWindowHandle(); + final Set windowHandlesBefore = driver.getWindowHandles(); + + driver.findElement(link).click(); + final Set windowHandlesAfter = driver.getWindowHandles(); + windowHandlesAfter.removeAll(windowHandlesBefore); + + final Optional newWindowHandle = windowHandlesAfter.stream().findFirst(); + newWindowHandle.ifPresent(s -> driver.switchTo().window(s)); + + return windowHandle; + } +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java index de519a44fc..c6abda08ee 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java @@ -15,6 +15,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; +import java.time.Duration; +import java.time.temporal.ChronoUnit; public class SeleniumJavaScriptClickLiveTest { @@ -25,7 +27,7 @@ public class SeleniumJavaScriptClickLiveTest { public void setUp() { System.setProperty("webdriver.chrome.driver", new File("src/main/resources/chromedriver.mac").getAbsolutePath()); driver = new ChromeDriver(); - wait = new WebDriverWait(driver, 20); + wait = new WebDriverWait(driver, Duration.of(20, ChronoUnit.SECONDS)); } @After @@ -62,4 +64,4 @@ public class SeleniumJavaScriptClickLiveTest { executor.executeScript("arguments[0].click();", element); } -} +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java index 337e3b85fb..8906f89fba 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java @@ -9,17 +9,16 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import java.io.File; +import java.time.Duration; import java.util.Set; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.openqa.selenium.Capabilities; import org.openqa.selenium.Cookie; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; -import org.openqa.selenium.remote.DesiredCapabilities; public class SeleniumCookiesJUnitLiveTest { @@ -29,11 +28,10 @@ public class SeleniumCookiesJUnitLiveTest { @Before public void setUp() { System.setProperty("webdriver.gecko.driver", findFile("geckodriver.mac")); - - Capabilities capabilities = DesiredCapabilities.firefox(); - driver = new FirefoxDriver(capabilities); + + driver = new FirefoxDriver(); navUrl = "https://baeldung.com"; - driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); + driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5)); } private static String findFile(String filename) { @@ -123,4 +121,4 @@ public class SeleniumCookiesJUnitLiveTest { assertThat(overriddenCookie.getValue(), equalTo("foo")); } -} +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java index cf705bb81f..e1ecdb4fa4 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; +import java.time.Duration; import java.util.concurrent.TimeUnit; import javax.imageio.ImageIO; @@ -13,12 +14,10 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.openqa.selenium.By; -import org.openqa.selenium.Capabilities; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.remote.DesiredCapabilities; import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.Screenshot; @@ -33,17 +32,16 @@ public class TakeScreenShotSeleniumLiveTest { public static void setUp() { System.setProperty("webdriver.chrome.driver", resolveResourcePath("chromedriver.mac")); - Capabilities capabilities = DesiredCapabilities.chrome(); - driver = new ChromeDriver(capabilities); + driver = new ChromeDriver(); driver.manage() .timeouts() - .implicitlyWait(5, TimeUnit.SECONDS); + .implicitlyWait(Duration.ofSeconds(5)); driver.get("http://www.google.com/"); } @AfterClass - public static void tearDown() throws IOException { + public static void tearDown() { driver.close(); System.clearProperty("webdriver.chrome.driver"); @@ -82,4 +80,4 @@ public class TakeScreenShotSeleniumLiveTest { File file = new File("src/test/resources/" + filename); return file.getAbsolutePath(); } -} +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java new file mode 100644 index 0000000000..08708fb0bc --- /dev/null +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java @@ -0,0 +1,97 @@ +package com.baeldung.selenium.tabs; + +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WindowType; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +final class SeleniumTabsLiveTest extends SeleniumTestBase { + + private static final By LINK_TO_ATTRIBUTES_PAGE_XPATH = By.xpath("//a[.='Attributes in new page']"); + private static final By LINK_TO_ALERT_PAGE_XPATH = By.xpath("//a[.='Alerts In A New Window From JavaScript']"); + + private static final String MAIN_PAGE_URL = "https://testpages.herokuapp.com/styled/windows-test.html"; + private static final String ATTRIBUTES_PAGE_URL = "https://testpages.herokuapp.com/styled/attributes-test.html"; + private static final String ALERT_PAGE_URL = "https://testpages.herokuapp.com/styled/alerts/alert-test.html"; + + @Test + void givenOneTab_whenOpenTab_thenTwoTabsOpen() { + //given + driver.get(MAIN_PAGE_URL); + assertEquals(1, driver.getWindowHandles().size()); + + //when + driver.switchTo().newWindow(WindowType.TAB); + + //then + assertEquals(2, driver.getWindowHandles().size()); + } + + @Test + void givenOneTab_whenOpenLinkInTab_thenTwoTabsOpen() { + //given + driver.get(MAIN_PAGE_URL); + + //when + final String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH); + assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl()); + + //then + tabHelper.switchToTab(mainWindow); + assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl()); + assertEquals(2, driver.getWindowHandles().size()); + } + + @Test + void givenTwoTabs_whenCloseAllExceptMainTab_thenOneTabOpen() { + //given + driver.get(MAIN_PAGE_URL); + final String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH); + assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl()); + assertEquals(2, driver.getWindowHandles().size()); + + //when + tabHelper.closeAllTabsExcept(mainWindow); + + //then + assertEquals(1, driver.getWindowHandles().size()); + assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl()); + } + + @Test + void givenTwoTabs_whenSwitching_thenCorrectTabOpen() { + //given + driver.get(MAIN_PAGE_URL); + final String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH); + assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl()); + assertEquals(2, driver.getWindowHandles().size()); + + //when/then + final String secondWindow = tabHelper.switchToTab(mainWindow); + assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl()); + tabHelper.switchToTab(secondWindow); + assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl()); + } + + @Test + void givenThreeTabs_whenSwitching_thenCorrectTabOpen() { + //given + driver.get(MAIN_PAGE_URL); + final String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH); + final String secondWindow = tabHelper.switchToTab(mainWindow); + tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ALERT_PAGE_XPATH); + final String thirdWindow = driver.getWindowHandle(); + assertEquals(3, driver.getWindowHandles().size()); + + //when/then + tabHelper.switchToTab(mainWindow); + assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl()); + + tabHelper.switchToTab(secondWindow); + assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl()); + + tabHelper.switchToTab(thirdWindow); + assertEquals(ALERT_PAGE_URL, driver.getCurrentUrl()); + } +} \ No newline at end of file diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java new file mode 100644 index 0000000000..71efbb84da --- /dev/null +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java @@ -0,0 +1,55 @@ +package com.baeldung.selenium.tabs; + +import io.github.bonigarcia.wdm.WebDriverManager; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; + +/** + * Base class for Selenium Tests. This class handles the WebDriver setup and configuration. + * It takes care about closing all tabs except one after each test. After a test class it will close the browser. + */ +public class SeleniumTestBase { + + protected static WebDriver driver; + protected static TabHelper tabHelper; + + private static void setupChromeDriver() { + WebDriverManager.chromedriver().setup(); + driver = new ChromeDriver(); + options(); + tabHelper = new TabHelper(driver); + } + + private static void options() { + driver.manage().window().maximize(); + } + + /** + * Initializes the ChromeDriver before all tests. + */ + @BeforeAll + public static void init() { + setupChromeDriver(); + } + + /** + * After each test all tabs except the current tab will be closed. + */ + @AfterEach + public void closeTabs() { + tabHelper.closeAllTabsExceptCurrent(); + } + + /** + * After all tests the browser will be closed. + */ + @AfterAll + public static void cleanup() { + if (driver != null) { + driver.quit(); + } + } +} \ No newline at end of file diff --git a/testing-modules/spring-mockito/README.md b/testing-modules/spring-mockito/README.md index 3fda392c0f..73b102623f 100644 --- a/testing-modules/spring-mockito/README.md +++ b/testing-modules/spring-mockito/README.md @@ -4,3 +4,4 @@ This module contains articles about Spring with Mockito ### Relevant Articles: - [Injecting Mockito Mocks into Spring Beans](https://www.baeldung.com/injecting-mocks-in-spring) +- [SpringRunner vs MockitoJUnitRunner](https://www.baeldung.com/junit-springrunner-vs-mockitojunitrunner) diff --git a/testing-modules/spring-mockito/pom.xml b/testing-modules/spring-mockito/pom.xml index 36504ab306..6283ea2d1f 100644 --- a/testing-modules/spring-mockito/pom.xml +++ b/testing-modules/spring-mockito/pom.xml @@ -31,4 +31,5 @@ lombok + \ No newline at end of file diff --git a/testing-modules/spring-testing-2/README.md b/testing-modules/spring-testing-2/README.md index 434388d683..5bd1716609 100644 --- a/testing-modules/spring-testing-2/README.md +++ b/testing-modules/spring-testing-2/README.md @@ -2,5 +2,5 @@ - [Guide to @DynamicPropertySource in Spring](https://www.baeldung.com/spring-dynamicpropertysource) - [Concurrent Test Execution in Spring 5](https://www.baeldung.com/spring-5-concurrent-tests) -- [Spring 5 Testing with @EnabledIf Annotation](https://www.baeldung.com/spring-5-enabledIf) +- [Spring 5 Testing with @EnabledIf Annotation](https://www.baeldung.com/spring-5-enabledif) - [The Spring TestExecutionListener](https://www.baeldung.com/spring-testexecutionlistener) diff --git a/testing-modules/testing-assertions/src/test/java/com/baeldung/listassert/OrderAgnosticListComparisonUnitTest.java b/testing-modules/testing-assertions/src/test/java/com/baeldung/listassert/OrderAgnosticListComparisonUnitTest.java index bf278cea90..58b80ff07e 100644 --- a/testing-modules/testing-assertions/src/test/java/com/baeldung/listassert/OrderAgnosticListComparisonUnitTest.java +++ b/testing-modules/testing-assertions/src/test/java/com/baeldung/listassert/OrderAgnosticListComparisonUnitTest.java @@ -51,4 +51,12 @@ public class OrderAgnosticListComparisonUnitTest { assertThat(a).hasSameElementsAs(b); } + + @Test + void whenTestingForOrderAgnosticEqualityWithDuplicateElementsBothList_ShouldBeEqual() { + List a = Arrays.asList("a", "a", "b", "c"); + List b = Arrays.asList("a", "b", "a", "c"); + + assertThat(a).containsExactlyInAnyOrderElementsOf(b); + } } diff --git a/testing-modules/testing-libraries/pom.xml b/testing-modules/testing-libraries/pom.xml index f9443fa792..b7c9b8c0bd 100644 --- a/testing-modules/testing-libraries/pom.xml +++ b/testing-modules/testing-libraries/pom.xml @@ -90,6 +90,11 @@ + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs-plugin.version} + @@ -111,8 +116,9 @@ 4.8.0 3.0.0 1.19.0 - 1.0.0 + 1.2.1 2.4.3 + 3.0.5 \ No newline at end of file diff --git a/testing-modules/testing-libraries/src/test/java/com/baeldung/mutation/PalindromeUnitTest.java b/testing-modules/testing-libraries/src/test/java/com/baeldung/mutation/PalindromeUnitTest.java index 207077158e..92ddda2b6c 100644 --- a/testing-modules/testing-libraries/src/test/java/com/baeldung/mutation/PalindromeUnitTest.java +++ b/testing-modules/testing-libraries/src/test/java/com/baeldung/mutation/PalindromeUnitTest.java @@ -9,25 +9,25 @@ import com.baeldung.mutation.Palindrome; public class PalindromeUnitTest { @Test - public void whenEmptyString_thanAccept() { + public void whenEmptyString_thenAccept() { Palindrome palindromeTester = new Palindrome(); assertTrue(palindromeTester.isPalindrome("")); } @Test - public void whenPalindrom_thanAccept() { + public void whenPalindrom_thenAccept() { Palindrome palindromeTester = new Palindrome(); assertTrue(palindromeTester.isPalindrome("noon")); } @Test - public void whenNotPalindrom_thanReject(){ + public void whenNotPalindrom_thenReject(){ Palindrome palindromeTester = new Palindrome(); assertFalse(palindromeTester.isPalindrome("box")); } @Test - public void whenNearPalindrom_thanReject(){ + public void whenNearPalindrom_thenReject(){ Palindrome palindromeTester = new Palindrome(); assertFalse(palindromeTester.isPalindrome("neon")); } diff --git a/testing-modules/testng/README.md b/testing-modules/testng/README.md index a7e0e29d62..739cae1197 100644 --- a/testing-modules/testng/README.md +++ b/testing-modules/testng/README.md @@ -3,3 +3,4 @@ - [Introduction to TestNG](http://www.baeldung.com/testng) - [Custom Reporting with TestNG](http://www.baeldung.com/testng-custom-reporting) - [A Quick JUnit vs TestNG Comparison](https://www.baeldung.com/junit-vs-testng) +- [How to Run TestNG Tests on Jenkins](https://www.baeldung.com/ops/testng-jenkins) diff --git a/testing-modules/zerocode/pom.xml b/testing-modules/zerocode/pom.xml index bcd51bea85..15ef45be63 100644 --- a/testing-modules/zerocode/pom.xml +++ b/testing-modules/zerocode/pom.xml @@ -37,6 +37,7 @@ org.springframework.boot spring-boot-maven-plugin + ${spring.boot.version} it diff --git a/vaadin/pom.xml b/vaadin/pom.xml index 6976ff2a6a..aa37a2392a 100644 --- a/vaadin/pom.xml +++ b/vaadin/pom.xml @@ -184,8 +184,6 @@ 8.8.5 8.8.5 9.3.9.v20160517 - 1.8 - 1.8 local mytheme 3.0.0 diff --git a/web-modules/google-web-toolkit/pom.xml b/web-modules/google-web-toolkit/pom.xml index 2d5a1fa324..1fdb38f0a1 100644 --- a/web-modules/google-web-toolkit/pom.xml +++ b/web-modules/google-web-toolkit/pom.xml @@ -47,8 +47,8 @@ - + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes @@ -68,8 +68,8 @@ com.baeldung.Google_web_toolkit Google_web_toolkit true - + + ${maven.compiler.source} @@ -97,8 +97,9 @@ - + + + 1.8 1.8 2.8.2 diff --git a/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterManualTest.java b/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java similarity index 90% rename from web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterManualTest.java rename to web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java index b77901c8e2..64812f6935 100644 --- a/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterManualTest.java +++ b/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java @@ -7,11 +7,11 @@ import org.doctester.testbrowser.Response; import org.junit.Test; import ninja.NinjaDocTester; -public class ApiControllerDocTesterManualTest extends NinjaDocTester { +public class ApiControllerDocTesterUnitTest extends NinjaDocTester { String URL_INDEX = "/"; String URL_HELLO = "/hello"; - + @Test public void testGetIndex() { Response response = makeRequest(Request.GET().url(testServerUrl().path(URL_INDEX))); @@ -23,5 +23,5 @@ public class ApiControllerDocTesterManualTest extends NinjaDocTester { Response response = makeRequest(Request.GET().url(testServerUrl().path(URL_HELLO))); assertThat(response.payload, containsString("Bonjour, bienvenue dans Ninja Framework!")); } - + } diff --git a/web-modules/ninja/src/test/java/controllers/ApiControllerMockManualTest.java b/web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java similarity index 68% rename from web-modules/ninja/src/test/java/controllers/ApiControllerMockManualTest.java rename to web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java index 2fa76bca4e..8534fa0b0f 100644 --- a/web-modules/ninja/src/test/java/controllers/ApiControllerMockManualTest.java +++ b/web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java @@ -1,23 +1,23 @@ package controllers; import static org.junit.Assert.assertEquals; -import javax.inject.Inject; + import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import ninja.NinjaRunner; + +import ninja.NinjaTest; import ninja.Result; import services.UserService; -@RunWith(NinjaRunner.class) -public class ApiControllerMockManualTest { +public class ApiControllerMockUnitTest extends NinjaTest { - @Inject private UserService userService; + private UserService userService; - ApplicationController applicationController; + private ApplicationController applicationController; @Before public void setupTest() { + userService = this.ninjaTestServer.getInjector().getInstance(UserService.class); applicationController = new ApplicationController(); applicationController.userService = userService; } @@ -28,5 +28,5 @@ public class ApiControllerMockManualTest { System.out.println(result.getRenderable()); assertEquals(userService.getUserMap().toString(), result.getRenderable().toString()); } - + }