diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinder.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinder.java new file mode 100644 index 0000000000..bf4e785f29 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinder.java @@ -0,0 +1,43 @@ +package com.baeldung.algorithms.primeundernumber; + +import java.util.Arrays; + +public class LargestPrimeFinder { + + public static int findByBruteForce(int n) { + for (int i = n - 1; i >= 2; i--) { + if (isPrime(i)) { + return i; + } + } + return -1; // Return -1 if no prime number is found + } + + public static boolean isPrime(int number) { + for (int i = 2; i <= Math.sqrt(number); i++) { + if (number % i == 0) { + return false; + } + } + return true; + } + + public static int findBySieveOfEratosthenes(int n) { + boolean[] isPrime = new boolean[n]; + Arrays.fill(isPrime, true); + for (int p = 2; p*p < n; p++) { + if (isPrime[p]) { + for (int i = p * p; i < n; i += p) { + isPrime[i] = false; + } + } + } + + for (int i = n - 1; i >= 2; i--) { + if (isPrime[i]) { + return i; + } + } + return -1; + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinderUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinderUnitTest.java new file mode 100644 index 0000000000..f046431424 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/primeundernumber/LargestPrimeFinderUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.algorithms.primeundernumber; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class LargestPrimeFinderUnitTest { + + @Test + public void givenNormalCases_whenFindPrime_ThenFoundResult() { + assertEquals(7, LargestPrimeFinder.findByBruteForce(10)); + assertEquals(97, LargestPrimeFinder.findByBruteForce(100)); + assertEquals(7, LargestPrimeFinder.findBySieveOfEratosthenes(10)); + assertEquals(97, LargestPrimeFinder.findBySieveOfEratosthenes(100)); + } + + @Test + public void givenEdgeCases_whenFindPrime_ThenNotFoundResult() { + assertEquals(-1, LargestPrimeFinder.findByBruteForce(0)); + assertEquals(-1, LargestPrimeFinder.findByBruteForce(1)); + assertEquals(-1, LargestPrimeFinder.findByBruteForce(2)); + assertEquals(-1, LargestPrimeFinder.findBySieveOfEratosthenes(0)); + assertEquals(-1, LargestPrimeFinder.findBySieveOfEratosthenes(1)); + assertEquals(-1, LargestPrimeFinder.findBySieveOfEratosthenes(2)); + } + + @Test + public void givenLargeInput_whenFindPrime_ThenFoundResult() { + assertEquals(99991, LargestPrimeFinder.findByBruteForce(100000)); + assertEquals(99991, LargestPrimeFinder.findBySieveOfEratosthenes(100000)); + } +} diff --git a/algorithms-modules/algorithms-searching/README.md b/algorithms-modules/algorithms-searching/README.md index 7d10100832..394d14a06c 100644 --- a/algorithms-modules/algorithms-searching/README.md +++ b/algorithms-modules/algorithms-searching/README.md @@ -13,3 +13,4 @@ This module contains articles about searching algorithms. - [Range Search Algorithm in Java](https://www.baeldung.com/java-range-search) - [Fast Pattern Matching of Strings Using Suffix Tree in Java](https://www.baeldung.com/java-pattern-matching-suffix-tree) - [Find the Kth Smallest Element in Two Sorted Arrays in Java](https://www.baeldung.com/java-kth-smallest-element-in-sorted-arrays) +- [Find the First Non-repeating Element of a List](https://www.baeldung.com/java-list-find-first-non-repeating-element) diff --git a/apache-libraries-2/pom.xml b/apache-libraries-2/pom.xml index d188204208..2e7ef0344c 100644 --- a/apache-libraries-2/pom.xml +++ b/apache-libraries-2/pom.xml @@ -19,10 +19,29 @@ validation-api ${javax.validation.validation-api.version} + + org.apache.camel + camel-core + ${camel.version} + + + + org.apache.camel + camel-test-junit5 + ${camel.version} + test + + + + org.apache.camel + camel-main + ${camel.version} + 2.0.1.Final + 4.3.0 \ No newline at end of file diff --git a/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterBean.java b/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterBean.java new file mode 100644 index 0000000000..a28c3959a4 --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterBean.java @@ -0,0 +1,29 @@ +package com.baeldung.dynamicrouter; + +import org.apache.camel.ExchangeProperties; + +import java.util.Map; + +public class DynamicRouterBean { + public String route(String body, @ExchangeProperties Map properties) { + int invoked = (int) properties.getOrDefault("invoked", 0) + 1; + + properties.put("invoked", invoked); + + if (invoked == 1) { + switch (body.toLowerCase()) { + case "mock": + return "mock:dynamicRouter"; + case "direct": + return "mock:directDynamicRouter"; + case "seda": + return "mock:sedaDynamicRouter"; + case "file": + return "mock:fileDynamicRouter"; + default: + break; + } + } + return null; + } +} diff --git a/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterRoute.java b/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterRoute.java new file mode 100644 index 0000000000..875263f0b1 --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/dynamicrouter/DynamicRouterRoute.java @@ -0,0 +1,13 @@ +package com.baeldung.dynamicrouter; + +import org.apache.camel.builder.RouteBuilder; + +public class DynamicRouterRoute extends RouteBuilder { + + @Override + public void configure() { + + from("direct:dynamicRouter").dynamicRouter(method(DynamicRouterBean.class, "route")); + + } +} diff --git a/apache-libraries-2/src/test/java/dynamicrouter/DynamicRouterRouteUnitTest.java b/apache-libraries-2/src/test/java/dynamicrouter/DynamicRouterRouteUnitTest.java new file mode 100644 index 0000000000..6401fa4be2 --- /dev/null +++ b/apache-libraries-2/src/test/java/dynamicrouter/DynamicRouterRouteUnitTest.java @@ -0,0 +1,61 @@ +package dynamicrouter; + +import com.baeldung.dynamicrouter.DynamicRouterRoute; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +public class DynamicRouterRouteUnitTest extends CamelTestSupport { + + @Override + protected RoutesBuilder createRouteBuilder() { + return new DynamicRouterRoute(); + } + + @Test + void givenDynamicRouter_whenMockEndpointExpectedMessageCountOneAndMockAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException { + + MockEndpoint mockDynamicEndpoint = getMockEndpoint("mock:dynamicRouter"); + mockDynamicEndpoint.expectedMessageCount(1); + + template.send("direct:dynamicRouter", exchange -> exchange.getIn() + .setBody("mock")); + MockEndpoint.assertIsSatisfied(context); + } + + @Test + void givenDynamicRouter_whenMockEndpointExpectedMessageCountOneAndDirectAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException { + + MockEndpoint mockDynamicEndpoint = context.getEndpoint("mock:directDynamicRouter", MockEndpoint.class); + mockDynamicEndpoint.expectedMessageCount(1); + + template.send("direct:dynamicRouter", exchange -> exchange.getIn() + .setBody("direct")); + + MockEndpoint.assertIsSatisfied(context); + } + + @Test + void givenDynamicRouter_whenMockEndpointExpectedMessageCountOneAndSedaAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException { + + MockEndpoint mockDynamicEndpoint = context.getEndpoint("mock:sedaDynamicRouter", MockEndpoint.class); + mockDynamicEndpoint.expectedMessageCount(1); + + template.send("direct:dynamicRouter", exchange -> exchange.getIn() + .setBody("seda")); + MockEndpoint.assertIsSatisfied(context); + } + + @Test + void givenDynamicRouter_whenMockEndpointExpectedMessageCountOneAndBookAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException { + + MockEndpoint mockDynamicEndpoint = getMockEndpoint("mock:fileDynamicRouter"); + mockDynamicEndpoint.expectedMessageCount(1); + + template.send("direct:dynamicRouter", exchange -> exchange.getIn() + .setBody("file")); + MockEndpoint.assertIsSatisfied(context); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/README.md b/core-java-modules/core-java-arrays-operations-advanced-2/README.md index 17ffa2562d..88bda5c6d7 100644 --- a/core-java-modules/core-java-arrays-operations-advanced-2/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced-2/README.md @@ -1,2 +1,4 @@ ## Relevant Articles - [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) +- [Find the Equilibrium Indexes of an Array in Java](https://www.baeldung.com/java-equilibrium-index-array) +- [Moves Zeros to the End of an Array in Java](https://www.baeldung.com/java-array-sort-move-zeros-end) diff --git a/core-java-modules/core-java-collections-maps-7/README.md b/core-java-modules/core-java-collections-maps-7/README.md index 54668e13e5..4cecfdd580 100644 --- a/core-java-modules/core-java-collections-maps-7/README.md +++ b/core-java-modules/core-java-collections-maps-7/README.md @@ -7,4 +7,5 @@ - [Limiting the Max Size of a HashMap in Java](https://www.baeldung.com/java-hashmap-size-bound) - [How to Sort LinkedHashMap by Values in Java](https://www.baeldung.com/java-sort-linkedhashmap-using-values) - [How to Increment a Map Value in Java](https://www.baeldung.com/java-increment-map-value) +- [Collect Stream of entrySet() to a LinkedHashMap](https://www.baeldung.com/java-linkedhashmap-entryset-stream) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-6) diff --git a/core-java-modules/core-java-concurrency-2/README.md b/core-java-modules/core-java-concurrency-2/README.md index 5d05c900b8..033e476b23 100644 --- a/core-java-modules/core-java-concurrency-2/README.md +++ b/core-java-modules/core-java-concurrency-2/README.md @@ -8,3 +8,4 @@ - [How to Check if All Runnables Are Done](https://www.baeldung.com/java-runnables-check-status) - [Parallelize for Loop in Java](https://www.baeldung.com/java-for-loop-parallel) - [How to Effectively Unit Test CompletableFuture](https://www.baeldung.com/java-completablefuture-unit-test) +- [How to Collect All Results and Handle Exceptions With CompletableFuture in a Loop](https://www.baeldung.com/java-completablefuture-collect-results-handle-exceptions) diff --git a/core-java-modules/core-java-concurrency-2/src/test/java/com/baeldung/concurrent/completablefuture/CombiningCompletableFuturesUnitTest.java b/core-java-modules/core-java-concurrency-2/src/test/java/com/baeldung/concurrent/completablefuture/CombiningCompletableFuturesUnitTest.java new file mode 100644 index 0000000000..2c157b3ab2 --- /dev/null +++ b/core-java-modules/core-java-concurrency-2/src/test/java/com/baeldung/concurrent/completablefuture/CombiningCompletableFuturesUnitTest.java @@ -0,0 +1,90 @@ +package com.baeldung.concurrent.completablefuture; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +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 java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class CombiningCompletableFuturesUnitTest { + + private final Logger logger = mock(Logger.class); + + private static Stream clientData() { + return Stream.of( + Arguments.of(List.of("Good Resource"), 1, 0), + Arguments.of(List.of("Bad Resource"), 0, 1), + Arguments.of(List.of("Good Resource", "Bad Resource"), 1, 1), + Arguments.of(List.of("Good Resource", "Bad Resource", "Good Resource", "Bad Resource", "Good Resource"), 3, 2) + ); + } + + @ParameterizedTest + @MethodSource("clientData") + public void givenMicroserviceClient_whenMultipleCreateResource_thenCombineResults(List inputs, int successCount, int errorCount) { + MicroserviceClient mockMicroservice = mock(MicroserviceClient.class); + // Return an identifier of 123 on "Good Resource" + when(mockMicroservice.createResource("Good Resource")) + .thenReturn(CompletableFuture.completedFuture(123L)); + // Throw an exception on "Bad Resource" + when(mockMicroservice.createResource("Bad Resource")) + .thenReturn(CompletableFuture.failedFuture(new IllegalArgumentException("Bad Resource"))); + + // Given a list of CompletableFutures from our microservice calls... + List> clientCalls = new ArrayList<>(); + for (String resource : inputs) { + clientCalls.add(mockMicroservice.createResource(resource)); + } + + // When all CompletableFutures are completed (exceptionally or otherwise)... + Map> resultsByValidity = clientCalls.stream() + .map(this::handleFuture) + .collect(Collectors.partitioningBy(resourceId -> resourceId != -1L)); + + // Then the returned resource identifiers should match what is expected... + List validResults = resultsByValidity.getOrDefault(true, List.of()); + assertThat(validResults.size()).isEqualTo(successCount); + + // And the logger mock should be called once for each exception with the expected error message + List invalidResults = resultsByValidity.getOrDefault(false, List.of()); + assertThat(invalidResults.size()).isEqualTo(errorCount); + verify(logger, times(errorCount)) + .error(eq("Encountered error: java.lang.IllegalArgumentException: Bad Resource")); + } + + /** + * Completes the given CompletableFuture, handling any exceptions that are thrown. + * @param future the CompletableFuture to complete. + * @return the resource identifier (-1 if the request failed). + */ + private Long handleFuture(CompletableFuture future) { + return future + .exceptionally(this::handleError) + .join(); + } + + private Long handleError(Throwable throwable) { + logger.error("Encountered error: " + throwable); + return -1L; + } + + interface MicroserviceClient { + CompletableFuture createResource(String resourceName); + } + + interface Logger { + void error(String message); + } +} diff --git a/core-java-modules/core-java-date-operations-4/README.md b/core-java-modules/core-java-date-operations-4/README.md index 6f8bc6c4b8..0e9bc710c8 100644 --- a/core-java-modules/core-java-date-operations-4/README.md +++ b/core-java-modules/core-java-date-operations-4/README.md @@ -4,3 +4,4 @@ This module contains articles about date operations in Java. ### Relevant Articles: - [Calculate Number of Weekdays Between Two Dates in Java](https://www.baeldung.com/java-count-weekdays-between-two-dates) - [Convert Long to Date in Java](https://www.baeldung.com/java-long-date-conversion) +- [Convert Date to Unix Timestamp in Java](https://www.baeldung.com/java-convert-date-unix-timestamp) diff --git a/core-java-modules/core-java-datetime-conversion-2/pom.xml b/core-java-modules/core-java-datetime-conversion-2/pom.xml index 079df86a72..13849bc563 100644 --- a/core-java-modules/core-java-datetime-conversion-2/pom.xml +++ b/core-java-modules/core-java-datetime-conversion-2/pom.xml @@ -4,7 +4,6 @@ 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-datetime-conversion-2 - ${project.parent.version} core-java-datetime-conversion-2 jar diff --git a/core-java-modules/core-java-datetime-conversion/pom.xml b/core-java-modules/core-java-datetime-conversion/pom.xml index 17b5ff62ab..52ad29db5c 100644 --- a/core-java-modules/core-java-datetime-conversion/pom.xml +++ b/core-java-modules/core-java-datetime-conversion/pom.xml @@ -4,7 +4,6 @@ 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-datetime-conversion - ${project.parent.version} core-java-datetime-conversion jar diff --git a/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/math/rodcutting/RodCuttingProblem.java b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/math/rodcutting/RodCuttingProblem.java new file mode 100644 index 0000000000..ef10227edd --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/main/java/com/baeldung/math/rodcutting/RodCuttingProblem.java @@ -0,0 +1,72 @@ +package com.baeldung.math.rodcutting; + +import java.util.Arrays; + +public class RodCuttingProblem { + static int maxRevenueG; + public static int usingRecursion(int[] prices, int n) { + if (n <= 0) { + return 0; + } + int maxRevenue = Integer.MIN_VALUE; + + for (int i = 1; i <= n; i++) { + maxRevenue = Math.max(maxRevenue, prices[i - 1] + usingRecursion(prices, n - i)); + } + return maxRevenue; + } + + public static int usingMemoizedRecursion(int[] prices, int n) { + int[] memo = new int[n + 1]; + Arrays.fill(memo, -1); + + return memoizedHelper(prices, n, memo); + } + + private static int memoizedHelper(int[] prices, int n, int[] memo) { + if (n <= 0) { + return 0; + } + + if (memo[n] != -1) { + return memo[n]; + } + + int maxRevenue = Integer.MIN_VALUE; + + for (int i = 1; i <= n; i++) { + maxRevenue = Math.max(maxRevenue, prices[i - 1] + memoizedHelper(prices, n - i, memo)); + } + + memo[n] = maxRevenue; + return maxRevenue; + } + + public static int usingDynamicProgramming(int[] prices, int n) { + int[] dp = new int[n + 1]; + for (int i = 1; i <= n; i++) { + int maxRevenue = Integer.MIN_VALUE; + + for (int j = 1; j <= i; j++) { + maxRevenue = Math.max(maxRevenue, prices[j - 1] + dp[i - j]); + } + dp[i] = maxRevenue; + } + return dp[n]; + } + + public static int usingUnboundedKnapsack(int[] prices, int n) { + int[] dp = new int[n + 1]; + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < prices.length; j++) { + if (j + 1 <= i) { + dp[i] = Math.max(dp[i], dp[i - (j + 1)] + prices[j]); + } + } + } + + return dp[n]; + } + +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/math/rodcutting/RodCuttingProblemUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/math/rodcutting/RodCuttingProblemUnitTest.java new file mode 100644 index 0000000000..6ad16d5a5f --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/math/rodcutting/RodCuttingProblemUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.math.rodcutting; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class RodCuttingProblemUnitTest { + @Test + void givenARod_whenUsingRecursion_thenFindMaxRevenue() { + int[] prices = {1, 5, 8, 9}; + int rodLength = 4; + int maxRevenue = RodCuttingProblem.usingRecursion(prices, rodLength); + assertEquals(10, maxRevenue); + } + + @Test + void givenARod_whenUsingMemoizedRecursion_thenFindMaxRevenue() { + int[] prices = {1, 5, 8, 9}; + int rodLength = 4; + int maxRevenue = RodCuttingProblem.usingMemoizedRecursion(prices, rodLength); + assertEquals(10, maxRevenue); + } + + @Test + void givenARod_whenUsingDynamicProgramming_thenFindMaxRevenue() { + int[] prices = {1, 5, 8, 9}; + int rodLength = 4; + int maxRevenue = RodCuttingProblem.usingDynamicProgramming(prices, rodLength); + assertEquals(10, maxRevenue); + } + + @Test + void givenARod_whenUsingGreedy_thenFindMaxRevenue() { + int[] prices = {1, 5, 8, 9}; + int rodLength = 4; + int maxRevenue = RodCuttingProblem.usingUnboundedKnapsack(prices, rodLength); + assertEquals(10, maxRevenue); + } +} diff --git a/core-java-modules/core-java-lang-oop-patterns/README.md b/core-java-modules/core-java-lang-oop-patterns/README.md index 4e171483e6..7ea979435e 100644 --- a/core-java-modules/core-java-lang-oop-patterns/README.md +++ b/core-java-modules/core-java-lang-oop-patterns/README.md @@ -11,3 +11,4 @@ This module contains articles about Object-oriented programming (OOP) patterns i - [Should We Create an Interface for Only One Implementation?](https://www.baeldung.com/java-interface-single-implementation) - [How to Deep Copy an ArrayList in Java](https://www.baeldung.com/java-arraylist-deep-copy) - [Stateless Object in Java](https://www.baeldung.com/java-stateless-object) +- [Mutable vs. Immutable Objects in Java](https://www.baeldung.com/java-mutable-vs-immutable-objects) 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 4b93f8d192..52b05e95a4 100644 --- a/core-java-modules/core-java-lang-operators-2/README.md +++ b/core-java-modules/core-java-lang-operators-2/README.md @@ -11,3 +11,4 @@ This module contains articles about Java operators - [Alternatives for instanceof Operator in Java](https://www.baeldung.com/java-instanceof-alternatives) - [What Does “––>” Mean in Java?](https://www.baeldung.com/java-minus-minus-greaterthan) - [All the Ways Java Uses the Colon Character](https://www.baeldung.com/java-colon) +- [Convert Infix to Postfix Expressions in Java](https://www.baeldung.com/java-convert-infix-to-postfix-expressions) diff --git a/core-java-modules/core-java-networking-4/README.md b/core-java-modules/core-java-networking-4/README.md index 9b7e1b0f55..e62cab7c6e 100644 --- a/core-java-modules/core-java-networking-4/README.md +++ b/core-java-modules/core-java-networking-4/README.md @@ -6,3 +6,5 @@ - [URL Query Manipulation in Java](https://www.baeldung.com/java-url-query-manipulation) - [Understanding the java.net.SocketException Broken Pipe Error](https://www.baeldung.com/java-socketexception-broken-pipe-error) - [Normalize a URL in Java](https://www.baeldung.com/java-url-normalization) +- [Translating Space Characters in URLEncoder](https://www.baeldung.com/java-urlencoder-translate-space-characters) +- [Creating a Custom URL Connection](https://www.baeldung.com/java-custom-url-connection) diff --git a/core-java-modules/core-java-serialization/pom.xml b/core-java-modules/core-java-serialization/pom.xml index aecc66060d..5989dbf870 100644 --- a/core-java-modules/core-java-serialization/pom.xml +++ b/core-java-modules/core-java-serialization/pom.xml @@ -31,11 +31,6 @@ jackson-databind ${jackson.version} - - org.springframework - spring-core - ${spring.core.version} - org.springframework spring-core diff --git a/core-java-modules/core-java-streams-6/src/test/java/com/baeldung/streams/range/StreamRangeUnitTest.java b/core-java-modules/core-java-streams-6/src/test/java/com/baeldung/streams/range/StreamRangeUnitTest.java new file mode 100644 index 0000000000..2d0a2e8c12 --- /dev/null +++ b/core-java-modules/core-java-streams-6/src/test/java/com/baeldung/streams/range/StreamRangeUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.streams.range; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StreamRangeUnitTest { + + @Test + public void whenRangeStreamUsingLimitSkip_thenPrintsRange() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + List expectedRange = Arrays.asList(3, 4, 5, 6, 7); + + List range = numbers.stream() + .skip(2) + .limit(5) + .collect(Collectors.toList()); + + assertEquals(expectedRange, range); + } + + @Test + public void whenRangeStreamUsingCollectingAndThen_thenPrintsRange() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + List expectedRange = Arrays.asList(3, 4, 5, 6, 7); + + List range = numbers.stream() + .filter(n -> n >= 3 && n <= 7) + .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); + + assertEquals(expectedRange, range); + } +} diff --git a/core-java-modules/core-java-string-operations-7/README.md b/core-java-modules/core-java-string-operations-7/README.md index a358c8fa57..7264c3d945 100644 --- a/core-java-modules/core-java-string-operations-7/README.md +++ b/core-java-modules/core-java-string-operations-7/README.md @@ -15,3 +15,4 @@ - [Simple Morse Code Translation in Java](https://www.baeldung.com/java-morse-code-english-translate) - [How to Determine if a String Contains Invalid Encoded Characters](https://www.baeldung.com/java-check-string-contains-invalid-encoded-characters) - [Regular Expression for Password Validation in Java](https://www.baeldung.com/java-regex-password-validation) +- [Mask an Email Address and Phone Number in Java](https://www.baeldung.com/java-mask-email-address-phone-number) diff --git a/core-java-modules/core-java-string-operations-8/README.md b/core-java-modules/core-java-string-operations-8/README.md index 2dce44d217..7e961ed041 100644 --- a/core-java-modules/core-java-string-operations-8/README.md +++ b/core-java-modules/core-java-string-operations-8/README.md @@ -1,2 +1,2 @@ - -### Relevant Articles: +### Relevant Articles: +- [Count Uppercase and Lowercase Letters in a String](https://www.baeldung.com/java-string-count-letters-uppercase-lowercase) diff --git a/core-java-modules/core-java-string-operations-8/pom.xml b/core-java-modules/core-java-string-operations-8/pom.xml index 2495abccf8..a2f97a93d9 100644 --- a/core-java-modules/core-java-string-operations-8/pom.xml +++ b/core-java-modules/core-java-string-operations-8/pom.xml @@ -1,72 +1,34 @@ - - - 4.0.0 - core-java-string-operations-8 - core-java-string-operations-8 - jar - - - com.baeldung.core-java-modules - core-java-modules - 0.0.1-SNAPSHOT - - - - - org.apache.commons - commons-lang3 - ${apache.commons.lang3.version} - - - org.apache.commons - commons-text - ${commons-text.version} - - - org.liquibase - liquibase-core - 4.9.1 - test - - - org.junit.jupiter - junit-jupiter - 5.8.1 - test - - - org.liquibase - liquibase-core - 4.9.1 - test - - - junit - junit - 4.13.2 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven.compiler.source} - ${maven.compiler.target} - - - - - - - 11 - 11 - 3.13.0 - 1.10.0 - - - \ No newline at end of file + + + 4.0.0 + core-java-string-operations-8 + core-java-string-operations-8 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + 11 + 11 + + + diff --git a/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/checkifstringisbased64/CheckIfStringIsBased64UnitTest.java b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/checkifstringisbased64/CheckIfStringIsBased64UnitTest.java new file mode 100644 index 0000000000..fdb543b3f5 --- /dev/null +++ b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/checkifstringisbased64/CheckIfStringIsBased64UnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.checkifstringisbased64; + +import org.junit.jupiter.api.Test; + +import java.util.Base64; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.*; + +public class CheckIfStringIsBased64UnitTest { + + @Test + public void givenBase64EncodedString_whenDecoding_thenNoException() { + try { + Base64.getDecoder().decode("SGVsbG8gd29ybGQ="); + assertTrue(true); + } catch (IllegalArgumentException e) { + fail("Unexpected exception: " + e.getMessage()); + } + } + + @Test + public void givenNonBase64String_whenDecoding_thenCatchException() { + try { + Base64.getDecoder().decode("Hello world!"); + fail("Expected IllegalArgumentException was not thrown"); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + } + + @Test + public void givenString_whenOperatingRegex_thenCheckIfItIsBase64Encoded() { + Pattern BASE64_PATTERN = Pattern.compile( + "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + ); + + assertTrue(BASE64_PATTERN.matcher("SGVsbG8gd29ybGQ=").matches()); + } +} diff --git a/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/countupperandlowercasechars/CountUpperAndLowercaseCharsUnitTest.java b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/countupperandlowercasechars/CountUpperAndLowercaseCharsUnitTest.java new file mode 100644 index 0000000000..64e8b7ebbd --- /dev/null +++ b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/countupperandlowercasechars/CountUpperAndLowercaseCharsUnitTest.java @@ -0,0 +1,90 @@ +package com.baeldung.countupperandlowercasechars; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CountUpperAndLowercaseCharsUnitTest { + private static final String MY_STRING = "Hi, Welcome to Baeldung! Let's count letters!"; + + @Test + void whenUsingCountByCharacterRange_thenGetExpectedResult() { + LetterCount result = LetterCount.countByCharacterRange(MY_STRING); + assertEquals(4, result.getUppercaseCount()); + assertEquals(31, result.getLowercaseCount()); + } + + @Test + void whenUsingCountByCharacterIsLowerOrUpperCase_thenGetExpectedResult() { + LetterCount result = LetterCount.countByCharacterIsUpperLower(MY_STRING); + assertEquals(4, result.getUppercaseCount()); + assertEquals(31, result.getLowercaseCount()); + } + + @Test + void whenUsingCountByStreamApi_thenGetExpectedResult() { + LetterCount result = LetterCount.countByStreamAPI(MY_STRING); + assertEquals(4, result.getUppercaseCount()); + assertEquals(31, result.getLowercaseCount()); + } + + @Test + void whenUsingIsUpperCaseAndIsLowerCase_thenUnicodeCharactersCanBeChecked() { + assertTrue(Character.isLowerCase('ä')); + assertTrue(Character.isUpperCase('Ä')); + } +} + +class LetterCount { + private int uppercaseCount; + private int lowercaseCount; + + private LetterCount(int uppercaseCount, int lowercaseCount) { + this.uppercaseCount = uppercaseCount; + this.lowercaseCount = lowercaseCount; + } + + public static LetterCount countByCharacterRange(String input) { + int upperCount = 0; + int lowerCount = 0; + for (char c : input.toCharArray()) { + if (c >= 'A' && c <= 'Z') { + upperCount++; + } + if (c >= 'a' && c <= 'z') { + lowerCount++; + } + } + return new LetterCount(upperCount, lowerCount); + } + + public static LetterCount countByCharacterIsUpperLower(String input) { + int upperCount = 0; + int lowerCount = 0; + for (char c : input.toCharArray()) { + if (Character.isUpperCase(c)) { + upperCount++; + } + if (Character.isLowerCase(c)) { + lowerCount++; + } + } + return new LetterCount(upperCount, lowerCount); + } + + public static LetterCount countByStreamAPI(String input) { + return new LetterCount( + (int) input.chars().filter(Character::isUpperCase).count(), + (int) input.chars().filter(Character::isLowerCase).count() + ); + } + + public int getUppercaseCount() { + return uppercaseCount; + } + + public int getLowercaseCount() { + return lowercaseCount; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/findlargestnuminstring/FindLargestNumInStringUnitTest.java b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/findlargestnuminstring/FindLargestNumInStringUnitTest.java new file mode 100644 index 0000000000..634786704d --- /dev/null +++ b/core-java-modules/core-java-string-operations-8/src/test/java/com/baeldung/findlargestnuminstring/FindLargestNumInStringUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.findlargestnuminstring; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class FindLargestNumInStringUnitTest { + String inputString = "The numbers are 10, 20, and 5"; + int expectedLargestNumber = 20; + + @Test + public void givenInputString_whenUsingBasicApproach_thenFindingLargestNumber() { + String[] numbers = inputString.split("[^0-9]+"); + + int largestNumber = Integer.MIN_VALUE; + for (String number : numbers) { + if (!number.isEmpty()) { + int currentNumber = Integer.parseInt(number); + if (currentNumber > largestNumber) { + largestNumber = currentNumber; + } + } + } + assertEquals(expectedLargestNumber, largestNumber); + + } + + @Test + public void givenInputString_whenUsingRegularExpression_thenFindingLargestNumber() { + Pattern pattern = Pattern.compile("\\d+"); + Matcher matcher = pattern.matcher(inputString); + + int largestNumber = Integer.MIN_VALUE; + while (matcher.find()) { + int currentNumber = Integer.parseInt(matcher.group()); + if (currentNumber > largestNumber) { + largestNumber = currentNumber; + } + } + assertEquals(expectedLargestNumber, largestNumber); + + } + + @Test + public void givenInputString_whenUsingStreamAndLambdaExpression_thenFindingLargestNumber() { + int largestNumber = Arrays.stream(inputString.split("[^0-9]+")) + .filter(s -> !s.isEmpty()) + .mapToInt(Integer::parseInt) + .max() + .orElse(Integer.MIN_VALUE); + + assertEquals(expectedLargestNumber, largestNumber); + + } +} \ No newline at end of file diff --git a/jackson-modules/jackson-jr/pom.xml b/jackson-modules/jackson-jr/pom.xml index 7f806f0d89..868c3ee17f 100644 --- a/jackson-modules/jackson-jr/pom.xml +++ b/jackson-modules/jackson-jr/pom.xml @@ -18,18 +18,17 @@ com.fasterxml.jackson.jr jackson-jr-all - 2.15.2 + ${jackson.version} com.fasterxml.jackson.jr jackson-jr-annotation-support - 2.15.2 + ${jackson.version} org.projectlombok lombok - RELEASE - compile + ${lombok.version} @@ -44,4 +43,8 @@ + + 2.16.0 + + \ No newline at end of file diff --git a/json-modules/json-2/pom.xml b/json-modules/json-2/pom.xml index b9a75e8aff..2449d0ad62 100644 --- a/json-modules/json-2/pom.xml +++ b/json-modules/json-2/pom.xml @@ -112,12 +112,6 @@ commons-io 2.11.0 - - org.junit.jupiter - junit-jupiter - RELEASE - test - javax.annotation javax.annotation-api diff --git a/json-modules/json-conversion/README.md b/json-modules/json-conversion/README.md index a1851d9b7a..49c150264c 100644 --- a/json-modules/json-conversion/README.md +++ b/json-modules/json-conversion/README.md @@ -6,3 +6,4 @@ This module contains articles about JSON Conversions - [Convert JSON Array to Java List](https://www.baeldung.com/java-convert-json-array-to-list) - [Reading JSON Documents as Maps and Comparing Them](https://www.baeldung.com/java-json-maps-comparison) - [Convert Byte Array to JSON and Vice Versa in Java](https://www.baeldung.com/java-json-byte-array-conversion) +- [Preventing Gson from Expressing Integers as Floats](https://www.baeldung.com/java-gson-prevent-expressing-integers-as-floats) diff --git a/json-modules/json-conversion/src/main/java/com/baeldung/preventexpressingintasfloat/Main.java b/json-modules/json-conversion/src/main/java/com/baeldung/preventexpressingintasfloat/Main.java deleted file mode 100644 index c0f14fa73d..0000000000 --- a/json-modules/json-conversion/src/main/java/com/baeldung/preventexpressingintasfloat/Main.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.preventexpressingintasfloat; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Hashtable; - -public class Main { - public static String draft = "[{\"id\":4077395,\"field_id\":242566,\"body\":\"\"}, " + - "{\"id\":4077398,\"field_id\":242569,\"body\":[[273019,0],[273020,1],[273021,0]]}, " + - "{\"id\":4077399,\"field_id\":242570,\"body\":[[273022,0],[273023,1],[273024,0]]}]"; - - public static void main(String[] args) { - ArrayList> responses; - Type ResponseList = new TypeToken>>() { - }.getType(); - responses = new Gson().fromJson(draft, ResponseList); - System.out.println(responses); - } -} \ No newline at end of file diff --git a/json-modules/json-conversion/src/test/java/com/baeldung/preventexpressingintasfloat/PreventExpressingIntAsFloatUnitTest.java b/json-modules/json-conversion/src/test/java/com/baeldung/preventexpressingintasfloat/PreventExpressingIntAsFloatUnitTest.java index 6ada093ab3..558ee42e90 100644 --- a/json-modules/json-conversion/src/test/java/com/baeldung/preventexpressingintasfloat/PreventExpressingIntAsFloatUnitTest.java +++ b/json-modules/json-conversion/src/test/java/com/baeldung/preventexpressingintasfloat/PreventExpressingIntAsFloatUnitTest.java @@ -14,17 +14,24 @@ public class PreventExpressingIntAsFloatUnitTest { public String jsonString = "[{\"id\":4077395,\"field_id\":242566,\"body\":\"\"}, " + "{\"id\":4077398,\"field_id\":242569,\"body\":[[273019,0],[273020,1],[273021,0]]}, " + "{\"id\":4077399,\"field_id\":242570,\"body\":[[273022,0],[273023,1],[273024,0]]}]"; - public String expectedOutput = "[{body=, field_id=242566, id=4077395}, " + "{body=[[273019, 0], [273020, 1], [273021, 0]], field_id=242569, id=4077398}, " + "{body=[[273022, 0], [273023, 1], [273024, 0]], field_id=242570, id=4077399}]"; + public String defaultOutput = "[{body=, field_id=242566.0, id=4077395.0}, " + + "{body=[[273019.0, 0.0], [273020.0, 1.0], [273021.0, 0.0]], field_id=242569.0, id=4077398.0}, " + + "{body=[[273022.0, 0.0], [273023.0, 1.0], [273024.0, 0.0]], field_id=242570.0, id=4077399.0}]"; @Test - public void givenJsonString_whenUsingsetObjectToNumberStrategyMethod_thenValidateOutput() { - Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create(); - ArrayList> responses = gson.fromJson(jsonString, new TypeToken>>() { + public void givenJsonString_whenUsingSetObjectToNumberStrategyMethod_thenValidateOutput() { + Gson defaultGson = new Gson(); + ArrayList> defaultResponses = defaultGson.fromJson(jsonString, new TypeToken>>() { }.getType()); - assertEquals(expectedOutput, responses.toString()); + Gson customGson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create(); + ArrayList> customResponses = customGson.fromJson(jsonString, new TypeToken>>() { + }.getType()); + + assertEquals(defaultOutput, defaultResponses.toString()); + assertEquals(expectedOutput, customResponses.toString()); } } diff --git a/lightrun/lightrun-tasks-service/pom.xml b/lightrun/lightrun-tasks-service/pom.xml index 773c81a9d5..c27ef103b9 100644 --- a/lightrun/lightrun-tasks-service/pom.xml +++ b/lightrun/lightrun-tasks-service/pom.xml @@ -48,6 +48,7 @@ org.apache.activemq artemis-jms-server + ${activemq.version} org.springframework.boot @@ -65,4 +66,8 @@ + + 2.32.0 + + \ No newline at end of file diff --git a/maven-modules/maven-simple/README.md b/maven-modules/maven-simple/README.md index 783d58a3a0..150eefa3a8 100644 --- a/maven-modules/maven-simple/README.md +++ b/maven-modules/maven-simple/README.md @@ -10,3 +10,4 @@ Since this is a module tied to an e-book, it should **not** be moved or used to ### Relevant Articles - [Apache Maven Tutorial](https://www.baeldung.com/maven) +- [Run Maven From Java Code](https://www.baeldung.com/java-maven-run-program) diff --git a/metrics/pom.xml b/metrics/pom.xml index 40a1d95d0c..a8f5e113e8 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -88,7 +88,7 @@ 1.11.0 3.1.0 1.2.0 - 1.5.4 + 1.7.7 \ No newline at end of file diff --git a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java index 8341befb83..7521aabdbb 100644 --- a/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/micrometer/MicrometerAtlasManualTest.java @@ -282,7 +282,7 @@ public class MicrometerAtlasManualTest { Map expectedMicrometer = new TreeMap<>(); expectedMicrometer.put(2.5E7,1D); expectedMicrometer.put(3.0E8,1D); - expectedMicrometer.put(6.0E8,4D); + expectedMicrometer.put(6.0E8,1D); Map actualMicrometer = new TreeMap<>(); HistogramSnapshot snapshot = timer.takeSnapshot(); diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationManualTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationManualTest.java index 2f908531f6..c2c1f52365 100644 --- a/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationManualTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationManualTest.java @@ -8,6 +8,7 @@ import com.netflix.servo.monitor.Monitors; import com.netflix.servo.tag.BasicTag; import com.netflix.servo.tag.BasicTagList; import com.netflix.servo.tag.TagList; +import org.junit.Before; import org.junit.Test; import java.util.Iterator; @@ -24,6 +25,12 @@ import static org.junit.Assert.assertTrue; public class MetricAnnotationManualTest extends MetricTestBase { + static { + System.setProperty( + "com.netflix.servo.DefaultMonitorRegistry.registryClass", + "com.netflix.servo.jmx.JmxMonitorRegistry"); + } + @Monitor(name = "integerCounter", type = DataSourceType.COUNTER, description = "Total number of update operations.") private final AtomicInteger updateCount = new AtomicInteger(0); diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverManualTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverManualTest.java index 3bb421b3ef..af60623841 100644 --- a/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverManualTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverManualTest.java @@ -24,6 +24,12 @@ import static org.junit.Assert.assertThat; public class MetricObserverManualTest extends MetricTestBase { + static { + System.setProperty( + "com.netflix.servo.DefaultMonitorRegistry.registryClass", + "com.netflix.servo.jmx.JmxMonitorRegistry"); + } + @Test public void givenMetrics_whenRegister_thenMonitored() throws InterruptedException { Gauge gauge = new BasicGauge<>(MonitorConfig diff --git a/parent-boot-3/pom.xml b/parent-boot-3/pom.xml index d4ca41291d..f45e108f02 100644 --- a/parent-boot-3/pom.xml +++ b/parent-boot-3/pom.xml @@ -229,8 +229,8 @@ 3.3.0 3.3.0 2.22.2 - 3.1.5 - 5.8.2 + 3.2.2 + 5.10.2 0.9.17 1.4.4 2.0.3 diff --git a/persistence-modules/core-java-persistence-3/README.md b/persistence-modules/core-java-persistence-3/README.md index 6ca158560b..c3cc8d0713 100644 --- a/persistence-modules/core-java-persistence-3/README.md +++ b/persistence-modules/core-java-persistence-3/README.md @@ -1,2 +1,3 @@ ## Relevant Articles - [Convert ResultSet Into Map](https://www.baeldung.com/java-resultset-map) +- [Pagination With JDBC](https://www.baeldung.com/java-jdbc-pagination) diff --git a/persistence-modules/hibernate-annotations/README.md b/persistence-modules/hibernate-annotations/README.md index dad29edc32..663c39ea33 100644 --- a/persistence-modules/hibernate-annotations/README.md +++ b/persistence-modules/hibernate-annotations/README.md @@ -12,3 +12,4 @@ This module contains articles about Annotations used in Hibernate. - [@Immutable in Hibernate](https://www.baeldung.com/hibernate-immutable) - [Hibernate @CreationTimestamp and @UpdateTimestamp](https://www.baeldung.com/hibernate-creationtimestamp-updatetimestamp) - [Difference Between @JoinColumn and @PrimaryKeyJoinColumn in JPA](https://www.baeldung.com/java-jpa-join-vs-primarykeyjoin) +- [A Guide to the @SoftDelete Annotation in Hibernate](https://www.baeldung.com/java-hibernate-softdelete-annotation) diff --git a/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CodeGenerationIntegrationTest.java b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CodeGenerationIntegrationTest.java index 3ca0919eaa..72b6ab710a 100644 --- a/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CodeGenerationIntegrationTest.java +++ b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CodeGenerationIntegrationTest.java @@ -34,7 +34,7 @@ public class CodeGenerationIntegrationTest { Connection conn = DriverManager.getConnection("jdbc:h2:mem:tes;INIT=CREATE SCHEMA IF NOT EXISTS \"public\""); context = DSL.using(conn, SQLDialect.H2); - context.createTable(Author.AUTHOR) + context.createTableIfNotExists(Author.AUTHOR) .columns( Author.AUTHOR.ID, Author.AUTHOR.FIRST_NAME, @@ -42,7 +42,7 @@ public class CodeGenerationIntegrationTest { Author.AUTHOR.AGE ) .execute(); - context.createTable(Article.ARTICLE) + context.createTableIfNotExists(Article.ARTICLE) .columns( Article.ARTICLE.ID, Article.ARTICLE.TITLE, diff --git a/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudIntegrationTest.java b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudIntegrationTest.java index 0d8df27ccc..74c75dfeea 100644 --- a/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudIntegrationTest.java +++ b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudIntegrationTest.java @@ -37,7 +37,7 @@ public class CrudIntegrationTest { Connection conn = DriverManager.getConnection("jdbc:h2:mem:tes;INIT=CREATE SCHEMA IF NOT EXISTS \"public\""); context = DSL.using(conn, SQLDialect.H2); - context.createTable(Author.AUTHOR) + context.createTableIfNotExists(Author.AUTHOR) .columns( Author.AUTHOR.ID, Author.AUTHOR.FIRST_NAME, @@ -45,7 +45,7 @@ public class CrudIntegrationTest { Author.AUTHOR.AGE ) .execute(); - context.createTable(Article.ARTICLE) + context.createTableIfNotExists(Article.ARTICLE) .columns( Article.ARTICLE.ID, Article.ARTICLE.TITLE, diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Account.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Account.java new file mode 100644 index 0000000000..e70e699303 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Account.java @@ -0,0 +1,69 @@ +package com.baeldung.findby; + +import jakarta.persistence.*; + +import java.sql.Timestamp; + +@Entity +@Table(name = "ACCOUNTS") +public class Account { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_seq") + @SequenceGenerator(name = "accounts_seq", sequenceName = "accounts_seq", allocationSize = 1) + @Column(name = "user_id") + private int userId; + private String username; + private String password; + private String email; + private Timestamp createdOn; + private Timestamp lastLogin; + + @OneToOne + @JoinColumn(name = "permissions_id") + private Permission permission; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setEmail(String email) { + this.email = email; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + + public void setLastLogin(Timestamp lastLogin) { + this.lastLogin = lastLogin; + } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "Account{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", createdOn=" + createdOn + ", lastLogin=" + lastLogin + ", permission=" + permission + '}'; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountApplication.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountApplication.java new file mode 100644 index 0000000000..45d0560529 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.findby; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AccountApplication { + public static void main(String[] args) { + SpringApplication.run(AccountApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountRepository.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountRepository.java new file mode 100644 index 0000000000..b6504bff3c --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/AccountRepository.java @@ -0,0 +1,18 @@ +package com.baeldung.findby; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AccountRepository extends JpaRepository { + + Account findByEmail(String email); + + Account findByUsernameAndEmail(String username, String email); + + Account findByUsernameOrEmail(String username, String email); + + List findByUsernameInOrEmailIn(List usernames, List emails); +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Permission.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Permission.java new file mode 100644 index 0000000000..06c9d3d213 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/Permission.java @@ -0,0 +1,24 @@ +package com.baeldung.findby; + +import jakarta.persistence.*; + +@Entity +@Table(name = "PERMISSIONS") +public class Permission { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "permissions_id_sq") + @SequenceGenerator(name = "permissions_id_sq", sequenceName = "permissions_id_sq", allocationSize = 1) + private int id; + + private String type; + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "Permission{" + "id=" + id + ", type='" + type + '\'' + '}'; + } +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/PermissionRepository.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/PermissionRepository.java new file mode 100644 index 0000000000..294b81bd15 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/findby/PermissionRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.findby; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PermissionRepository extends JpaRepository { + Permission findByType(String type); +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/findby/AccountRepositoryUnitTest.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/findby/AccountRepositoryUnitTest.java new file mode 100644 index 0000000000..ce0a7d8f3e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/findby/AccountRepositoryUnitTest.java @@ -0,0 +1,105 @@ +package com.baeldung.boot.findby; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.findby.Account; +import com.baeldung.findby.AccountApplication; +import com.baeldung.findby.AccountRepository; +import com.baeldung.findby.Permission; +import com.baeldung.findby.PermissionRepository; + +@SpringBootTest(classes = AccountApplication.class) +public class AccountRepositoryUnitTest { + + @Autowired + private AccountRepository accountRepository; + + @Autowired + private PermissionRepository permissionRepository; + + @BeforeEach + void setup() { + saveAccount(); + } + + @AfterEach + void tearDown() { + accountRepository.deleteAll(); + permissionRepository.deleteAll(); + } + + @Test + void givenAccountInDb_whenPerformFindByEmail_thenReturnsAccount() { + String email = "test@test.com"; + Account account = accountRepository.findByEmail(email); + assertThat(account.getEmail()).isEqualTo(email); + } + + @Test + void givenAccountInDb_whenPerformFindByUsernameAndEmail_thenReturnsAccount() { + String email = "test@test.com"; + String username = "user_admin"; + Account account = accountRepository.findByUsernameAndEmail(username, email); + assertThat(account.getUsername()).isEqualTo(username); + assertThat(account.getEmail()).isEqualTo(email); + } + + @Test + void givenAccountInDb_whenPerformFindByUsernameOrEmail_thenReturnsAccount() { + String email = "test@test.com"; + String username = "user_editor"; + Account account = accountRepository.findByUsernameOrEmail(username, email); + assertThat(account.getUsername()).isNotEqualTo(username); + assertThat(account.getEmail()).isEqualTo(email); + } + + @Test + void givenAccountInDb_whenPerformFindByUsernameInOrEmailIn_thenReturnsAccounts() { + List emails = Arrays.asList("test@test.com", "abc@abc.com", "pqr@pqr.com"); + List usernames = Arrays.asList("user_editor", "user_admin"); + List byUsernameInOrEmailIn = accountRepository.findByUsernameInOrEmailIn(usernames, emails); + assertThat(byUsernameInOrEmailIn.size()).isEqualTo(1); + assertThat(byUsernameInOrEmailIn.get(0) + .getEmail()).isEqualTo("test@test.com"); + } + + private Permission getPermissions() { + Permission editor = new Permission(); + editor.setType("editor"); + permissionRepository.save(editor); + return editor; + } + + private void saveAccount() { + List> sampleRecords = Arrays.asList( + Arrays.asList("test@test.com", "user_admin"), + Arrays.asList("test1@test.com", "user_admin_1"), + Arrays.asList("test2@test.com", "user_admin_2") + ); + + sampleRecords.forEach(sampleRecord -> { + Account account = new Account(); + account.setEmail(sampleRecord.get(0)); + account.setUsername(sampleRecord.get(1)); + account.setPermission(getPermissions()); + account.setPassword(UUID.randomUUID() + .toString()); + account.setCreatedOn(Timestamp.from(Instant.now())); + account.setLastLogin(Timestamp.from(Instant.now())); + accountRepository.save(account); + System.out.println(account.toString()); + }); + } +} diff --git a/persistence-modules/spring-boot-persistence-4/README.md b/persistence-modules/spring-boot-persistence-4/README.md index 7011f492ca..746df92a0b 100644 --- a/persistence-modules/spring-boot-persistence-4/README.md +++ b/persistence-modules/spring-boot-persistence-4/README.md @@ -2,3 +2,4 @@ - [Scroll API in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-scroll-api) - [List vs. Set in @OneToMany JPA](https://www.baeldung.com/spring-jpa-onetomany-list-vs-set) - [N+1 Problem in Hibernate and Spring Data JPA](https://www.baeldung.com/spring-hibernate-n1-problem) +- [Get All Results at Once in a Spring Boot Paged Query Method](https://www.baeldung.com/spring-boot-paged-query-all-results) diff --git a/persistence-modules/spring-jooq/pom.xml b/persistence-modules/spring-jooq/pom.xml index 5f8ab7231c..1387635afe 100644 --- a/persistence-modules/spring-jooq/pom.xml +++ b/persistence-modules/spring-jooq/pom.xml @@ -194,6 +194,7 @@ 1.0.0 1.5 1.0.0 + 3.1.5 \ No newline at end of file diff --git a/persistence-modules/spring-mybatis/pom.xml b/persistence-modules/spring-mybatis/pom.xml index 6de7cef347..d179881710 100644 --- a/persistence-modules/spring-mybatis/pom.xml +++ b/persistence-modules/spring-mybatis/pom.xml @@ -84,6 +84,7 @@ 3.5.2 3.0.3 true + 3.1.5 \ No newline at end of file diff --git a/pom.xml b/pom.xml index dc2156faf8..6de6042906 100644 --- a/pom.xml +++ b/pom.xml @@ -328,12 +328,6 @@ - parent-boot-1 - parent-boot-2 - parent-spring-4 - parent-spring-5 - parent-spring-6 - core-java-modules/core-java-8 @@ -404,12 +398,6 @@ - parent-boot-1 - parent-boot-2 - parent-spring-4 - parent-spring-5 - parent-spring-6 - spring-4 spring-6 @@ -460,12 +448,6 @@ - parent-boot-1 - parent-boot-2 - parent-spring-4 - parent-spring-5 - parent-spring-6 - apache-spark jhipster-modules web-modules/restx @@ -498,12 +480,6 @@ - parent-boot-1 - parent-boot-2 - parent-spring-4 - parent-spring-5 - parent-spring-6 - core-java-modules/core-java-8 @@ -683,6 +659,11 @@ + parent-boot-1 + parent-boot-2 + parent-spring-4 + parent-spring-5 + parent-spring-6 akka-modules algorithms-modules apache-cxf-modules @@ -924,6 +905,11 @@ + parent-boot-1 + parent-boot-2 + parent-spring-4 + parent-spring-5 + parent-spring-6 akka-modules algorithms-modules apache-cxf-modules diff --git a/quarkus-modules/quarkus-virtual-threads/README.md b/quarkus-modules/quarkus-virtual-threads/README.md index e69de29bb2..4db48675bb 100644 --- a/quarkus-modules/quarkus-virtual-threads/README.md +++ b/quarkus-modules/quarkus-virtual-threads/README.md @@ -0,0 +1,2 @@ +### Relevant Articles +- [Quarkus and Virtual Threads](https://www.baeldung.com/java-quarkus-virtual-threads) diff --git a/spring-aop-2/README.md b/spring-aop-2/README.md index 0aa20d32f0..3553ed7888 100644 --- a/spring-aop-2/README.md +++ b/spring-aop-2/README.md @@ -8,4 +8,5 @@ This module contains articles about Spring aspect oriented programming (AOP) - [When Does Java Throw UndeclaredThrowableException?](https://www.baeldung.com/java-undeclaredthrowableexception) - [Get Advised Method Info in Spring AOP](https://www.baeldung.com/spring-aop-get-advised-method-info) - [Invoke Spring @Cacheable from Another Method of Same Bean](https://www.baeldung.com/spring-invoke-cacheable-other-method-same-bean) +- [Logging With AOP in Spring](https://www.baeldung.com/spring-aspect-oriented-programming-logging) - More articles: [[<-- prev]](/spring-aop) diff --git a/spring-aop-2/src/main/java/com/baeldung/logging/GreetingService.java b/spring-aop-2/src/main/java/com/baeldung/logging/GreetingService.java new file mode 100644 index 0000000000..1bdf3dc9d8 --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/logging/GreetingService.java @@ -0,0 +1,11 @@ +package com.baeldung.logging; + +import org.springframework.stereotype.Service; + +@Service +public class GreetingService { + + public String greet(String name) { + return String.format("Hello %s", name); + } +} diff --git a/spring-aop-2/src/main/java/com/baeldung/logging/GreetingServiceWithoutAOP.java b/spring-aop-2/src/main/java/com/baeldung/logging/GreetingServiceWithoutAOP.java new file mode 100644 index 0000000000..eee90af669 --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/logging/GreetingServiceWithoutAOP.java @@ -0,0 +1,18 @@ +package com.baeldung.logging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class GreetingServiceWithoutAOP { + + private static final Logger logger = LoggerFactory.getLogger(GreetingServiceWithoutAOP.class); + + public String greet(String name) { + logger.info(">> greet() - {}", name); + String result = String.format("Hello %s", name); + logger.info("<< greet() - {}", result); + return result; + } +} diff --git a/spring-aop-2/src/main/java/com/baeldung/logging/LoggingAspect.java b/spring-aop-2/src/main/java/com/baeldung/logging/LoggingAspect.java new file mode 100644 index 0000000000..6641b70eec --- /dev/null +++ b/spring-aop-2/src/main/java/com/baeldung/logging/LoggingAspect.java @@ -0,0 +1,55 @@ +package com.baeldung.logging; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +@Aspect +@Component +public class LoggingAspect { + + private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class); + + @Pointcut("execution(public * com.baeldung.logging.*.*(..))") + private void publicMethodsFromLoggingPackage() { + } + + @Before(value = "publicMethodsFromLoggingPackage()") + public void logBefore(JoinPoint joinPoint) { + Object[] args = joinPoint.getArgs(); + String methodName = joinPoint.getSignature().getName(); + logger.info(">> {}() - {}", methodName, Arrays.toString(args)); + } + + @AfterReturning(value = "publicMethodsFromLoggingPackage()", returning = "result") + public void logAfter(JoinPoint joinPoint, Object result) { + String methodName = joinPoint.getSignature().getName(); + logger.info("<< {}() - {}", methodName, result); + } + + @AfterThrowing(pointcut = "publicMethodsFromLoggingPackage()", throwing = "exception") + public void logException(JoinPoint joinPoint, Throwable exception) { + String methodName = joinPoint.getSignature().getName(); + logger.error("<< {}() - {}", methodName, exception.getMessage()); + } + + @Around(value = "publicMethodsFromLoggingPackage()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + Object[] args = joinPoint.getArgs(); + String methodName = joinPoint.getSignature().getName(); + logger.info(">> {}() - {}", methodName, Arrays.toString(args)); + Object result = joinPoint.proceed(); + logger.info("<< {}() - {}", methodName, result); + return result; + } +} diff --git a/spring-aop-2/src/test/java/com/baeldung/logging/GreetingServiceUnitTest.java b/spring-aop-2/src/test/java/com/baeldung/logging/GreetingServiceUnitTest.java new file mode 100644 index 0000000000..6a6c1c8a70 --- /dev/null +++ b/spring-aop-2/src/test/java/com/baeldung/logging/GreetingServiceUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.logging; + +import com.baeldung.Application; +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.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringBootTest(classes = Application.class) +class GreetingServiceUnitTest { + + @Autowired + private GreetingService greetingService; + + @Test + void givenName_whenGreet_thenReturnCorrectResult() { + String result = greetingService.greet("Baeldung"); + assertNotNull(result); + assertEquals("Hello Baeldung", result); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/pom.xml b/spring-boot-modules/spring-boot-properties/pom.xml index dc1ab067a9..7614941f2d 100644 --- a/spring-boot-modules/spring-boot-properties/pom.xml +++ b/spring-boot-modules/spring-boot-properties/pom.xml @@ -147,6 +147,7 @@ @ com.baeldung.yaml.MyApplication + 3.1.5 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml index 1f4e58f21f..8edbd9c79e 100644 --- a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml +++ b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml @@ -53,6 +53,7 @@ 5.0.3 + 3.1.5 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-eureka/pom.xml b/spring-cloud-modules/spring-cloud-eureka/pom.xml index 9966459a5c..686ca4f0e9 100644 --- a/spring-cloud-modules/spring-cloud-eureka/pom.xml +++ b/spring-cloud-modules/spring-cloud-eureka/pom.xml @@ -10,9 +10,10 @@ Spring Cloud Eureka Server and Sample Clients - com.baeldung.spring.cloud - spring-cloud-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -23,6 +24,10 @@ spring-cloud-eureka-server + + 2023.0.0 + + org.springframework.boot diff --git a/spring-jinq/pom.xml b/spring-jinq/pom.xml index ebac1c3112..4ba2028bc6 100644 --- a/spring-jinq/pom.xml +++ b/spring-jinq/pom.xml @@ -65,6 +65,7 @@ 2.0.1 6.4.2.Final + 3.1.5 \ No newline at end of file diff --git a/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/HandleInstanceAlreadyExistsException.java b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/HandleInstanceAlreadyExistsException.java new file mode 100644 index 0000000000..1de39987b8 --- /dev/null +++ b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/HandleInstanceAlreadyExistsException.java @@ -0,0 +1,56 @@ +package com.baeldung.spring.kafka.kafkaexception; + +import java.lang.management.ManagementFactory; +import java.util.Properties; +import java.util.UUID; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.common.serialization.StringSerializer; + +public class HandleInstanceAlreadyExistsException { + + public static void generateUniqueClientIDUsingUUIDRandom() { + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("key.serializer", StringSerializer.class); + props.put("value.serializer", StringSerializer.class); + + String clientId = "my-producer-" + UUID.randomUUID(); + props.setProperty("client.id", clientId); + KafkaProducer producer1 = new KafkaProducer<>(props); + + clientId = "my-producer-" + UUID.randomUUID(); + props.setProperty("client.id", clientId); + KafkaProducer producer2 = new KafkaProducer<>(props); + } + + public static void closeProducerProperlyBeforeReinstantiate() { + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("client.id", "my-producer"); + props.put("key.serializer", StringSerializer.class); + props.put("value.serializer", StringSerializer.class); + + KafkaProducer producer1 = new KafkaProducer<>(props); + producer1.close(); + + producer1 = new KafkaProducer<>(props); + } + + public static void useUniqueObjectName() throws Exception { + MBeanServer mBeanServer1 = ManagementFactory.getPlatformMBeanServer(); + MBeanServer mBeanServer2 = ManagementFactory.getPlatformMBeanServer(); + + ObjectName objectName1 = new ObjectName("kafka.server:type=KafkaMetrics,id=metric1"); + ObjectName objectName2 = new ObjectName("kafka.server:type=KafkaMetrics,id=metric2"); + + MyMBean mBean1 = new MyMBean(); + mBeanServer1.registerMBean(mBean1, objectName1); + + MyMBean mBean2 = new MyMBean(); + mBeanServer2.registerMBean(mBean2, objectName2); + } +} diff --git a/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/KafkaAppMain.java b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/KafkaAppMain.java new file mode 100644 index 0000000000..14d6b71b10 --- /dev/null +++ b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/KafkaAppMain.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.kafka.kafkaexception; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class KafkaAppMain { + + public static void main(String[] args) { + SpringApplication.run(KafkaAppMain.class, args); + } +} diff --git a/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/SimulateInstanceAlreadyExistsException.java b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/SimulateInstanceAlreadyExistsException.java new file mode 100644 index 0000000000..d454d317f2 --- /dev/null +++ b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/kafkaexception/SimulateInstanceAlreadyExistsException.java @@ -0,0 +1,123 @@ +package com.baeldung.spring.kafka.kafkaexception; + +import java.lang.management.ManagementFactory; +import java.util.Properties; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.stereotype.Service; + +@Service +public class SimulateInstanceAlreadyExistsException { + + public static void jmxRegistrationConflicts() throws Exception { + // Create two instances of MBeanServer + MBeanServer mBeanServer1 = ManagementFactory.getPlatformMBeanServer(); + MBeanServer mBeanServer2 = ManagementFactory.getPlatformMBeanServer(); + + // Define the same ObjectName for both MBeans + ObjectName objectName = new ObjectName("kafka.server:type=KafkaMetrics"); + + // Create and register the first MBean + MyMBean mBean1 = new MyMBean(); + mBeanServer1.registerMBean(mBean1, objectName); + + // Attempt to register the second MBean with the same ObjectName + MyMBean mBean2 = new MyMBean(); + mBeanServer2.registerMBean(mBean2, objectName); + } + + public static void duplicateConsumerClientID() { + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("client.id", "my-consumer"); + props.put("group.id", "test-group"); + props.put("key.deserializer", StringDeserializer.class); + props.put("value.deserializer", StringDeserializer.class); + + // Simulating concurrent client creation by multiple threads + for (int i = 0; i < 3; i++) { + new Thread(() -> { + KafkaConsumer consumer = new KafkaConsumer<>(props); + }).start(); + } + } + + public void duplicateProducerClientID() throws Exception { + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("client.id", "my-producer"); + props.put("key.serializer", StringSerializer.class); + props.put("value.serializer", StringSerializer.class); + + KafkaProducer producer1 = new KafkaProducer<>(props); + // Attempting to create another producer using same client.id + KafkaProducer producer2 = new KafkaProducer<>(props); + } + + public static void unclosedProducerAndReinitialize() { + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("client.id", "my-producer"); + props.put("key.serializer", StringSerializer.class); + props.put("value.serializer", StringSerializer.class); + + KafkaProducer producer1 = new KafkaProducer<>(props); + // Attempting to reinitialize without proper close + producer1 = new KafkaProducer<>(props); + } +} + +class MyMBean implements DynamicMBean { + + @Override + public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { + return null; + } + + @Override + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + + } + + @Override + public AttributeList getAttributes(String[] attributes) { + return null; + } + + @Override + public AttributeList setAttributes(AttributeList attributes) { + return null; + } + + @Override + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { + return null; + } + + @Override + public MBeanInfo getMBeanInfo() { + MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[0]; + MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[0]; + MBeanOperationInfo[] operations = new MBeanOperationInfo[0]; + MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[0]; + return new MBeanInfo(MyMBean.class.getName(), "My MBean", attributes, constructors, operations, notifications); + } +} diff --git a/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/KafkaMessageConsumer.java b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/KafkaMessageConsumer.java new file mode 100644 index 0000000000..3bdc13d968 --- /dev/null +++ b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/KafkaMessageConsumer.java @@ -0,0 +1,33 @@ +package com.baeldung.spring.kafka.viewheaders; + +import java.util.Map; + +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Headers; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +public class KafkaMessageConsumer { + + @KafkaListener(topics = { "my-topic" }, groupId = "my-consumer-group") + public void listen(@Payload String message, @Headers Map headers) { + System.out.println("Received message: " + message); + System.out.println("Headers:"); + headers.forEach((key, value) -> System.out.println(key + ": " + value)); + + String topicName = (String) headers.get(KafkaHeaders.TOPIC); + System.out.println("Topic: " + topicName); + int partitionID = (int) headers.get(KafkaHeaders.RECEIVED_PARTITION_ID); + System.out.println("Partition ID: " + partitionID); + } + + @KafkaListener(topics = { "my-topic" }, groupId = "my-consumer-group") + public void listen(@Payload String message, @Header(KafkaHeaders.RECEIVED_TOPIC) String topicName, + @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + System.out.println("Topic: " + topicName); + System.out.println("Partition ID: " + partition); + } +} \ No newline at end of file diff --git a/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/Main.java b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/Main.java new file mode 100644 index 0000000000..fdd28e9044 --- /dev/null +++ b/spring-kafka-3/src/main/java/com/baeldung/spring/kafka/viewheaders/Main.java @@ -0,0 +1,63 @@ +package com.baeldung.spring.kafka.viewheaders; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; + +@SpringBootApplication +public class Main { + + @Autowired + static KafkaMessageConsumer kafkaMessageConsumer; + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaConsumer kafkaConsumer() { + Map configProps = new HashMap<>(); + configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); + configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configProps.put(ConsumerConfig.GROUP_ID_CONFIG, "my-consumer-group"); + return new KafkaConsumer<>(configProps); + } + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class, args); + + // Get the KafkaTemplate bean from the application context + KafkaTemplate kafkaTemplate = context.getBean(KafkaTemplate.class); + + // Send a message to the "my-topic" Kafka topic + String message = "Hello Baeldung!"; + kafkaTemplate.send("my-topic", message); + + // Close the application context + context.close(); + } +} diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java index e8aa63a88d..6d3ba2b4d9 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java @@ -116,7 +116,7 @@ public class KafkaConsumerConfig { public ConcurrentKafkaListenerContainerFactory multiTypeKafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(multiTypeConsumerFactory()); - factory.setMessageConverter(multiTypeConverter()); + factory.setRecordMessageConverter(multiTypeConverter()); return factory; } diff --git a/spring-reactive-modules/spring-reactive-exceptions/pom.xml b/spring-reactive-modules/spring-reactive-exceptions/pom.xml index a9fdb675f5..e9208c8b20 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/pom.xml +++ b/spring-reactive-modules/spring-reactive-exceptions/pom.xml @@ -54,4 +54,8 @@ + + 3.1.5 + + diff --git a/spring-security-modules/spring-security-web-angular/pom.xml b/spring-security-modules/spring-security-web-angular/pom.xml index 15dc4d007c..67b6d233e6 100644 --- a/spring-security-modules/spring-security-web-angular/pom.xml +++ b/spring-security-modules/spring-security-web-angular/pom.xml @@ -10,7 +10,8 @@ com.baeldung - spring-security-modules + parent-boot-3 + ../../parent-boot-3 0.0.1-SNAPSHOT diff --git a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/pom.xml b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/pom.xml index b33e0925a3..bf9fed6898 100644 --- a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/pom.xml +++ b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/pom.xml @@ -15,10 +15,6 @@ - - - - org.springframework.boot spring-boot-starter-security 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 5f4b82a191..37b63d95b4 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 @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.provisioning.InMemoryUserDetailsManager; @@ -27,18 +28,13 @@ public class BasicAuthConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() + http.csrf(AbstractHttpConfigurer::disable) .cors(withDefaults()) - .authorizeRequests() - .antMatchers(HttpMethod.OPTIONS, "/**") - .permitAll() - .antMatchers("/login") - .permitAll() - .anyRequest() - .authenticated() - .and() - .httpBasic(); + .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .requestMatchers("/login").permitAll() + .anyRequest().authenticated()) + .httpBasic(withDefaults()); return http.build(); } } diff --git a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/controller/UserController.java b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/controller/UserController.java index 0eef4198a1..3413eaf69b 100644 --- a/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/controller/UserController.java +++ b/spring-security-modules/spring-security-web-angular/spring-security-web-angular-server/src/main/java/com/baeldung/springbootsecurityrest/controller/UserController.java @@ -3,7 +3,7 @@ package com.baeldung.springbootsecurityrest.controller; import java.security.Principal; import java.util.Base64; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestBody; diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml index 136f5b8907..59e07ece69 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml @@ -29,17 +29,23 @@ org.openapitools openapi-generator ${openapi-generator.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson-databind.version} + + + org.slf4j + slf4j-simple + + org.springdoc springdoc-openapi-ui ${springdoc.version} + + org.openapitools + jackson-databind-nullable + ${jackson-databind-nullable.version} + @@ -85,9 +91,9 @@ 3.0.0 2.17.1 1.7.0 - 3.3.4 - 2.16.0 - 5.1.0 + 7.2.0 + 7.2.0 + 0.2.6 \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache index ed806c6282..34f9f0a65c 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache @@ -1,14 +1,29 @@ /** - * NOTE: This class is auto generated by OpenAPI Generator (https://com.baeldung.openapi-generator.tech) ({{{generatorVersion}}}). - * https://com.baeldung.openapi-generator.tech + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) ({{{generatorVersion}}}). + * https://openapi-generator.tech * Do not edit the class manually. */ package {{package}}; {{#imports}}import {{import}}; {{/imports}} -import io.swagger.annotations.*; import com.baeldung.openapi.petstore.validation.Capitalized; +{{#swagger2AnnotationLibrary}} +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +{{/swagger2AnnotationLibrary}} +{{#swagger1AnnotationLibrary}} +import io.swagger.annotations.*; +{{/swagger1AnnotationLibrary}} {{#jdk8-no-delegate}} {{#virtualService}} import io.virtualan.annotation.ApiVirtual; @@ -17,18 +32,28 @@ import io.virtualan.annotation.VirtualService; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; {{/jdk8-no-delegate}} +{{^useResponseEntity}} +import org.springframework.http.HttpStatus; +{{/useResponseEntity}} +{{#useResponseEntity}} import org.springframework.http.ResponseEntity; +{{/useResponseEntity}} {{#useBeanValidation}} import org.springframework.validation.annotation.Validated; {{/useBeanValidation}} -{{#vendorExtensions.x-spring-paginated}} -import org.springframework.data.domain.Pageable; -{{/vendorExtensions.x-spring-paginated}} +{{#useSpringController}} +{{#useResponseEntity}} +import org.springframework.stereotype.Controller; +{{/useResponseEntity}} +{{^useResponseEntity}} +import org.springframework.web.bind.annotation.RestController; +{{/useResponseEntity}} +{{/useSpringController}} import org.springframework.web.bind.annotation.*; {{#jdk8-no-delegate}} - {{^reactive}} +{{^reactive}} import org.springframework.web.context.request.NativeWebRequest; - {{/reactive}} +{{/reactive}} {{/jdk8-no-delegate}} import org.springframework.web.multipart.MultipartFile; {{#reactive}} @@ -39,8 +64,8 @@ import org.springframework.http.codec.multipart.Part; {{/reactive}} {{#useBeanValidation}} -import javax.validation.Valid; -import javax.validation.constraints.*; +import {{javaxPackage}}.validation.Valid; +import {{javaxPackage}}.validation.constraints.*; {{/useBeanValidation}} import java.util.List; import java.util.Map; @@ -48,22 +73,42 @@ import java.util.Map; import java.util.Optional; {{/jdk8-no-delegate}} {{^jdk8-no-delegate}} - {{#useOptional}} +{{#useOptional}} import java.util.Optional; - {{/useOptional}} +{{/useOptional}} {{/jdk8-no-delegate}} {{#async}} -import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}}; +import java.util.concurrent.CompletableFuture; {{/async}} +import {{javaxPackage}}.annotation.Generated; + {{>generatedAnnotation}} {{#useBeanValidation}} @Validated {{/useBeanValidation}} -@Api(value = "{{{baseName}}}", tags = "All") +{{#useSpringController}} +{{#useResponseEntity}} +@Controller +{{/useResponseEntity}} +{{^useResponseEntity}} +@RestController +{{/useResponseEntity}} +{{/useSpringController}} +{{#swagger2AnnotationLibrary}} +@Tag(name = "{{{tagName}}}", description = {{#tagDescription}}"{{{.}}}"{{/tagDescription}}{{^tagDescription}}"the {{{tagName}}} API"{{/tagDescription}}) +{{/swagger2AnnotationLibrary}} +{{#swagger1AnnotationLibrary}} +@Api(value = "{{{tagName}}}", description = {{#tagDescription}}"{{{.}}}"{{/tagDescription}}{{^tagDescription}}"the {{{tagName}}} API"{{/tagDescription}}) +{{/swagger1AnnotationLibrary}} {{#operations}} {{#virtualService}} @VirtualService {{/virtualService}} +{{#useRequestMappingOnInterface}} +{{=<% %>=}} +@RequestMapping("${openapi.<%title%>.base-path:<%>defaultBasePath%>}") +<%={{ }}=%> +{{/useRequestMappingOnInterface}} public interface {{classname}} { {{#jdk8-default-interface}} {{^isDelegate}} @@ -102,45 +147,127 @@ public interface {{classname}} { * @see {{summary}} Documentation {{/externalDocs}} */ + {{#isDeprecated}} + @Deprecated + {{/isDeprecated}} {{#virtualService}} @ApiVirtual {{/virtualService}} - @ApiOperation(value = "{{{summary}}}", nickname = "{{{operationId}}}", notes = "{{{notes}}}"{{#returnBaseType}}, response = {{{returnBaseType}}}.class{{/returnBaseType}}{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { - {{#authMethods}}{{#isOAuth}}@Authorization(value = "{{name}}", scopes = { - {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}}, - {{/-last}}{{/scopes}} }){{^-last}},{{/-last}}{{/isOAuth}} - {{^isOAuth}}@Authorization(value = "{{name}}"){{^-last}},{{/-last}} - {{/isOAuth}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) - @ApiResponses(value = { {{#responses}} - @ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}.class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{^-last}},{{/-last}}{{/responses}} }) - {{#implicitHeaders}} - @ApiImplicitParams({ - {{#headerParams}} - {{>implicitHeader}} - {{/headerParams}} + {{#swagger2AnnotationLibrary}} + @Operation( + operationId = "{{{operationId}}}", + {{#summary}} + summary = "{{{.}}}", + {{/summary}} + {{#notes}} + description = "{{{.}}}", + {{/notes}} + {{#isDeprecated}} + deprecated = true, + {{/isDeprecated}} + {{#vendorExtensions.x-tags.size}} + tags = { {{#vendorExtensions.x-tags}}"{{tag}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-tags}} }, + {{/vendorExtensions.x-tags.size}} + responses = { + {{#responses}} + @ApiResponse(responseCode = {{#isDefault}}"default"{{/isDefault}}{{^isDefault}}"{{{code}}}"{{/isDefault}}, description = "{{{message}}}"{{#baseType}}, content = { + {{#produces}} + @Content(mediaType = "{{{mediaType}}}", {{#isArray}}array = @ArraySchema({{/isArray}}schema = @Schema(implementation = {{{baseType}}}.class){{#isArray}}){{/isArray}}){{^-last}},{{/-last}} + {{/produces}} + }{{/baseType}}){{^-last}},{{/-last}} + {{/responses}} + }{{#hasAuthMethods}}, + security = { + {{#authMethods}} + @SecurityRequirement(name = "{{name}}"{{#scopes.0}}, scopes={ {{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}} }{{/scopes.0}}){{^-last}},{{/-last}} + {{/authMethods}} + }{{/hasAuthMethods}}{{#externalDocs}}, + externalDocs = @ExternalDocumentation(description = "{{externalDocs.description}}", url = "{{externalDocs.url}}"){{/externalDocs}} + ) + {{/swagger2AnnotationLibrary}} + {{#swagger1AnnotationLibrary}} + @ApiOperation( + {{#vendorExtensions.x-tags.size}} + tags = { {{#vendorExtensions.x-tags}}"{{tag}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-tags}} }, + {{/vendorExtensions.x-tags.size}} + value = "{{{summary}}}", + nickname = "{{{operationId}}}", + notes = "{{{notes}}}"{{#returnBaseType}}, + response = {{{.}}}.class{{/returnBaseType}}{{#returnContainer}}, + responseContainer = "{{{.}}}"{{/returnContainer}}{{#hasAuthMethods}}, + authorizations = { + {{#authMethods}} + {{#scopes.0}} + @Authorization(value = "{{name}}", scopes = { + {{#scopes}} + @AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}},{{/-last}} + {{/scopes}} + }){{^-last}},{{/-last}} + {{/scopes.0}} + {{^scopes.0}} + @Authorization(value = "{{name}}"){{^-last}},{{/-last}} + {{/scopes.0}} + {{/authMethods}} }{{/hasAuthMethods}} + ) + @ApiResponses({ + {{#responses}} + @ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{.}}}.class{{/baseType}}{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}){{^-last}},{{/-last}} + {{/responses}} }) - {{/implicitHeaders}} + {{/swagger1AnnotationLibrary}} + {{#implicitHeadersParams.0}} + {{#swagger2AnnotationLibrary}} + @Parameters({ + {{#implicitHeadersParams}} + {{>paramDoc}}{{^-last}},{{/-last}} + {{/implicitHeadersParams}} + }) + {{/swagger2AnnotationLibrary}} + {{#swagger1AnnotationLibrary}} + @ApiImplicitParams({ + {{#implicitHeadersParams}} + {{>implicitHeader}}{{^-last}},{{/-last}} + {{/implicitHeadersParams}} + }) + {{/swagger1AnnotationLibrary}} + {{/implicitHeadersParams.0}} @RequestMapping( method = RequestMethod.{{httpMethod}}, value = "{{{path}}}"{{#singleContentTypes}}{{#hasProduces}}, produces = "{{{vendorExtensions.x-accepts}}}"{{/hasProduces}}{{#hasConsumes}}, - consumes = "{{{vendorExtensions.x-contentType}}}"{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}, + consumes = "{{{vendorExtensions.x-content-type}}}"{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}, produces = { {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }{{/hasProduces}}{{#hasConsumes}}, - consumes = { {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }{{/hasConsumes}}{{/singleContentTypes}} + consumes = { {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }{{/hasConsumes}}{{/singleContentTypes}}{{#hasVersionHeaders}}, + headers = { {{#vendorExtensions.versionHeaderParamsList}}"{{baseName}}{{#defaultValue}}={{{.}}}{{/defaultValue}}"{{^-last}}, {{/-last}}{{/vendorExtensions.versionHeaderParamsList}} } {{/hasVersionHeaders}}{{#hasVersionQueryParams}}, + params = { {{#vendorExtensions.versionQueryParamsList}}"{{baseName}}{{#defaultValue}}={{{.}}}{{/defaultValue}}"{{^-last}}, {{/-last}}{{/vendorExtensions.versionQueryParamsList}} } {{/hasVersionQueryParams}} ) - {{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},{{/-last}}{{#-last}}{{#reactive}}, {{/reactive}}{{/-last}}{{/allParams}}{{#reactive}}final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}}{{#unhandledException}} throws Exception{{/unhandledException}} { + {{^useResponseEntity}} + @ResponseStatus({{#springHttpStatus}}{{#responses.0}}{{{code}}}{{/responses.0}}{{/springHttpStatus}}) + {{/useResponseEntity}} + {{#vendorExtensions.x-operation-extra-annotation}} + {{{.}}} + {{/vendorExtensions.x-operation-extra-annotation}} + {{#vendorExtensions.x-sse}}@ResponseBody{{/vendorExtensions.x-sse}} + {{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{>responseType}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}( + {{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}}, + {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, + {{/hasParams}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, + {{/hasParams}}{{^hasParams}}{{#reactive}},{{/reactive}}{{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore {{/springFoxDocumentationProvider}}{{#springDocDocumentationProvider}}@ParameterObject {{/springDocDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.x-spring-provide-args}}{{#hasParams}}, + {{/hasParams}}{{^hasParams}}{{#reactive}},{{/reactive}}{{/hasParams}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}} {{{.}}}{{^hasParams}}{{^-last}}{{^reactive}},{{/reactive}} + {{/-last}}{{/hasParams}}{{/vendorExtensions.x-spring-provide-args}} + ){{#unhandledException}} throws Exception{{/unhandledException}}{{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}} { {{#delegate-method}} - return {{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); + {{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}); } // Override this method - {{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} { + {{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} { {{/delegate-method}} {{^isDelegate}} {{>methodBody}} {{/isDelegate}} {{#isDelegate}} - return getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); + {{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}); {{/isDelegate}} }{{/jdk8-default-interface}} diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache index e3c19c6474..45d963d889 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache @@ -1,26 +1,25 @@ {{{ vendorExtensions.x-constraints }}} -{{#errorMessage}}@Mandatory(errorMessage="{{{pattern}}}") {{/errorMessage}} -{{#pattern}}@Pattern(regexp="{{{pattern}}}") {{/pattern}}{{! +{{#pattern}}{{^isByteArray}}@Pattern(regexp = "{{{pattern}}}"{{#vendorExtensions.x-pattern-message}}, message="{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}) {{/isByteArray}}{{/pattern}}{{! minLength && maxLength set -}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +}}{{#minLength}}{{#maxLength}}@Size(min = {{minLength}}, max = {{maxLength}}) {{/maxLength}}{{/minLength}}{{! minLength set, maxLength not -}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{! +}}{{#minLength}}{{^maxLength}}@Size(min = {{minLength}}) {{/maxLength}}{{/minLength}}{{! minLength not set, maxLength set -}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +}}{{^minLength}}{{#maxLength}}@Size(max = {{.}}) {{/maxLength}}{{/minLength}}{{! @Size: minItems && maxItems set -}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +}}{{#minItems}}{{#maxItems}}@Size(min = {{minItems}}, max = {{maxItems}}) {{/maxItems}}{{/minItems}}{{! @Size: minItems set, maxItems not -}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{! +}}{{#minItems}}{{^maxItems}}@Size(min = {{minItems}}) {{/maxItems}}{{/minItems}}{{! @Size: minItems not set && maxItems set -}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! -@Email: useBeanValidation set && isEmail && java8 set -}}{{#useBeanValidation}}{{#isEmail}}{{#java8}}@javax.validation.constraints.Email{{/java8}}{{/isEmail}}{{/useBeanValidation}}{{! -@Email: performBeanValidation set && isEmail && not java8 set -}}{{#performBeanValidation}}{{#isEmail}}{{^java8}}@org.hibernate.validator.constraints.Email{{/java8}}{{/isEmail}}{{/performBeanValidation}}{{! +}}{{^minItems}}{{#maxItems}}@Size(max = {{.}}) {{/maxItems}}{{/minItems}}{{! +@Email: useBeanValidation +}}{{#isEmail}}{{#useBeanValidation}}@{{javaxPackage}}.validation.constraints.Email {{/useBeanValidation}}{{! +@Email: performBeanValidation exclusive +}}{{^useBeanValidation}}{{#performBeanValidation}}@org.hibernate.validator.constraints.Email {{/performBeanValidation}}{{/useBeanValidation}}{{/isEmail}}{{! check for integer or long / all others=decimal type with @Decimal* isInteger set -}}{{#isInteger}}{{#minimum}}@Min({{minimum}}){{/minimum}}{{#maximum}} @Max({{maximum}}) {{/maximum}}{{/isInteger}}{{! +}}{{#isInteger}}{{#minimum}}@Min({{.}}) {{/minimum}}{{#maximum}}@Max({{.}}) {{/maximum}}{{/isInteger}}{{! isLong set -}}{{#isLong}}{{#minimum}}@Min({{minimum}}L){{/minimum}}{{#maximum}} @Max({{maximum}}L) {{/maximum}}{{/isLong}}{{! +}}{{#isLong}}{{#minimum}}@Min({{.}}L) {{/minimum}}{{#maximum}}@Max({{.}}L) {{/maximum}}{{/isLong}}{{! Not Integer, not Long => we have a decimal value! -}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin({{#exclusiveMinimum}}value={{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}},inclusive=false{{/exclusiveMinimum}}){{/minimum}}{{#maximum}} @DecimalMax({{#exclusiveMaximum}}value={{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}},inclusive=false{{/exclusiveMaximum}}) {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file +}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin({{#exclusiveMinimum}}value = {{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}}, inclusive = false{{/exclusiveMinimum}}) {{/minimum}}{{#maximum}}@DecimalMax({{#exclusiveMaximum}}value = {{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}}, inclusive = false{{/exclusiveMaximum}}) {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache index e21bd9ff4b..74a837988f 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache @@ -1 +1 @@ -{{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{^isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}{{/isContainer}}) @CookieValue("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file +{{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @CookieValue(name = "{{baseName}}"{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache deleted file mode 100644 index 3cdae7f3cc..0000000000 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache +++ /dev/null @@ -1,31 +0,0 @@ -class {{classname}} { - /// The underlying value of this enum member. - {{dataType}} value; - - {{classname}}._internal(this.value); - {{ vendorExtensions.x-enum-varnames }} - {{ vendorExtensions.x-enum-descriptions }} - {{#allowableValues}} - {{#enumVars}} - {{#description}} - /// {{description}} - {{/description}} - static {{classname}} {{name}} = {{classname}}._internal({{{value}}}); - {{/enumVars}} - {{/allowableValues}} - - {{classname}}.fromJson(dynamic data) { - switch (data) { - {{#allowableValues}} - {{#enumVars}} - case {{{value}}}: value = data; break; - {{/enumVars}} - {{/allowableValues}} - default: throw('Unknown enum value to decode: $data'); - } - } - - static dynamic encode({{classname}} data) { - return data.value; - } -} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumClass.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumClass.mustache new file mode 100644 index 0000000000..14aff87c60 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumClass.mustache @@ -0,0 +1,60 @@ +/** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{{description}}} + */ + {{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { + {{#gson}} + {{#allowableValues}} + {{#enumVars}} + {{#enumDescription}} + /** + * {{.}} + */ + {{/enumDescription}} + @SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}) + {{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}} + {{/enumVars}} + {{/allowableValues}} + {{/gson}} + {{^gson}} + {{#allowableValues}} + {{#enumVars}} + {{#enumDescription}} + /** + * {{.}} + */ + {{/enumDescription}} + {{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}} + {{/enumVars}} + {{/allowableValues}} + {{/gson}} + + private {{{dataType}}} value; + + {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}({{{dataType}}} value) { + this.value = value; + } + + {{#jackson}} + @JsonValue + {{/jackson}} + public {{{dataType}}} getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) { + for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (b.value.{{^isString}}equals{{/isString}}{{#isString}}{{#useEnumCaseInsensitive}}equalsIgnoreCase{{/useEnumCaseInsensitive}}{{^useEnumCaseInsensitive}}equals{{/useEnumCaseInsensitive}}{{/isString}}(value)) { + return b; + } + } + {{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/isNullable}} + } + } \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumOuterClass.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumOuterClass.mustache new file mode 100644 index 0000000000..4c6b2e6329 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enumOuterClass.mustache @@ -0,0 +1,61 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +{{/jackson}} + +/** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{{description}}} + */ +{{>additionalEnumTypeAnnotations}} +{{>generatedAnnotation}} +public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { + {{#gson}} + {{#allowableValues}}{{#enumVars}} + {{#enumDescription}} + /** + * {{.}} + */ + {{/enumDescription}} + @SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}) + {{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} + {{/gson}} + {{^gson}} + {{#allowableValues}}{{#enumVars}} + {{#enumDescription}} + /** + * {{.}} + */ + {{/enumDescription}} + {{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} + {{/gson}} + + private {{{dataType}}} value; + + {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) { + this.value = value; + } + + {{#jackson}} + @JsonValue + {{/jackson}} + public {{{dataType}}} getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) { + for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (b.value.{{^isString}}equals{{/isString}}{{#isString}}{{#useEnumCaseInsensitive}}equalsIgnoreCase{{/useEnumCaseInsensitive}}{{^useEnumCaseInsensitive}}equals{{/useEnumCaseInsensitive}}{{/isString}}(value)) { + return b; + } + } + {{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/isNullable}} + } +} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache index 4546a811ef..3b6b12fda4 100644 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache @@ -1,42 +1,62 @@ package {{package}}; +import java.net.URI; +import java.util.Objects; {{#imports}}import {{import}}; {{/imports}} -import com.fasterxml.jackson.databind.annotation.*; -import com.fasterxml.jackson.annotation.*; import com.baeldung.openapi.petstore.validation.Capitalized; -{{^supportJava6}} -import java.util.Objects; -import java.util.Arrays; -{{/supportJava6}} -{{#supportJava6}} -import org.apache.commons.lang3.ObjectUtils; -{{/supportJava6}} -{{#imports}} -import {{import}}; -{{/imports}} +{{#openApiNullable}} +import org.openapitools.jackson.nullable.JsonNullable; +{{/openApiNullable}} {{#serializableModel}} import java.io.Serializable; {{/serializableModel}} +import java.time.OffsetDateTime; +{{#useBeanValidation}} +import {{javaxPackage}}.validation.Valid; +import {{javaxPackage}}.validation.constraints.*; +{{/useBeanValidation}} +{{^useBeanValidation}} +import {{javaxPackage}}.validation.constraints.NotNull; +{{/useBeanValidation}} +{{#performBeanValidation}} +import org.hibernate.validator.constraints.*; +{{/performBeanValidation}} {{#jackson}} {{#withXml}} -import com.fasterxml.jackson.dataformat.xml.annotation.*; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; {{/withXml}} {{/jackson}} +{{#swagger2AnnotationLibrary}} +import io.swagger.v3.oas.annotations.media.Schema; +{{/swagger2AnnotationLibrary}} + {{#withXml}} -import javax.xml.bind.annotation.*; +import {{javaxPackage}}.xml.bind.annotation.*; {{/withXml}} -{{#parcelableModel}} -import android.os.Parcelable; -import android.os.Parcel; -{{/parcelableModel}} -{{#useBeanValidation}} -import javax.validation.constraints.*; -import javax.validation.Valid; -{{/useBeanValidation}} +{{^parent}} +{{#hateoas}} +import org.springframework.hateoas.RepresentationModel; +{{/hateoas}} +{{/parent}} + +import java.util.*; +import {{javaxPackage}}.annotation.Generated; {{#models}} {{#model}} -{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>pojo}}{{/isEnum}} +{{#additionalPropertiesType}} +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +{{/additionalPropertiesType}} +{{#isEnum}} +{{>enumOuterClass}} +{{/isEnum}} +{{^isEnum}} +{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}} +{{/isEnum}} {{/model}} {{/models}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache deleted file mode 100644 index 29f27bd851..0000000000 --- a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache +++ /dev/null @@ -1,68 +0,0 @@ -{{#jackson}} -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -{{/jackson}} -{{#gson}} -import java.io.IOException; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -{{/gson}} - -/** - * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} - */ -{{#gson}} -@JsonAdapter({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.Adapter.class) -{{/gson}} -public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { - {{#allowableValues}}{{#enumVars}} - {{{name}}}({{{value}}}){{^-last}}, - {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} - - private {{{dataType}}} value; - - {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) { - this.value = value; - } - -{{#jackson}} - @JsonValue -{{/jackson}} - public {{{dataType}}} getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - -{{#jackson}} - @JsonCreator -{{/jackson}} - public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue{{#jackson}}({{{dataType}}} value){{/jackson}}{{^jackson}}(String text){{/jackson}} { - for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { - if ({{#jackson}}b.value.equals(value){{/jackson}}{{^jackson}}String.valueOf(b.value).equals(text){{/jackson}}) { - return b; - } - } - throw new UlpValidationException(UlpBundleKey.{{vendorExtensions.x-enum-invalidtag}}); - } -{{#gson}} - - public static class Adapter extends TypeAdapter<{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}> { - @Override - public void write(final JsonWriter jsonWriter, final {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} enumeration) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException { - {{#isNumber}}BigDecimal value = new BigDecimal(jsonReader.nextDouble()){{/isNumber}}{{^isNumber}}{{#isInteger}}Integer value {{/isInteger}}{{^isInteger}}String value {{/isInteger}}= jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}nextString(){{/isInteger}}{{/isNumber}}; - return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue({{#jackson}}value{{/jackson}}{{^jackson}}String.valueOf(value){{/jackson}}); - } - } -{{/gson}} -} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapitools.json b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapitools.json new file mode 100644 index 0000000000..e73b975830 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.2.0" + } +} diff --git a/spring-web-modules/spring-thymeleaf-5/README.md b/spring-web-modules/spring-thymeleaf-5/README.md index dcf5dd91b3..31796e251f 100644 --- a/spring-web-modules/spring-thymeleaf-5/README.md +++ b/spring-web-modules/spring-thymeleaf-5/README.md @@ -8,4 +8,5 @@ This module contains articles about Spring with Thymeleaf - [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration) - [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination) - [Display Image With Thymeleaf](https://www.baeldung.com/spring-thymeleaf-image) +- [How to Check if a Variable Is Defined in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-variable-defined) - More articles: [[<-- prev]](../spring-thymeleaf-4) diff --git a/testing-modules/spring-testing/pom.xml b/testing-modules/spring-testing/pom.xml index b2ef0a59ad..c4c929b7aa 100644 --- a/testing-modules/spring-testing/pom.xml +++ b/testing-modules/spring-testing/pom.xml @@ -75,6 +75,16 @@ spring-testing + + + org.apache.maven.plugins + maven-compiler-plugin + + 15 + 15 + + + src/main/resources @@ -87,7 +97,7 @@ 2.0.0.0 3.1.6 - 5.3.4 + 6.1.3 2.1.1 diff --git a/testing-modules/spring-testing/src/main/java/com/baeldung/testpropertysource/ClassUsingProperty.java b/testing-modules/spring-testing/src/main/java/com/baeldung/testpropertysource/ClassUsingProperty.java index d545daf0df..88f2f89b4c 100644 --- a/testing-modules/spring-testing/src/main/java/com/baeldung/testpropertysource/ClassUsingProperty.java +++ b/testing-modules/spring-testing/src/main/java/com/baeldung/testpropertysource/ClassUsingProperty.java @@ -8,8 +8,15 @@ public class ClassUsingProperty { @Value("${baeldung.testpropertysource.one}") private String propertyOne; - + + @Value("${baeldung.testpropertysource.two}") + private String propertyTwo; + public String retrievePropertyOne() { return propertyOne; } + + public String retrievePropertyTwo() { + return propertyTwo; + } } diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceListIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceListIntegrationTest.java new file mode 100644 index 0000000000..e882d5c7cd --- /dev/null +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceListIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.testpropertysource; + +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.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ClassUsingProperty.class) +@TestPropertySource( + locations = "/other-location.properties", + properties = { + "baeldung.testpropertysource.one=one", + "baeldung.testpropertysource.two=two", + }) +public class MultiplePropertiesInPropertySourceListIntegrationTest { + + @Autowired + ClassUsingProperty classUsingProperty; + + @Test + public void givenAMultilinePropertySource_whenVariableOneRetrieved_thenValueInPropertyAnnotationIsReturned() { + String output = classUsingProperty.retrievePropertyOne(); + + assertThat(output).isEqualTo("one"); + } + + @Test + public void givenAMultilinePropertySource_whenVariableTwoRetrieved_thenValueInPropertyAnnotationIsReturned() { + String output = classUsingProperty.retrievePropertyTwo(); + + assertThat(output).isEqualTo("two"); + } +} diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceTextBlockIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceTextBlockIntegrationTest.java new file mode 100644 index 0000000000..e31055a4c6 --- /dev/null +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/MultiplePropertiesInPropertySourceTextBlockIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.testpropertysource; + +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.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ClassUsingProperty.class) +@TestPropertySource( + locations = "/other-location.properties", + properties = """ + baeldung.testpropertysource.one=one + baeldung.testpropertysource.two=two + """) +public class MultiplePropertiesInPropertySourceTextBlockIntegrationTest { + + @Autowired + ClassUsingProperty classUsingProperty; + + @Test + public void givenAMultilinePropertySource_whenVariableOneRetrieved_thenValueInPropertyAnnotationIsReturned() { + String output = classUsingProperty.retrievePropertyOne(); + + assertThat(output).isEqualTo("one"); + } + + @Test + public void givenAMultilinePropertySource_whenVariableTwoRetrieved_thenValueInPropertyAnnotationIsReturned() { + String output = classUsingProperty.retrievePropertyTwo(); + + assertThat(output).isEqualTo("two"); + } +} diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/PropertiesTestPropertySourceIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/PropertiesTestPropertySourceIntegrationTest.java index d98e2b9f98..5100d3a3bb 100644 --- a/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/PropertiesTestPropertySourceIntegrationTest.java +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/testpropertysource/PropertiesTestPropertySourceIntegrationTest.java @@ -18,7 +18,7 @@ public class PropertiesTestPropertySourceIntegrationTest { ClassUsingProperty classUsingProperty; @Test - public void givenDefaultTestPropertySource_whenVariableOneRetrieved_thenValueInDefaultFileReturned() { + public void givenACustomPropertySource_whenVariableOneRetrieved_thenValueInPropertyAnnotationIsReturned() { String output = classUsingProperty.retrievePropertyOne(); assertThat(output).isEqualTo("other-properties-value");